ray()

Baseline 2024
新推出

自 ⁨2024 年 1 月⁩起,此特性已在最新的设备和浏览器版本中可用。此特性可能无法在较旧的设备或浏览器上使用。

ray() CSS 函数定义了动画元素可以遵循的 offset-path 线段。该线段被称为“射线”(ray)。射线从 offset-position 开始,并沿指定角度的方向延伸。射线的长度可以通过指定大小并使用 contain 关键字来约束。

语法

css
/* all parameters specified */
offset-path: ray(50deg closest-corner contain at 100px 20px);

/* two parameters specified, order does not matter */
offset-path: ray(contain 200deg);

/* only one parameter specified */
offset-path: ray(45deg);

参数

参数可以按任何顺序指定。

<angle>

指定线段从偏移起始位置延伸的方向。角度 0deg 位于 y 轴上指,正角度沿顺时针方向增加。

<size>

指定线段的长度,即 offset-distance 0%100% 之间的距离,相对于包含块。这是一个可选参数(如果未指定 <size>,则使用 closest-side)。它接受以下关键字值之一:

closest-side:射线的起点与元素的包含块最近的边之间的距离。如果射线的起点位于包含块的边缘上,则线段的长度为零。如果射线的起点在包含块之外,则包含块的边缘被视为延伸至无穷远。这是默认值。

closest-corner:射线的起点与元素包含块中最近的角之间的距离。如果射线的起点位于包含块的角上,则线段的长度为零。

farthest-side:射线的起点与元素的包含块最远的边之间的距离。如果射线的起点在包含块之外,则包含块的边缘被视为延伸至无穷远。

farthest-corner:射线的起点与元素包含块中最远的角之间的距离。

sides:射线的起点与线段与包含块边界相交的点之间的距离。如果起点在包含块边界上或之外,则线段的长度为零。

contain

缩短线段的长度,以便即使在 offset-distance: 100% 时,元素也能保持在包含块内。具体来说,线段的长度会减少元素边框盒宽度或高度的一半(取较大者),并且永远不小于零。这是一个可选参数。

at <position>

指定射线的起点以及元素在其包含块中的放置位置。这是一个可选参数。如果包含此参数,<position> 值必须以 at 关键字开头。如果省略,则使用元素的 offset-position 值。如果省略且元素没有 offset-position 值,则射线起始位置使用的值是 offset-position: normal,它将元素放置在包含块的中心(或 50% 50%)。

描述

ray() 函数通过一个角度和一个与参考点的距离(极坐标)来指定元素在二维空间中的位置,从而沿着路径定位元素。这一特性使得 ray() 函数在创建二维空间过渡时非常有用。相比之下,这种方法不同于通过指定点与固定原点的水平和垂直距离(笛卡尔坐标)来定位的方法(如 translate() 函数所使用的),也不同于通过动画使元素沿已定义路径移动的方法。

由于 ray() 在二维空间中工作,因此同时考虑元素的初始位置和方向非常重要。当 ray() 函数作为元素的 offset-path 值应用时,你可以通过以下方式控制这些方面:

  • 元素最初通过将元素的offset-anchor 点移动到元素的偏移起始位置来定位。默认情况下,射线的起始位置由 offset-position 值决定。如果 offset-position 被明确指定为 normal(或省略并允许其默认为 normal),则元素位于其包含块的中心(或 50% 50%)。指定 offset-position: auto 会将起始位置设置在元素位置的左上角(或 0 0)。
  • 元素最初会旋转,使其内联轴(文本流动的方向)与 ray() 指定的角度对齐。例如,当 ray() 的角度为 0deg(位于 y 轴向上)时,元素的内联轴会旋转为垂直,以匹配射线的角度。元素在其整个路径上都保持此旋转。要自定义此行为,请使用 offset-rotate 属性,它允许你为元素指定不同的旋转角度或方向,从而更精确地控制其沿路径移动时的外观。例如,设置 offset-rotate: 0deg 将移除 ray() 应用的任何旋转,使元素的内联轴重新与文本流动方向对齐。

正式语法

<ray()> = 
ray( <angle> &&
<ray-size>? &&
contain? &&
[ at <position> ]? )

<ray-size> =
closest-side |
closest-corner |
farthest-side |
farthest-corner |
sides

<position> =
<position-one> |
<position-two> |
<position-four>

<position-one> =
left |
center |
right |
top |
bottom |
x-start |
x-end |
y-start |
y-end |
block-start |
block-end |
inline-start |
inline-end |
<length-percentage>

<position-two> =
[ left | center | right | x-start | x-end ] && [ top | center | bottom | y-start | y-end ] |
[ left | center | right | x-start | x-end | <length-percentage> ] [ top | center | bottom | y-start | y-end | <length-percentage> ] |
[ block-start | center | block-end ] && [ inline-start | center | inline-end ] |
[ start | center | end ]{2}

