马黑黑 发表于 2026-8-1 11:52

offset-path ray函数演示(二)

<style>
    .artBox { margin: 20px auto; font: normal 18px/26px sans-serif; max-width: 1200px; }
    .artBox mark { padding: 2px 6px; background: #ccc; }
    .artBox blockquote { padding: 14px; border: solid gray; border-width: 0 4px; border-radius: 10px; background: #ddd; }
    .artBox p { margin: 10px 0; }
    .artBox table { border-collapse: collapse; white-space: pre-wrap; box-sizing: border-box; margin: 10px 0; }
    .artBox th, .artBox td { padding: 8px 10px; border: 1px solid #999; }
    .artBox th { text-align: center; background: #eee; }
</style>

<div class="artBox">
    <p>在 <a href="https://www.huachaowang.com/forum.php?mod=viewthread&tid=95004&extra=page%3D1" target="_blank">offset-path ray函数演示(一)</a> 中,大家可能已经对 ray() 函数有了些许印象,本演示则需要了解更多:ray 函数的所有参数以及其它相关知识。</p>
    <h3>&#128161;ray() 函数语法:</h3>
    <blockquote>
      ray(&lt;angle&gt; && &lt;size&gt;? && contain? && ?)<br>
      对应参数含义:射线角度、射线长度、块内包含、射线起点位置。参数顺序没有硬性规定。
    </blockquote>
   
    <table>
      <caption style="text-align: left"><h3>&#128161;ray()函数参数</h3></caption>
      <tr>
            <th width="50">序号</th>
            <th width="100">参数</th>
            <th>说明</th>
      </tr>
      <tr>
            <td>1</td>
            <td>angle</td>
            <td>必须参数,规范射线方向,角度值,0deg 向上,顺时针增加</td>
      </tr>
      <tr>
            <td>2</td>
            <td>size</td>
            <td>可选参数,路径长度,即 offset-distance 0% 和 100% 之间的距离,相对于包含块。可选值有 closest-side(最近边,默认)、 farthest-side(最远边)、closest-corner(最近角)、farthest-corner(最远角)、sides(沿角度到容器边界)</td>
      </tr>
      <tr>
            <td>3</td>
            <td>contain</td>
            <td>可选参数,元素全程不超出包含块缩短线段的长度(设计本意,算法或浏览器支持度待改进)</td>
      </tr>
      <tr>
            <td>4</td>
            <td>at position</td>
            <td>可选参数,指定射线的起点以及元素在其包含块中的放置位置,缺省默认 at 50% 50%</td>
      </tr>
    </table>
   
    <h3>&#128161;主要配套CSS属性</h3>
    <blockquote>
      offset-distance - 沿路径的位置(0% ~ 100%)<br>
      offset-position - 射线起点(默认 50% 50%)<br>
      offset-rotate - 元素朝向(auto:随路径转向,角度值:朝向固定)<br>
      offset-anchor - 元素锚点(默认元素中心点)
    </blockquote>

    <h3>&#128161;演示代码(支持预览):</h3>
    <p>以下示例设计为综合性演示,ray() 的四个参数一起用上。演示代码不理解没有关系,关键在于演示体验:不同的参数组合生成的射线路径各异,体验时慢慢领会。体验中通过调节不同参数的值、查看 movebox 元素的运动状态应该有助于理解射线路径形态。演示加入了 offset-distance 相抵路径动画效果,在调整射线角度后触发。体验当中注意观察动态生成的 offset-path 路径代码。</p>
    <div class="hEdiv" data-prev="1"><pre class="hEpre">
&lt;style&gt;
    @import 'https://638183.freep.cn/638183/web/css/hl.css';
    h2 { text-align: center; }
    .pa {
      width: 800px;
      height: 400px;
      border: 1px solid gray;
      position: relative;
      margin: 30px auto 0;
    }
    .pa:nth-of-type(1)::before {
      position: absolute;
      content: attr(data-code);
      width: 100%;
      bottom: 10px;
      text-align: center;
    }
    .pa:nth-of-type(2) {
      border-width: 0;
    }
    .movebox {
      padding: 0px;
      font-size: 36px;
      border: 1px solid gray;
      position: absolute;
    }
    @keyframes move {
      from { offset-distance: 0%; }
      to { offset-distance: 100%; }
    }
&lt;/style&gt;

&lt;h2&gt;ray()函数综合演示&lt;/h2&gt;
&lt;div id="pa" class="pa hlCode" data-code="offset-path尚未生成"&gt;
    &lt;div class="movebox"&gt;➡️&lt;/div&gt;
&lt;/div&gt;
&lt;div class="pa"&gt;
    &lt;p&gt;
      &lt;label for="rangeSet"&gt;调整角度 :&lt;/label&gt;
      &lt;input id="rangeSet" type="range" value="0" max="360" min="-360" step="5" /&gt;
      &lt;output id="outRes"&gt;0&lt;/output&gt;
    &lt;/p&gt;
    &lt;p&gt;
      &lt;label&gt;路径长度:&lt;/label&gt;
      &lt;input id="r1" type="radio" name="size" value="closest-side" checked /&gt;
      &lt;label for="r1"&gt;closest-side&lt;/label&gt;
      &lt;input id="r2" type="radio" name="size" value="farthest-side" /&gt;
      &lt;label for="r2"&gt;farthest-side&lt;/label&gt;
      &lt;input id="r3" type="radio" name="size" value="closest-corner" /&gt;
      &lt;label for="r3"&gt;closest-corner&lt;/label&gt;
      &lt;input id="r4" type="radio" name="size" value="farthest-corner" /&gt;
      &lt;label for="r4"&gt;farthest-corner&lt;/label&gt;
      &lt;input id="r5" type="radio" name="size" value="sides" /&gt;
      &lt;label for="r5"&gt;sides&lt;/label&gt;
    &lt;/p&gt;
    &lt;p&gt;
      &lt;label for="chkContain"&gt;contain :&lt;/label&gt;
      &lt;input id="chkContain" type="checkbox" value="contain" checked /&gt;
    &lt;/p&gt;
    &lt;p&gt;
      &lt;label for="atX"&gt;射线起点(x坐标):&lt;/label&gt;
      &lt;input id="atX" type="range" max="100" min="0" value="50"/&gt;
      &lt;output id="outX"&gt;50%&lt;/output&gt;
    &lt;/p&gt;
    &lt;p&gt;
      &lt;label for="atY"&gt;射线起点(y坐标):&lt;/label&gt;
      &lt;input id="atY" type="range" max="100" min="0" value="50"/&gt;
      &lt;output id="outY"&gt;50%&lt;/output&gt;
    &lt;/p&gt;
    &lt;p&gt;&lt;button onclick="location.reload()"&gt;全部重置&lt;/button&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;script&gt;
    const movebox = document.querySelector('.movebox');
   
    movebox.onanimationend = () =&gt; rangeSet.disabled = false;
   
    movebox.onanimationstart = () =&gt; rangeSet.disabled = true;
   
    rangeSet.oninput = () =&gt; {
      outRes.value = rangeSet.value + 'deg';
      movebox.style.setProperty('offset-path', createRayPath());
    }
   
    rangeSet.onchange = () =&gt; {
      const path = createRayPath();

      movebox.style.animation = '';
      pa.dataset.code = `offset-path: ${path};`;
      
      setTimeout( () =&gt; {
            movebox.style.setProperty('offset-path', `${path}`);
            movebox.style.setProperty('animation', 'move linear 2s forwards');
      }, 500);
    };
   
    atX.oninput = () =&gt; {
      movebox.style.setProperty('offset-path', createRayPath());
      outX.value = `${atX.value}%`;
    };
    atY.oninput = () =&gt; {
      movebox.style.setProperty('offset-path', createRayPath());
      outY.value = `${atY.value}%`;
    };
   
    function createRayPath() {
      const contain = chkContain.checked ? 'contain' : '';
      const size = document.querySelector('input:checked').value;
      const pos = `${atX.value}% ${atY.value}%`;
      let ray = `${rangeSet.value}deg ${contain} ${size} at ${pos}`.replaceAll('', ' ');
      ray = `ray(${ray})`;
      return ray;
    }
&lt;/script&gt;
    </pre></div>

</div>

<script type="module">
    import hl from 'https://638183.freep.cn/638183/web/js/hl.js';
    const divs = document.querySelectorAll('.hEdiv');
    const pres = document.querySelectorAll('.hEpre');
    divs.forEach((div,idx) => hl.hl(div, pres));
</script>

霜染枫丹 发表于 2026-8-1 12:09

马老师中午好!

这个我运行了一下,特别赞佩!喜欢这形式,我先抱走了。很感谢您的分享,辛苦了,祝您吉祥快乐!{:4_178:}{:4_199:}{:4_190:}{:4_204:}

红影 发表于 2026-8-1 12:56

去运行了一下,看着小方块按照指令滑行着,closest-side(最近边,默认)还有最远边等等的那几个设置没弄明白是什么意思呢{:4_204:}

小辣椒 发表于 2026-8-1 13:06

小辣椒欣赏加学习{:4_187:}

马黑黑 发表于 2026-8-1 14:58

小辣椒 发表于 2026-8-1 13:06
小辣椒欣赏加学习

{:4_190:}

马黑黑 发表于 2026-8-1 15:09

红影 发表于 2026-8-1 12:56
去运行了一下,看着小方块按照指令滑行着,closest-side(最近边,默认)还有最远边等等的那几个设置没弄 ...
表格里关于 ray() 参数都有简要说明。

size 参数用来设置射线的长度,共有五个可选值,都是基于包含块(容器)的边界、从起点到指定边的距离:

① 最近边,射线长度按从起点到最近边的距离计算(缺省默认);
② 最远边,射线长度按从起点到最远边的距离计算;
③ 最近角,射线长度按从起点到最近角的距离计算;
④ 最远角,射线长度按从起点到最远角的距离计算;
⑤ sides(边界),射线长度按从起点到射线延长线与容器相交的边的距离计算。

杨帆 发表于 2026-8-1 22:23

谢谢马老师精彩讲解 ray函数四个参数的直观效果。另:contain作为可选参数,默认值是什么?

红影 发表于 2026-8-2 09:18

马黑黑 发表于 2026-8-1 15:09
表格里关于 ray() 参数都有简要说明。

size 参数用来设置射线的长度,共有五个可选值,都是基于包含块 ...

所以,我不明白的是,最近边和最远边到底是什么呢?

马黑黑 发表于 2026-8-2 12:22

红影 发表于 2026-8-2 09:18
所以,我不明白的是,最近边和最远边到底是什么呢?
射线都有起点,假设是 a(40% 20%)。

因为角度,射线有了方向,假设是 0deg,射线朝上(正上方向)。

射线的长度依据 size 参数设定,假设设为最近边(closest-side),那么,射线的长度按 a 点到四个边中的最近的那一个计。这条边不论是哪一边,不一定是射线指向的边,仅用作距离参照,即点 a 到这个边的垂直距离。

所以,这条射线,起点在点 a、方向指向正北、长度是点 a 到最近边的距离。

马黑黑 发表于 2026-8-2 12:25

杨帆 发表于 2026-8-1 22:23
谢谢马老师精彩讲解 ray函数四个参数的直观效果。另:contain作为可选参数,默认值是什么?

contain 参数缺省默认就是没有 contain,所以,contain 有就有,没有就没有

杨帆 发表于 2026-8-2 13:18

马黑黑 发表于 2026-8-2 12:25
contain 参数缺省默认就是没有 contain,所以,contain 有就有,没有就没有

谢谢老师答疑解惑~{:4_190:}

马黑黑 发表于 2026-8-2 21:16

杨帆 发表于 2026-8-2 13:18
谢谢老师答疑解惑~

{:4_190:}

红影 发表于 2026-8-2 21:39

马黑黑 发表于 2026-8-2 12:22
射线都有起点,假设是 a(40% 20%)。

因为角度,射线有了方向,假设是 0deg,射线朝上(正上方向)。


我的天,刚发现,这个概念居然这么奇特,还是头一次知道呢,怪不的前面怎么都想不明白。

马黑黑 发表于 2026-8-2 22:43

红影 发表于 2026-8-2 21:39
我的天,刚发现,这个概念居然这么奇特,还是头一次知道呢,怪不的前面怎么都想不明白。

CSS中,最近边、最远边和最近角、最远角是常用的距离概念
页: [1]
查看完整版本: offset-path ray函数演示(二)