CSS `Trigonometric Functions` (`sin()`, `cos()`) (提案) 创建复杂形状

各位前端的侠士们,晚上好!今天咱们来聊点刺激的,关于CSS Trigonometric Functions,也就是CSS三角函数 (sin(), cos(), tan(), atan(), asin(), acos()) 的提案。别害怕,虽然听起来像数学课,但其实有了它们,咱们就能在CSS里玩转复杂的形状和动画,摆脱图片和SVG的束缚,想想都觉得兴奋!

开场白:CSS,不止于盒模型

咱们都知道,CSS的世界里,盒模型是基石。但时间长了,天天对着矩形、圆形,是不是有点审美疲劳?想象一下,如果咱们能用CSS直接绘制出各种奇形怪状,那该有多酷!这就是CSS三角函数提案的意义所在:它试图打破盒模型的限制,赋予CSS更强大的图形绘制能力。

什么是CSS三角函数?

简单来说,CSS三角函数就是允许咱们在CSS里使用正弦 (sin())、余弦 (cos())、正切 (tan()) 以及对应的反函数 (asin(), acos(), atan())。这些函数接收一个角度作为参数,返回一个介于 -1 和 1 之间的数值 (对于 sin()cos()),或者一个角度值 (对于反函数)。

为什么要用CSS三角函数?

  • 动态性: 可以根据屏幕尺寸、用户交互等动态调整形状和动画,实现真正的响应式设计。
  • 性能: 相比于使用图片或SVG,CSS绘制的图形通常具有更好的性能,尤其是对于复杂的动画效果。
  • 灵活性: 可以创造出各种独特的形状和动画,突破传统CSS的限制。
  • 可维护性: 代码可读性更高,更易于维护和修改。
  • 减少HTTP请求: 避免使用图片,减少HTTP请求,加快页面加载速度。

CSS三角函数的基本用法

先来看几个简单的例子,了解一下这些函数的基本用法。

/* 使用 sin() 和 cos() 创建一个圆形路径上的点 */
:root {
  --angle: 45deg; /* 定义一个角度变量 */
  --x: calc(50px + 50px * cos(var(--angle))); /* x坐标 */
  --y: calc(50px + 50px * sin(var(--angle))); /* y坐标 */
}

.circle-point {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: 10px;
  height: 10px;
  background-color: red;
  border-radius: 50%;
}

在这个例子中,我们使用了 sin()cos() 函数来计算一个点在圆形路径上的坐标。--angle 变量定义了角度,--x--y 变量分别计算了点的 x 和 y 坐标。通过改变 --angle 的值,我们可以让这个点沿着圆形路径移动。

sin(), cos(), tan() 函数

这三个是最常用的三角函数,它们的用法也很简单:

  • sin(angle):返回给定角度的正弦值。
  • cos(angle):返回给定角度的余弦值。
  • tan(angle):返回给定角度的正切值。

角度可以使用 deg (度)、rad (弧度)、grad (百分度) 或 turn (圈数) 作为单位。

.element {
  transform: rotate(calc(30deg * sin(45deg))); /* 旋转角度 */
  width: calc(100px * cos(60deg)); /* 宽度 */
  height: calc(50px * tan(30deg)); /* 高度 */
}

反三角函数:asin(), acos(), atan()

反三角函数用于计算给定值的角度。

  • asin(number):返回给定数字的反正弦值 (弧度)。数字必须在 -1 到 1 之间。
  • acos(number):返回给定数字的反余弦值 (弧度)。数字必须在 -1 到 1 之间。
  • atan(number):返回给定数字的反正切值 (弧度)。
.element {
  --angle: calc(asin(0.5)); /* 计算反正弦值,结果是弧度 */
  transform: rotate(calc(var(--angle) * 180 / pi())); /* 将弧度转换为度数 */
}

注意,反三角函数返回的是弧度值,如果需要转换为度数,可以使用 calc() 函数进行转换,其中 pi() 函数返回圆周率 π。

atan2() 函数

