如何在CSS中绘制曲线图形及展示动画

首先,回顾一下box-shadow这个属性。基本属性用法就是给元素创造一层阴影。

再简单提一下,本文会用到的关于阴影的第一个技巧:

使用阴影复制图像/投影图像

当 box-shadow 的第三、第四个参数模糊半径和扩张半径都为 0 的时候,我们可以得到一个和元素大小一样的阴影:

div { width: 80px; height: 80px; border: 1px solid #333; box-sizing: border-box; box-shadow: 80px 80px 0 0 #000; }

得到如下结果:

如何在CSS中绘制曲线图形及展示动画

阴影可以是多重的

第二个技巧则是,box-shadow是允许多重阴影的,并且他们的坐标是可以完全掌控的。

是的,我们可以像下面这样给一个元素定义多重阴影,并且利用阴影的第一、第二个参数控制它相对于元素的坐标:

div { width: 80px; height: 80px; border: 1px solid #333; box-sizing: border-box; box-shadow: 80px 80px 0 0 #000, 70px 70px 0 0 #000, ... 60px 60px 0 0 #000; }

在阴影坐标中运用三角函数

继续。接下来,我们尝试在阴影的坐标中引入三角函数。

为啥是三角函数,不是圆的标准方程或者椭圆的标准方程或者其他图形函数呢?当然也是可以的,只是这里借助三角函数的cos或sin可以实现直接使用 CSS 实现起来很困难的曲线。

带着疑问,先继续向下,假设我们要实现这样一条曲线:

如何在CSS中绘制曲线图形及展示动画

使用 CSS 的话,有什么办法呢?

可能的一些办法是clip-path,或者一些奇技淫巧,使用text-decoration里的波浪下划线wavy,或者是使用渐变叠加。

当然,还有一种办法是本文将提到的使用box-shadow及 三角函数。

三角函数

咳咳,简单回顾下三角函数里面的 sin、cos 曲线图像变换,还没有全部还给老师。

如何在CSS中绘制曲线图形及展示动画

如果我们有一个 1x1 的 div,它的多重阴影,能够按照像正弦/余弦函数的图像一样进行排布,连起来不就是一条曲线吗?

如何在 CSS 中使用三角函数 sin/cos

想法不错,但是 CSS 本身并没有提供三角函数。这里,我们需要借助 Sass 来在 CSS 中实现简单的三角函数。

还好,已经有前人帮忙把这个工作做完了:

trigonometry in sass

在Sass中实现三角函数计算

简单而言,就是借助三角函数的泰勒展开式,使用 Sass 函数模拟实现三角函数的 sin()、cos()、tan():

如何在CSS中绘制曲线图形及展示动画

由于展开式是无限长的,使用 Sass 函数模拟时,不可能得到一个非常精确的值,但是在日常作图下已经完全够用了,以下是使用 Sass 函数模拟实现三角函数的 sin()、cos()、tan():

@function fact($number) { $value: 1; @if $number>0 { @for $i from 1 through $number { $value: $value * $i; } } @return $value; } @function pow($number, $exp) { $value: 1; @if $exp>0 { @for $i from 1 through $exp { $value: $value * $number; } } @else if $exp < 0 { @for $i from 1 through -$exp { $value: $value / $number; } } @return $value; } @function rad($angle) { $unit: unit($angle); $unitless: $angle / ($angle * 0 + 1); @if $unit==deg { $unitless: $unitless / 180 * pi(); } @return $unitless; } @function pi() { @return 3.14159265359; } @function sin($angle) { $sin: 0; $angle: rad($angle); // Iterate a bunch of times. @for $i from 0 through 20 { $sin: $sin + pow(-1, $i) * pow($angle, (2 * $i + 1)) / fact(2 * $i + 1); } @return $sin; } @function cos($angle) { $cos: 0; $angle: rad($angle); // Iterate a bunch of times. @for $i from 0 through 20 { $cos: $cos + pow(-1, $i) * pow($angle, 2 * $i) / fact(2 * $i); } @return $cos; } @function tan($angle) { @return sin($angle) / cos($angle); }

由于上面最终计算 sin、cos 泰勒展开的时候,只使用了 20 层循环,所以当传入的值太大的时候,则会产生较大误差。经测试,传入数值在 [-20, 20] 以内,精度还是非常高的。

而以 sin 函数为例,x 取值在 [-π, π] 之间,已经能覆盖所有 sin(x) 的取值范围,所以 [-20, 20] 这个范围是完全够用的,我们只需要尽量让传入的 x 值落在这个区域范围内即不会产生太大误差。

好,铺垫了那么多,接下来使用上述的 sin 函数试一下,假设我们有这样一个结构:

div { width: 1px; height: 1px; background: #000; border-radius: 50%; }

我们再借助 Sass 实现一个 50 层的循环,当然其中阴影的 x 坐标使用了 sin 函数:

@function shadowSet($vx, $vy) { $shadow : 0 0 0 0 #000; @for $i from 0 through 50 { $x: sin($i / 8) * $vx; $y: $i * $vy; $shadow: $shadow, #{$x} #{$y} 0 0 rgba(0, 0, 0, 1); } @return $shadow; } div { width: 1px; height: 1px; background: #000; border-radius: 50%; box-shadow: shadowSet(4px, 1px); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygdgs.html