<position-four> =
[ [ left | right | x-start | x-end ] <length-percentage> ] && [ [ top | bottom | y-start | y-end ] <length-percentage> ] |
[ [ block-start | block-end ] <length-percentage> ] && [ [ inline-start | inline-end ] <length-percentage> ] |
[ [ start | end ] <length-percentage> ]{2}

<length-percentage> =
<length> |
<percentage>

示例

为射线定义角度和起始位置

此示例展示了如何处理元素的起始位置,以及指定的射线角度如何影响元素的方向。

CSS

css
.box {
  background-color: palegreen;
  border-top: 4px solid black;
  opacity: 20%;
}

.box:first-of-type {
  position: absolute;
}

.box1 {
  offset-path: ray(0deg);
}

.box2 {
  offset-path: ray(150deg);
}

.box3 {
  offset-rotate: 0deg;
  offset-position: 20% 40%;
  offset-path: ray(150deg);
}

.box4 {
  offset-position: 0 0;
  offset-path: ray(0deg);
}

.box5 {
  offset-path: ray(60deg closest-side at bottom right);
}

transform-origin 类似,默认的锚点位于元素的中心。可以使用 offset-anchor 属性修改此锚点。

在此示例中,将各种 offset-path: ray() 值应用于编号为 15 的方框。每个方框的“包含块”都用虚线边框表示。左上角一个褪色的方框显示了在未应用任何 offset-positionoffset-path 的情况下每个方框的默认位置,以便进行并排比较。每个方框的顶部都用实线边框突出显示,以说明射线起点和方向的变化。在射线起点定位后,方框会与指定的射线角度方向对齐。如果未指定 offset-position,射线的默认偏移起始位置是方框包含块的中心(或 50% 50%)。

结果

  • box1 的初始位置是使其锚点(其中心)位于默认的偏移起始位置(包含块的 50% 50%)。box1 也被旋转以使其朝向射线的 0deg 角度。这现在将是路径的起点。通过与左侧褪色的 box0 进行比较,你可以观察到方框位置和旋转的变化。方框被旋转以匹配沿 y 轴向上的 0deg 角度。方框的旋转可以从方框内数字的方向看出。

  • box2 中,对射线应用了更大的正角度 150deg,以显示射线角度的工作方式。从左上角开始,方框沿顺时针方向旋转以达到指定的 150deg 角度。

  • box2box3 具有相同的 offset-path 值。在 box3 中,还对元素应用了 0degoffset-rotate。因此,元素将在射线的整个路径上保持这个特定的角度旋转,并且元素不会沿路径方向旋转。请注意,在 box3 中,射线路径为 150deg,但由于 offset-rotate,方框的方向在路径上不会改变。另请注意,box3offset-path 属性没有指定起始 <position>,因此射线的起始位置从元素的 offset-position 派生,本例中为 top 20% left 40%

  • box4offset-position 设置为包含块的左上角(0 0),因此,元素的锚点和偏移起始位置重合。0deg 的射线角度在此起始点应用于该元素。

  • box5 中,offset-path 属性指定了 at <position> 值,将方框放置在元素包含块的底部右侧边缘,并对射线的角度应用了 60deg

使元素沿射线动画

在此示例中,第一个形状作为其位置和方向的参考显示。对其他形状应用了射线运动路径。

CSS

css
body {
  display: grid;
  grid-template-columns: 200px 100px;
  gap: 40px;
  margin-left: 40px;
}

.container {
  transform-style: preserve-3d;
  width: 150px;
  height: 100px;
  border: 2px dotted green;
}

.shape {
  width: 40px;
  height: 40px;
  background: #2bc4a2;
  margin: 5px;
  text-align: center;
  line-height: 40px;
  clip-path: polygon(0% 0%, 70% 0%, 100% 50%, 70% 100%, 0% 100%, 30% 50%);
  animation: move 5000ms infinite alternate ease-in-out;
}

.shape2 {
  offset-path: ray(120deg sides contain);
}

.shape3 {
  offset-rotate: 0deg;
  offset-path: ray(120deg sides contain);
}

.shape4 {
  offset-position: auto;
  offset-path: ray(120deg closest-corner);
}

.shape5 {
  offset-position: auto;
  offset-path: ray(120deg farthest-corner);
}

@keyframes move {
  0%,
  20% {
    offset-distance: 0%;
  }
  80%,
  100% {
    offset-distance: 100%;
  }
}

结果

在前两个应用了 offset-path 的示例中,请注意在没有 offset-rotate 和有 offset-rotate 的情况下形状的方向。这两个示例都使用默认的 offset-positionnormal,因此,路径运动从 50% 50% 开始。最后两个 offset-path 示例显示了角 <size> 值的影响:closest-cornerfarthest-cornerclosest-corner 值创建了一个非常短的偏移路径,因为形状已经位于角落(offset-position: auto)。farthest-corner 值创建了最长的偏移路径,从包含块的左上角到右下角。

规范

规范
Motion Path Module Level 1
# ray-function

浏览器兼容性

另见