atan2(y, x) 函数返回点 (x, y) 与原点之间的角度,考虑到 x 和 y 的符号,可以确定角度所在的象限。这在创建指向特定位置的动画时非常有用。

:root {
  --mouse-x: 0; /* 鼠标x坐标 */
  --mouse-y: 0; /* 鼠标y坐标 */
  --angle: calc(atan2(var(--mouse-y), var(--mouse-x))); /* 计算角度 */
}

.arrow {
  transform: rotate(calc(var(--angle) * 180 / pi())); /* 旋转箭头 */
}

/* JavaScript 更新鼠标坐标 */
document.addEventListener('mousemove', (event) => {
  document.documentElement.style.setProperty('--mouse-x', event.clientX);
  document.documentElement.style.setProperty('--mouse-y', event.clientY);
});

在这个例子中,箭头会根据鼠标的位置旋转,始终指向鼠标。

实际应用:创建复杂形状和动画

有了这些三角函数,咱们就可以在CSS里创建各种复杂的形状和动画了。

1. 星形

<div class="star"></div>
.star {
  position: relative;
  width: 0;
  height: 0;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
  border-bottom: 35px solid red; /* 初始三角形 */
  transform-origin: 50% 100%; /* 旋转中心 */
}

.star::before,
.star::after {
  content: '';
  position: absolute;
  top: 0;
  left: -50px;
  width: 0;
  height: 0;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
  border-bottom: 35px solid red;
  transform-origin: 50% 100%;
}

.star::before {
  transform: rotate(calc(72deg * 1)); /* 旋转72度 */
}

.star::after {
  transform: rotate(calc(72deg * 2)); /* 旋转144度 */
}

如果使用三角函数,我们可以更加灵活的控制星形的形状,例如控制内角,外角,半径等。

<div class="star-trigonometric"></div>
.star-trigonometric {
    --points: 5;       /* 星星角数 */
    --radius: 50px;   /* 星星半径 */
    --inner-radius: 25px; /* 内半径 */
    position: relative;
    width: calc(var(--radius) * 2);
    height: calc(var(--radius) * 2);
    background: black;
    clip-path: polygon(
        /* 使用三角函数计算每个点的坐标 */
        /* 循环生成每个点的坐标 */
        /* 外部点 */
        calc(var(--radius) + var(--radius) * cos(calc(-90deg + var(--i) * (360deg / var(--points))))) calc(var(--radius) + var(--radius) * sin(calc(-90deg + var(--i) * (360deg / var(--points))))),
        /* 内部点 */
        calc(var(--radius) + var(--inner-radius) * cos(calc(-90deg + (var(--i) + 0.5) * (360deg / var(--points))))) calc(var(--radius) + var(--inner-radius) * sin(calc(-90deg + (var(--i) + 0.5) * (360deg / var(--points)))))

    );
    --i: 0; /* 用于循环的变量,不能直接在CSS中使用,所以需要配合javascript */
}

/*使用javascript 动态生成 clip-path */
const star = document.querySelector('.star-trigonometric');
let polygonString = '';
const points = 5;
const radius = 50;
const innerRadius = 25;

for (let i = 0; i < points; i++) {
    const angle = -Math.PI / 2 + i * (2 * Math.PI / points);
    const innerAngle = -Math.PI / 2 + (i + 0.5) * (2 * Math.PI / points);

    const x1 = radius + radius * Math.cos(angle);
    const y1 = radius + radius * Math.sin(angle);

    const x2 = radius + innerRadius * Math.cos(innerAngle);
    const y2 = radius + innerRadius * Math.sin(innerAngle);

    polygonString += `${x1}px ${y1}px, ${x2}px ${y2}px, `;
}

// 移除最后一个逗号和空格
polygonString = polygonString.slice(0, -2);

star.style.clipPath = `polygon(${polygonString})`;

说明:

  • --points: 星星的角数。
  • --radius: 星星的外半径。
  • --inner-radius: 星星的内半径。
  • clip-path: 使用polygon()函数绘制星星的形状。

上述代码需要配合javascript来实现,因为CSS中没有循环语句,无法动态生成多个坐标点。

2. 波浪动画

<div class="wave"></div>
.wave {
  position: relative;
  width: 200px;
  height: 100px;
  overflow: hidden;
}

.wave::before {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  width: 200%;
  height: 50%;
  background-color: blue;
  animation: wave 5s linear infinite;
}

@keyframes wave {
  0% {
    transform: translateX(0) translateY(calc(10px * sin(0deg)));
  }
  100% {
    transform: translateX(-50%) translateY(calc(10px * sin(360deg)));
  }
}

在这个例子中,我们使用了 sin() 函数来控制波浪的垂直位置,创建了一个简单的波浪动画。

3. 螺旋线

<div class="spiral"></div>
.spiral {
  position: relative;
  width: 200px;
  height: 200px;
}

.spiral::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 2px;
  height: 2px;
  background-color: red;
  animation: spiral 5s linear infinite;
}

@keyframes spiral {
  0% {
    transform: translate(-50%, -50%) rotate(0deg) translateX(0px);
  }
  100% {
    transform: translate(-50%, -50%) rotate(3600deg) translateX(100px);
  }
}

这个例子中,我们结合了 rotate()translateX() 变换,创建了一个螺旋线动画。

4. 使用 clip-path 创建复杂形状

clip-path 属性可以裁剪元素,使其显示为指定的形状。结合三角函数,我们可以创建各种复杂的裁剪路径。

<div class="clipped-shape"></div>
.clipped-shape {
  width: 200px;
  height: 200px;
  background-color: green;
  clip-path: polygon(
    calc(50% + 50px * cos(0deg)) calc(50% + 50px * sin(0deg)),
    calc(50% + 50px * cos(72deg)) calc(50% + 50px * sin(72deg)),
    calc(50% + 50px * cos(144deg)) calc(50% + 50px * sin(144deg)),
    calc(50% + 50px * cos(216deg)) calc(50% + 50px * sin(216deg)),
    calc(50% + 50px * cos(288deg)) calc(50% + 50px * sin(288deg))
  );
}

这个例子使用 clip-path 创建了一个五边形。

表格总结

函数 描述 参数 返回值
sin(angle) 返回给定角度的正弦值。 角度 (deg, rad, grad, turn) 介于 -1 和 1 之间的数值
cos(angle) 返回给定角度的余弦值。 角度 (deg, rad, grad, turn) 介于 -1 和 1 之间的数值
tan(angle) 返回给定角度的正切值。 角度 (deg, rad, grad, turn) 数值
asin(number) 返回给定数字的反正弦值 (弧度)。数字必须在 -1 到 1 之间。 数字 (-1 到 1) 弧度
acos(number) 返回给定数字的反余弦值 (弧度)。数字必须在 -1 到 1 之间。 数字 (-1 到 1) 弧度
atan(number) 返回给定数字的反正切值 (弧度)。 数字 弧度
atan2(y, x) 返回点 (x, y) 与原点之间的角度 (弧度),考虑到 x 和 y 的符号。 y, x 弧度
pi() 返回圆周率 π 的值。 圆周率 π 的值 (约等于 3.141592653589793)

注意事项

  • 兼容性: 截至目前(2024年),CSS三角函数提案仍在草案阶段,尚未被所有浏览器完全支持。使用前请务必检查浏览器的兼容性。
  • 性能: 复杂的三角函数计算可能会影响性能,尤其是在动画中。请谨慎使用,并进行性能测试。
  • 可读性: 复杂的三角函数表达式可能会降低代码的可读性。建议使用变量和注释来提高代码的可读性。

总结

CSS三角函数提案为咱们打开了一扇新的大门,让咱们可以在CSS里创造出各种复杂的形状和动画。虽然目前兼容性还不是很好,但相信随着提案的推进和浏览器的支持,它将成为前端开发中一个非常有用的工具。希望今天的讲解能帮助大家更好地理解和使用CSS三角函数,创造出更加炫酷的网页效果!

下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注