澳门新浦京娱乐游戏CSS3 SVG实现可爱的动物哈士奇和狐狸动画

本文由码农网 –
小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

原文:The State of
CSS Reflections

译者:nzbin

友情提示:由于演示 demo
的兼容性,推荐火狐浏览。该文章篇幅较长,内容庞杂,有一定难度。而我本人学识有限,加之时间仓促,所翻译内容可能有不恰当及晦涩之处。欢迎大家拍砖指正。

今天,我想向大家展示如何巧妙地使用HTML、CSS排序动画和SVG滤镜把生活中可能最可爱的东西之一——动物画到网页上。我们将探讨绘制动物的两种技术:一种使用纯HTML和CSS,另一种使用内联SVG背景图像。

我最近在 codePen 上看到了这个
加载程序,一个纯 CSS
制作的带有渐变反射的 3D
旋转竖条。它的制作方法是:为每个竖条创建一个元素,然后通过复制每一个元素来制作反射倒影,最后在反射倒影上添加渐变背景来制作渐隐的效果。听上去有点复杂,而且创建渐隐效果的渐变背景在非纯色背景下是无效的。有没有更好的
CSS 方法呢?

 

此演示高度实验性质——动画SVG滤镜目前仅在Chrome中可用。

澳门新浦京娱乐游戏 1

CSS动画工具 & 库

所涉及的动画也很复杂,因此本教程将重点介绍创建这些动物以及栩栩如生的动作所涉及的不同技术。放飞你的创意,自行创作独特和俏皮的动物动画吧。

答案是‘肯定’的,也是‘否定’的。‘肯定’是因为确实有可以做的方法,‘否定’是因为有些方法还不存在。令人遗憾的是,这些代码只能用预处理器(主要通过循环来实现压缩功能)压缩一点点。如果我们不想使用
canvas
并且想兼容主流浏览器的当前版本,复制竖条来制作倒影以及通过渐变背景来制作渐隐效果的方法仍然是最好的。

1. Animate Plus

话不多说,开始咯!

这篇文章主要探索现有的制作反射倒影的方法、举例说明可能的解决方案、跨浏览器问题以及我的一些想法。

一个可以帮你创建CSS属性和SVG属性的JavaScript动画库。

澳门新浦京娱乐游戏 2

基本设置

澳门新浦京娱乐游戏 3

在线演示
 
源码下载

创建竖条元素

首先创建一个 .loader 元素以及在其中创建10个 .bar 元素

HTML

<div class='loader'>
  <div class='bar'></div>
  <!-- repeat to create 9 more bars -->
</div>

把同样的事情写很多遍是一件痛苦的事,所以在该情况下使用一个预处理器会变得很简单。我们在这里使用
Haml 模板,当然也有人会选择其他的模板。

Haml

.loader
  - 10.times do
  .bar

 通过绝对定位把所有元素放到视图的中间。大多数情况下,我们会使用 top: 50%
,但是现在,使用 bottom: 50% 会使后面的操作更简单。

CSS

div {
  position: absolute;
  bottom: 50%; left: 50%;
}

给竖条设置 width 和 height ,为了能看到它再设置一个 background

SCSS

$bar-w: 1.25em;
$bar-h: 5 * $bar-w;

.bar {
  width: $bar-w; 
  height: $bar-h;
  background: currentColor;
}

我们希望竖条的底部贴合视图的水平中心线。设置 bottom: 50% 已经可以了。

现在所有的竖条都重合在一起,它们的左边贴在垂直中心线上,底部贴在水平中心线上。

See the Pen bar loader 1.1 creating the
bars by
Ana Tudor (@thebabydino) on
CodePen.

2. Rocket

塑造动物外形

演示使用两种不同的技术来创建动物不同身体部位的形状。哈士奇使用CSS border-radius属性,狐狸使用内联背景SVG图像,因为后者的形状更复杂。

定位竖条

我们需要让最左边的竖条和最右边的竖条到垂直中心线的距离相等。这个距离就是竖条数量( $n
)的一半乘以竖条的 width( $bar-w )。原始 demo 用的是普通的
CSS,我们会使用 Sass 来减少代码量。

See the Pen initial (stacked) vs. final
(distributed)
by Ana Tudor (@thebabydino) on
CodePen.

这意味着,从竖条的起始位置开始,我们需要将第一个竖条向左移动 5 * $n * $bar-w
。左侧是 x 轴的负方向,需要在前面加 -
号。所以第一个竖条的 margin-left 就是 -.5 * $n * $bar-w

第二个竖条(以 0 为基数,索引值是 1)就是向右(x
轴的正方向)移动 1
个竖条的宽度($bar-w)。所以第二个竖条的 margin-left
就是 -.5 * $n * $bar-w + $bar-w

第三个竖条(以 0 为基数,索引值是 2)就是向右(x
轴的正方向)移动 2 个竖条的宽度。所以第三个竖条的 margin-left
就是 -.5 * $n * $bar-w + 2 * $bar-w

最后一个(以 0 为基数,索引值是
$n - 1)就是向右(x轴的正方向)移动 $n - 1
个竖条的宽度。所以最后一个竖条 margin-left
就是 -.5 * $n * $bar-w + ($n - 1) * $bar-w

See the Pen bar
distribution
by Ana Tudor (@thebabydino) on
CodePen.

通常情况下,如果我们认为当前竖条的索引值是 $i (以 0
为基数),那么 $i 竖条的 margin-left
就是 -.5 * $n * $bar-w + $i * $bar-w
,可以简化为 ($i - .5 * $n) * $bar-w

这就允许我们使用 Sass 的循环来定位竖条。

SCSS

$n: 10;

@for $i from 0 to $n {
  .bar:nth-child(#{$i + 1}) {
  margin-left: ($i - .5 * $n) * $bar-w;
  }
}

 为了看清楚竖条的边界,我们给它一个 box-shadow

See the Pen bar loader 1.2 positioning the
bars by
Ana Tudor (@thebabydino) on
CodePen.

一个创建WEB动画的简单的工具。

HTML标记

两只动物都使用嵌套的HTML部分对身体部位进行分组。分组的概念对于创造逼真的动画效果非常重要——当头部移动时,眼睛和耳朵也应该保持一起移动,因为它们是长在头上的。

<!-- Markup for the fox head -->
<div class="fox-head">
  <div class="fox-face">            
    <div class="fox-ears">
      <div class="fox-ear"></div>
      <div class="fox-ear"></div>
    </div>
    <div class="fox-skull"></div>
    <div class="fox-front"></div>
    <div class="fox-eyes"></div>
    <div class="fox-nose"></div>
  </div>
</div>

<!-- Markup for the husky head -->
<div class="husky-head">
  <div class="husky-ear"></div>
  <div class="husky-ear"></div>
  <div class="husky-face">
    <div class="husky-eye"></div>
    <div class="husky-eye"></div>
    <div class="husky-nose"></div>
    <div class="husky-mouth">
      <div class="husky-lips"></div>
      <div class="husky-tongue"></div>
    </div>
  </div>
</div>

每个部分均可以独立移动,并随着其父元素的移动而移动,这样会产生更逼真的效果。不知道你发现没有,尾巴是深深嵌套到其他尾部组件中的。当每个尾巴部分相对于其母体定位,然后旋转相同的量时,就会产生均匀曲线的视觉感。

澳门新浦京娱乐游戏 4

给竖条添加渐变

竖条的背景色是从最左边的深蓝色( #1e3f57
)过渡到最右边的浅蓝色( #63a6c1 )。这听上去很像 the Sass mix()
function
所做的。第一个参数是浅蓝色,第二个参数是深蓝色,第三个参数(称作相对权重)表示将多少( %
表示)浅蓝色混合进去。

对于第一个竖条,这个数量就是 0% ( 0%
数量的浅蓝色),混合结果就是深蓝色。

对于最后一个竖条,这个数量是 100%( 100% 数量的浅蓝色,也就是 0%
数量的深蓝色),得到的背景色就是浅蓝色。

对于剩下的竖条,我们需要平均分布的中间值。如果我们有 $n
个竖条,第一个竖条在 0% 的位置,最后一个竖条在 100%
的位置,那么我们需要在两者之间平分成 $n - 1 个区间。

See the Pen distribute n points on 100% interval
(interactive) by Ana Tudor
(@thebabydino) on
CodePen.

一般来说,索引值为 $i澳门新浦京娱乐游戏,
的竖条的相对权重是 $i * 100% / ($n - 1),这意味着我们要添加如下代码:

SCSS

$c: #63a6c1 #1e3f57; // 1st = light 2nd = dark

@for $i from 0 to $n {
  // list of mix() arguments for current bar
  $args: append($c, $i * 100% / ($n - 1));

  .bar:nth-child(#{$i + 1}) {
  background: mix($args...);
  }
}

现在这些竖条看起来就和原始 demo 的一样了:

See the Pen bar loader #1.3 shading the
bars
by Ana Tudor (@thebabydino) on
CodePen.

澳门新浦京娱乐游戏 5

用CSS塑造图形

CSS的border-radius属性大量用来塑造哈士奇的形象。对于许多元素要素,需要对每个边界半径进行逐个控制。例如,下面是如何构造哈士奇后腿的代码:

.husky-hind-leg {
  // ...
  border-top-left-radius: 35% 100%;
  border-top-right-radius: 40% 100%;
}

第一个数字表示曲线从顶部/底部边缘开始的深度,第二个数字表示曲线从左/右边缘开始的深度。

其他形状,如前腿,不能单独用border-radius成形,需要使用transform成形:

.husky-front-legs > .husky-leg:before {
  transform: skewY(-30deg) skewX(10deg);
  transform-origin: top right;
}

一旦图形就位,那么每个元素就能在其父元素中被赋予绝对的基于百分比的位置。这确保每个身体部位的精确放置以及响应性。

探索反射的方案

  1. Tuesday

用SVG塑造图形

至于狐狸,Sass-SVG被用来为每个身体部位创建复杂的SVG形状。SVG图像可以用作背景图像,更好的是,只要它们是基于64或UTF-8编码的,就可以被内联编写(为了最大限度的浏览器支持)。

不过,SVG代码手写起来非常棘手。我使用Adobe Illustrator来创建初始形状:

澳门新浦京娱乐游戏 6

然后我将每个身体部分保存为SVG图像。SVG代码通过Sass-SVG传输到SCSS样式表。例如,这是狐狸的鼻子:

.fox-nose:before {
  @include svg((viewBox: (0 0 168 168))) {
    // the nose
    @include svg('path', (
      fill: $color-nose,
      d: 'M83.7,86.7c3.3,0,11.6-3.9,11.6-7.1c0-3.2-9.4-3.2-11.6-3.2c-2.2,0-11.6,0-11.6,3.2   C72.1,82.8,80.4,86.7,83.7,86.7z'
    ));

    // the line connecting the nose to the mouth
    @include svg('path', (
      stroke: $color-nose,
      fill: none,
      d: 'M83.7,102.3V86.7'
    ));

    // the mouth
    @include svg('path', (
      stroke: $color-nose,
      fill: none,
      d: 'M94.5,104.9c0,0-5.2-2.7-10.8-2.7c-5.6,0-10.8,2.7-10.8,2.7'
    ));
  }
}

这将在`url()`中生成一个编码的内联SVG字符串,看起来像这样:

.fox-nose:before {
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg...");
}

由于SVG是一个背景图像,因此它可以被转换和动画化,就像一个HTML元素一样。使用Sass-SVG,Sass $variables可用于完全控制SVG填充和笔触颜色。

通过内联SVG使狐狸响应起来很简单。viewbox属性值((viewBox:(0 0 168
168)))直接来自SVG文件,但只要保持高/宽比率,那么包含SVG背景图像的元素可以是任意大小。狐狸头部的所有部分都是绝对定位的,具有与.fox-head相同的高度和宽度。

WebKit浏览器:-webkit-box-reflect

很遗憾,这不是一个标准属性!我不知道为什么这个属性没有标准化。这一属性首次出现在Safari浏览器上时,我还不知道
CSS。 但是对于 WebKit
内核的浏览器,这是一个非常好的实现方法。它做了很多工作。它的使用很简单,即使在不支持该属性的浏览器上,除了不显示反射以外,并没有什么其他影响。

让我们看看它是怎么工作的,它需要三个参数值:

  • 方向:包含 belowleft , above , right
  • offset
    偏移值(可选):指定反射的开始位置到元素的底边的距离(这是一个 CSS
    长度值)。
  • 图片遮罩 mask(可选):可以是 CSS 渐变值。

See the Pen how `-webkit-box-reflect`
works by Ana Tudor
(@thebabydino) on
CodePen.

注意linear-gradient()可以有更多的颜色断点,也可以用
radial-gradient()替换。

在我们的 demo 中,我首先想到的就是给 .loader 元素添加这一属性。

SCSS

.loader {
  -webkit-box-reflect: below 0 linear-gradient(rgba(#fff), rgba(#fff, .7));
}

但是在 WebKit 浏览器中测试时,我们并没有看到反射。

See the Pen bar loader 2.1.1
-webkit-box-reflect
by Ana Tudor (@thebabydino) on
CodePen.

这里发生了什么?我们给所有的元素设置了绝对定位,但是并没有设置 .loader
元素的尺寸。所以这是一个宽高都为 0 的元素。

让我们给这个元素一个明确的尺寸,高度 height 等于竖条的高度 $bar-h
,宽度等于所有竖条的 width 之和 $n * $bar-w
。为了看清元素的边界,我们暂时给它一个 box-shadow

SCSS

$loader-w: $n * $bar-w;

.loader {
  width: $loader-w; height: $bar-h;
  box-shadow: 0 0 0 1px red;
}

我之所以用 box-shadow 而不用 box-shadow
是因为如果子元素溢出父元素,在不同的浏览器上使用
outline
突出物体的效果是不一样的。

澳门新浦京娱乐游戏 7

outline属性在WebKit浏览器中的对比。Edge(上)vs.
Firefox(下)

 

添加以上代码后的结果可以在 WebKit 浏览器中看到如下效果:

See the Pen bar loader 2.1.2 explicitly sizing the
loader
by Ana Tudor (@thebabydino) on
CodePen.

如果你用的不是 WebKit 浏览器,看下面的图片,就是这个样子:

澳门新浦京娱乐游戏 8

现在我们可以看到 loader 元素的边界和倒影,但是位置不正确。我们希望
loader 元素在水平中间的位置,所以把它向左移动 width
的一半。我们也希望子元素的底部与父元素的底部贴合,所以设置子元素 bottom: 0

SCSS

.loader { margin-left: -.5 * $loader-w; }

.bar { bottom: 0; }

修正位置之后的样子如下:

澳门新浦京娱乐游戏 9

See the Pen bar loader 2.1.3 tweaking loader and bar
positions
by Ana Tudor (@thebabydino) on
CodePen.

新奇CSS动画库。

“Squigglevision”和SVG滤镜

Squigglevision是一种通过摆动形状轮廓来模拟手绘动画的动画技术。这使得像狐狸和哈士奇这样的场景看上去更加动态化和手绘化,即使动物在不动的时候也是如此。

SVG有一个称为<feTurbulence>的滤镜,可以给任何应用了此滤镜的地方“噪声”。结合<feDisplacementMap>滤镜以指定像素在每个过滤器中移动的距离。

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="squiggly-0">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="0"/>
      <feDisplacementMap id="displacement" in="SourceGraphic" in2="noise" scale="2" />
    </filter>
    <filter id="squiggly-1">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="1"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="3" />
    </filter>

    <filter id="squiggly-2">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="2"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="2" />
    </filter>
    <filter id="squiggly-3">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="3"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="3" />
    </filter>

    <filter id="squiggly-4">
      <feTurbulence id="turbulence" baseFrequency="0.02" numOctaves="3" result="noise" seed="4"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="1" />
    </filter>
  </defs> 
</svg>

属性的任何元素。要创建“squigglevision”效果,关键帧动画快速地一次设置一个滤镜

@keyframes squigglevision {
  0% {
    -webkit-filter: url('#squiggly-0');
    filter: url('#squiggly-0');
  }
  25% {
    -webkit-filter: url('#squiggly-1');
    filter: url('#squiggly-1');
  }
  50% {
    -webkit-filter: url('#squiggly-2');
    filter: url('#squiggly-2');
  }
  75% {
    -webkit-filter: url('#squiggly-3');
    filter: url('#squiggly-3');
  }
  100% {
    -webkit-filter: url('#squiggly-4');
    filter: url('#squiggly-4');
  }
}

注意:这些SVG滤镜目前在Firefox中似乎不起作用,因此可以将这样的滤镜动画视为一种渐进增强处理。

火狐浏览器 element() + mask

澳门新浦京娱乐游戏 10

给动物添加动画特效

CSS关键帧不能为我们提供一种方便的排序和组合动画的方法。解决这个问题的最好方法是将动画计划(故事板)作为时间轴,并使用预处理器,如Sass,生成关键帧。

例如狐狸,在概述每个动画应发生的故事板之后,转换和绝对时间偏移(秒)被用于对每个身体部分进行动画处理。以下是SCSS中对狐狸鼻子进行概述的一个例子:

$animations: (
  // ...

  'nose': (
    // resting position
    (4s, 5s, 7s): rotateY(-4deg),

    // nose down
    4.5s: rotateY(-4deg) rotateX(-3deg),

    // fox looks left
    (7.5s, 9s): rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg),

    // fox looks right
    (9.5s, 12s): rotateY(7deg),

    // fox looks straight ahead
    13s: rotateY(0),
  ),

  // ...
);

在这里,$animations是一类Sass
map,其中键是动画的名称(例如“nose”)。每个动画名称的值是另一个map,其中键是以秒为单位的偏移或偏移列表(例如(7.5s,9s)),并且值是每个偏移键的transform属性。

那么,我们怎么把这个map变成@keyframe动画呢?首先,设置全局的$duration:
17s变量——这将是每个动画的总持续时间。然后,使用嵌套的Sass @each ... in ... 循环,我们可以通过对$animations map循环为每个动画生成预期的CSS
@keyframe声明:

@each $animation-name, $animation in $animations {
  // keyframe declaration
  @keyframes #{$animation-name} {
    @each $offsets, $transform in $animation {
      @each $offset in $offsets {
        // offset declaration block    
        #{percentage($offset / $duration)} {
          // transform property
          transform: #{$transform};
        }
      }
    }
  }
}

这将生成如下所示的关键帧:

@keyframes nose {
  14.70588% {
    transform: rotateY(-4deg); }
  23.52941% {
    transform: rotateY(-4deg); }
  29.41176% {
    transform: rotateY(-4deg); }
  41.17647% {
    transform: rotateY(-4deg); }
  26.47059% {
    transform: rotateY(-4deg) rotateX(-3deg); }
  44.11765% {
    transform: rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg); }
  52.94118% {
    transform: rotateX(-3deg) rotateY(-28deg) rotateZ(-11deg); }
  55.88235% {
    transform: rotateY(7deg); }
  70.58824% {
    transform: rotateY(7deg); }
  76.47059% {
    transform: rotateY(0); } }

在不使用SCSS的情况下,这些百分比的计算可能非常繁琐。它们代表动画的每个步骤中每个所需时间值相对于总$duration的百分比偏移量。

然后可以将动画应用于它们各自的身体部位,例如animation: nose $duration
none infinite;。每个动画的持续时间都得是一样的,这样它们可以无缝循环。

element() 制作反射

element() 函数(现在仍然有效,必须在火狐浏览器中使用并且添加 -moz-
前缀)给我们提供了一个像真实图片一样可以任意使用的图像值。它需要一个参数值,就是我们希望以 background
还是 border-image 显示的被选元素的 id
。这允许我们做很多事情,比如使用可以控制的图片作为背景 。我们也可以在
Firefox 中制作一个反射元素。

需要着重了解的一点就是 element()
函数不是递归函数,我们不能创建使用元素作为自身背景的图像。这在创建反射的loader元素的伪类上使用是安全的,因此我们不用创建额外的元素。

好吧,让我们看看如何操作。首先给 loader 元素一个 id
。转到样式表,我们从适用于 WebKit 浏览器的CSS着手。在 loader
元素上添加一个 ::after 伪类

CSS

.loader::after {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  box-shadow: 0 0 0 2px currentColor;
  color: crimson;
  content: 'REFLECTION';
}

为了在最终效果中看清伪类的边界和方向,我们设置了一些暂时性的样式,我们想让它是颠倒的。

See the Pen bar loader 2.2.1 adding a
pseudo
by Ana Tudor (@thebabydino) on
CodePen.

现在我们需要以底边为基准把 ::after
伪类镜像过来。为了做到这一点,使用 scaleY()
属性并且选择合适的 transform-origin

以下的可交互 demo
说明了包含多个缩放因子以及变换中心的定向缩放是如何工作的:

See the Pen how CSS scaling w.r.t. various origins
works by Ana Tudor
(@thebabydino) on
CodePen.

注意:缩放因子的数值和变换中心可以超出 demo 中规定的限制。

在演示 demo 中,需要 scaleY(-1) 并且 transform-origin 在 ::after
伪类的底边上。

澳门新浦京娱乐游戏 11

使用scaleY(-1)和一个合适的
transform-origin 来镜像元素

 

我们把这些设置添加到代码中,并且用 element() 函数把 ::after
伪类的背景设置为 #loader

CSS

.loader::after {
  transform-origin: 0 100%;
  transform: scaleY(-1);
  background: -moz-element(#loader);
}

注意:由于特别的原因我们使用 .loaderr
作为选择器并且由于 element() 函数参数的需要我们设置它的 id
为 #loader

添加以上代码后的效果如下所示(只在 Firefox 浏览器中有效)

See the Pen bar loader 2.2.2 -moz-element() for reflecting
pseudo
by Ana Tudor (@thebabydino) on
CodePen.

对于使用其他浏览器阅读这篇文章的朋友,以下是截图

澳门新浦京娱乐游戏 12

在Firefox中使用
element() 制作的反射效果

 

  1. Shift.css

逼真的Easing Curves

制作动画的另一个重要组成部分是看上去要逼真,所以要为动画的每个部分仔细选择(或创建)Easing
Curves。最为生动的Easing
Curves是“正弦曲线”——换句话说,是平滑起伏的Easing
Curves。这样一来,自然动作就不会僵硬地起动或停止,animation-timing-function应该能反映出来。

对于狐狸和哈士奇,我使用cubic-bezier(0.645, 0.045, 0.355,
1)(在这里预览)。此曲线(见下文)开始略快,然后平稳地停住。当然,最好试验曲线以找到最适合动画的那种。

澳门新浦京娱乐游戏 13

最后:在Chrome中,你可以直观地检查所有排序的动画,以确保它们在正确的时间发生。你只需打开控制台,单击Style选项卡,然后单击播放按钮即可:

希望本教程可以帮助启发你创建更多的序列CSS动物动画!

用 mask 制作渐变

我们使用和 WebKit 情况下一样的方法给反射添加渐变。在 WebKit
的情况下,遮罩是 -webkit-box-reflect 属性的一部分。而现在,我们讨论
CSS 的 mask 属性,它需要引用 SVG 作为值。

CSS

mask: url(#fader);

 #fader 元素是一个包含长方形的SVG mask 元素。

SVG

<svg>
  <mask id='fader' maskContentUnits='objectBoundingBox'>
    <rect width='1' height='1'/>
  </mask>
</svg>

我们可以用 Haml 模板压缩一下

Haml

%svg
  %mask#fader(maskContentUnits='objectBoundingBox')
    %rect(width='1' height='1')

但是,如果我们加上以上代码,我们的反射倒影消失了,在 Firefox 中查看如下
demo

See the Pen bar loader 2.2.3 adding a SVG
mask
by Ana Tudor (@thebabydino) on
CodePen.

这是因为,默认情况下,SVG 图形会有一个纯黑色的 fill
,完全不透明,但是,我们的
遮罩
默认是有透明度的。因此为了实现反射渐变的效果我们需要给长方形一个 fill
(需引入 SVG linearGradient

Haml

%rect(width='1' height='1' fill='url(#grad)')

一个 SVG linearGradient 由定义的两个点 x1 , y1 , x2 , y2
组成。 x1 和 y1 是渐变线的起始点(0%)坐标,而 x2 和 y2
是这条线的终点(100%)坐标。如果这些数值是空的,默认设为 0% , 0%
, 100% , 0% 。这些数值描绘了从指定元素(由于 gradientUnits
的默认值是 objectBoundingBox)的左上( 0% 0% )到右上( 100% 0%
)的一条线。这意味着,默认情况下,渐变是从左到右。

但是在我们的例子中,我们希望渐变从 top 到 bottom ,所以我们将 x2
的值从 100% 设置为 0% 并且将 y2 的值从 0% 设置为 100%
。这使得指定元素的渐变向量从左上角( 0% 0% )指向左下角( 0% 100%
)。

Haml

%linearGradient#grad(x2='0%' y2='100%')

在 linearGradient 元素之内,我们至少需要两个 stop
元素。其中有三个特定的属性, 偏移值 offset , 颜色断点 stop-color
透明度断点 stop-color

  1.  偏移值 offset:可以使用百分比 %,通常在 0% 到 100% 之间,和
    CSS 渐变一样。也可以使用数值,通常是从 0 到 1 。
  2.  颜色断点 stop-color:理论上可以使用关键字 hexrgb()
    , rgba() , hsl() 或者 hsla() ,实际上 Safari
    不支持半透明数值
    ,因此如果想设置渐变为半透明,我们需要依赖第三个属性。
  3.  透明度断点 stop-opacity:可以设置从 0(完全透明)到
    1(完全不透明)的数值。

我们需要记住应用渐变遮罩的伪类已经通过 scaleY(-1)
属性镜像过来了,这意味着渐变遮罩的底部在视觉上是顶端。因此渐变是从顶部(视觉下端)的完全透明到底部(视觉上端)的 .7

因为渐变是从上到下,所以第一个断点完全透明的。

Haml

%linearGradient#grad(x2='0%' y2='100%')
  %stop(offset='0' stop-color='#fff' stop-opacity='0')
  %stop(offset='1' stop-color='#fff' stop-opacity='.7')

添加线性渐变之后,在Firefox中就是我们想要的结果了

澳门新浦京娱乐游戏 14

实时效果如下:

See the Pen bar loader 2.2.4 linearGradient
it
by Ana Tudor (@thebabydino) on
CodePen.

创建定时CSS动画的简单框架。

SVG渐变的问题

在我们的例子中,因为遮罩渐变是垂直的所以看起来很简单。但是如果渐变不是垂直、水平或者从一个角到另一个角怎么办?如果我们想要一个特定角度的渐变怎么办?

SVG中 有一个 gradientTransform 属性,它可以通过指定 x1y1
, x2 ,  y2 来旋转渐变线。有人可能会认为这是制作具有特定角度的 CSS
渐变的简单方法。但是,并没有想象的那么简单!

想一想从金色到深红色渐变的例子。为了看得清楚一点,我们在两者之间 50%
的位置设置一个剧烈的过渡。首先我们将这个渐变的 CSS 角度设置为 0deg
。这意味着渐变会从底部(金色)过渡到顶部(深红色)。创建这个渐变的CSS
如下:

CSS

background-image: linear-gradient(0deg, #e18728 50%, #d14730 0);

如果你还不明白 CSS 线性渐变的工作原理,你可以看一下Patrick
Brosset 做的这个
优秀作品。

我们看到的结果如下:

See the Pen CSS linear-gradient at 0deg with sharp stop at
50% by Ana Tudor
(@thebabydino) on
CodePen.

为了制作 SVG 的渐变,我们设置 y1100%,  y2 为 0% 以及把 x1
和 x2 设置成相同的数值(简单起见设置为
0)。这意味着渐变线从底部垂直上升到顶部。我们同时把断点的偏移值设置为
50%

Jade

linearGradient#g(y1='100%' x2='0%' y2='0%' gradientTransform='rotate(0 .5 .5)')
  stop(offset='50%' stop-color='#e18728')
  stop(offset='50%' stop-color='#d14730')

编辑注:我问 Ana 为什么她现在要使用 Jade 模板。她说:我起初使用 Haml
模板是因为我想避免引入我不需要的循环变量,而之后使用 Jade
模板是因为它允许变量和计算。

这个渐变还没有旋转,因为 gradientTransform 的值是 rotate(0 .5 .5)
。其中后两个数值表示渐变旋转的坐标。其中 0 0 表示左上角, 1 1
表示右下角, .5 .5 表示中心。

实时效果如下:

See the Pen SVG linearGradient bottom to top rotated by 0deg with sharp
stop at 50% by Ana Tudor
(@thebabydino) on
CodePen.

如果我们希望渐变从左到右,在 CSS 渐变中,我们把角度从 0deg 设置为
90deg

CSS

background-image: linear-gradient(90deg, #e18728 50%, #d14730 0);

See the Pen CSS linear-gradient at 90deg with sharp stop at
50% by Ana Tudor
(@thebabydino) on
CodePen.

为了在 SVG 渐变中得到同样的结果,我们将 gradientTransform
的值设置为 rotate(90 .5 .5)

Jade

linearGradient#g(y1='100%' x2='0%' y2='0%' gradientTransform='rotate(90 .5 .5)')
  // same stops as before

See the Pen SVG linearGradient bottom to top rotated by 90deg with
sharp stop at 50% by Ana
Tudor (@thebabydino) on
CodePen.

到目前为止,一切正常。用 SVG 来代替 CSS
渐变并没有遇到太多问题。让我们尝试一下其他的角度。在下面的可交互 demo
中,左侧是一个 CSS 渐变,右边是一个SVG
渐变。紫色的线是渐变线,它与金色和深红色的交界线是垂直的。拖拽滑块可以同时改变
CSS 和 SVG 的渐变角度。我们会看到一些错误:有些数值不是 90deg 的倍数。

See the Pen CSS vs. SVG gradient, same angle (interactive,
responsive) by Ana Tudor
(@thebabydino) on
CodePen.

如以上 demo 所示,有些数值不是 90deg
的倍数,我们无法得到相同的结果。只有当我们设置渐变的元素是正方形时结果是相同的。这意味着我们可以给一个更大的正方形元素设置渐变,然后裁剪成实际的形状。然而做这些工作会让 element()
和 mask 来创建渐变倒影的方法更加复杂。

澳门新浦京娱乐游戏 15

Edge:可以全用SVG吗?

令人遗憾的是,以上提到的两种方法在 Edge 中都没有用。因此既能在 Edge
中运行又无需手动复制每个竖条的仅有的方法就是,放下前面的工作重新制作 SVG
加载器。这中方法具有跨浏览器的优势。

总的来说,我们创建一个带有 viewBox 的 SVG 元素,以便把 0 0
点放在中间。我们定义一个竖条,它的底边在 x 轴上,左边在 y
轴上。然后我们在 #loader 群组中根据需要复制(通过 SVG use
元素)多次。我们如之前一样放置这些竖条的位置。

Jade

- var bar_w = 125, bar_h = 5 * bar_w;
- var n = 10;
- var vb_w = n * bar_w;
- var vb_h = 2 * bar_h;
- var vb_x = -.5 * vb_w, vb_y = -.5 * vb_h;

svg(viewBox=[vb_x, vb_y, vb_w, vb_h].join(' '))
  defs
    rect#bar(y=-bar_h width=bar_w height=bar_h)

  g#loader
    - for(var i = 0; i < n; i++) {
      - var x = (i - .5 * n) * bar_w;
      use(xlink:href='#bar' x=x)
    - }

以上代码的效果如下:

See the Pen bar loader 2.3.1 creating and positioning SVG
bars
by Ana Tudor (@thebabydino) on
CodePen.

现在我们已经创建了所有竖条,我们想把 svg
元素的位置调整的更准确而且我们使用 flexbox
属性。同时我们也和之前一样给竖条添加渐变色。我们用Sass做这些事情:

SCSS

$n: 10;
$c: #63a6c1 #1e3f57;
$bar-w: 1.25em;
$bar-h: 5 * $bar-w;
$loader-w: $n * $bar-w;
$loader-h: 2 * $bar-h;

body {
  display: flex;
  justify-content: center;
  margin: 0;
  height: 100vh;
}

svg {
  align-self: center;
  width: $loader-w; height: $loader-h;
}

@for $i from 0 to $n {
  $args: append($c, $i * 100%/($n - 1));

  [id='loader'] use:nth-child(#{$i + 1}) {
    fill: mix($args...);
  }
}

添加以上代码后的效果如下:

See the Pen bar loader 2.3.2 sizing + positioning the SVG & shading the
bars
by Ana Tudor (@thebabydino) on
CodePen.

复制 #loader 群组(再次使用 use 元素)。通过 scale(1 -1)
方法镜像克隆体并且给它添加一个遮罩,和我们之前给伪类元素设置的一样。默认情况下,SVG
元素相对于 SVG 画布的 0 0
点缩放,这个点正好位于loader
元素的底边上,可以很完美的将 loader
元素镜像过来,我们不用设置 transform-origin

Jade/SVG

use(xlink:href='#loader' transform='scale(1 -1)')

使用 transform 属性代替CSS变换,因为 CSS 变换在 Edge 中不支持。

现在我们有了反射倒影,如下所示:

See the Pen bar loader 2.3.3 getting the
reflection
by Ana Tudor (@thebabydino) on
CodePen.

最后一步就是用 mask
给反射添加渐变。它的方法及代码和之前都是一样的,我们不再赘述。所有的代码都在下面的
Pen 中

See the Pen bar loader 2.3.4 fading the
reflection
by Ana Tudor (@thebabydino) on
CodePen.

  1. MOTION
    UI

动画

原始案例中的 CSS 动画很简单,就是用3D方式旋转竖条:

CSS

@keyframes bar {
  0% {
  transform: rotate(-.5turn) rotateX(-1turn);
  }
  75%, 100% { transform: none; }
}

所有的竖条都是同样的动画:

CSS

animation: bar 3s cubic-bezier(.81, .04, .4, .7) infinite;

我们只是给循环的竖条添加了不同的延迟时间。

SCSS

animation-delay: $i*50ms;

因为我们希望旋转的竖条具有3D效果,所有我们给 loader
元素添加一个 perspective 属性

但是使用 -webkit-box-reflect 方法后和预期的一样只能在 WebKit
浏览器中执行。

澳门新浦京娱乐游戏 16

在Chrome浏览器中使用 -webkit-box-reflect
属性后的最终结果

我们同时添加了一张背景图片来看一下它的表现效果。只能在 WebKit
浏览器中预览的效果如下:

See the Pen bar loader 3.1 animating the
bars
by Ana Tudor (@thebabydino) on
CodePen.

我们也尝试在 Firefox 中执行动画。但是,如果我们把动画添加到之前在
Firefox 中运行良好的代码中,好像出现了一些问题。

澳门新浦京娱乐游戏 17

在Firefox中使用element()和mask方法做的动画雏形

 

这里出现了一些问题,下面的demo可以在Firefox中实时检测:

See the Pen bar loader 3.2.1 adding
animation
by Ana Tudor (@thebabydino) on
CodePen.

第一个问题就是反射在伪类的边界处被切断。我们可以通过增加 loader
元素的尺寸来修复这一问题(伪类元素不受影响):

SCSS

$loader-w: ($n + 1) * $bar-w + $bar-h;

但是我们对于其余的两个问题就束手无策了。当竖条进行3D旋转时,反射无法平滑的渲染更新;以及 perspective
属性导致了竖条的消失。

澳门新浦京娱乐游戏 18澳门新浦京娱乐游戏 19

 添加perspective属性的结果              
                                  没有添加perspective属性的结果

以下是实时的显示结果:

See the Pen bar loader 3.2.2
tweaks
by Ana Tudor (@thebabydino) on
CodePen.

全部都用 SVG 的方案怎么样?很不幸,上面的例子中,我们只用 CSS 的 3D
变化制作动画。在 Edge 中,SVG 元素不支持 CSS
的变换属性,所以我们之前在创建倒影时使用了 SVG 的 transform
属性。但是 transform 属性是严格的 2D 模式,我们只能使用 JavaScript 。

所以就目前来看,想要制作一个兼容所有浏览器并且不用复制每一个竖条的加载动画是不可能了。我们现在能做的就是创建两个
loader 元素,每一个都有相同数量的竖条。

Haml

- 2.times do
  .loader
    - 10.times do 
      .bar

竖条的样式和之前一样,我们使用 scale(-1) 来镜像第二个loader元素。

CSS

.loader:nth-child(2) {
  transform: scaleY(-1);
}

我们添加竖条动画后得到如下结果:

See the Pen bar loader 3.3.1 reflection via
duplication
by Ana Tudor (@thebabydino) on
CodePen.

现在我们需要给反射添加渐变。遗憾的是,我们不能在第二个 loader
元素上使用 mask ,因为它只在跨浏览器的 SVG 元素上有效。Edge
目前还不支持 HTML 元素的遮罩效果,但是你可以给官方提建议。

我们只能在第二个 loader
元素上添加渐变背景。这样一来我们就不能使用图片背景了。渐变背景只在纯色背景或者有限的情况下才有效。我们在第二个
loader 元素的 ::after
上添加渐变背景并且设置的大一点,这样就不会挡住旋转的竖条。

SCSS

$bgc: #eee;
$cover-h: $bar-w + $bar-h;
$cover-w: $n * $bar-w + $cover-h;

html { background: $bgc; }

.loader:nth-child(2)::after {
  margin-left: -.5 * $cover-w;
  width: $cover-w; height: $cover-h;
  background: linear-gradient($bgc $bar-w, rgba($bgc, .3));
  content: '';
}

最终结果如下:

See the Pen bar loader 3.3.2 emulate fading with
cover
by Ana Tudor (@thebabydino) on
CodePen.

用于创建灵活的CSS过渡和动画的SASS库。

最后的思考

我们需要一个更好的跨浏览器解决方案。我相信制作物体的反射并不需要像我们在这个例子中一样复制所有的子元素。为了制作可以放置在图像背景 background
上的渐变反射,我们不能替换成 SVG 的方案(其自身也有很多问题)。

哪一种方案更好? -webkit-box-reflect 还是 element()mask
?我也不知道。我个人喜欢同时使用。

虽然使用:reflection
伪类元素
看上去很合理,但是我曾经确信我不想使用额外的元素制作反射。但是现在有比不用插入额外元素更让我喜欢的事情。使用 element()
可以在不同方向上自由创建多个反射,以及用不同的方式变换反射,比如 3D
旋转或者倾斜。这正是我喜欢它的原因。而且用 SVG
做遮罩意味着我们可以在反射上应用更复杂的遮罩同时获得更酷的效果。

另一方面,能力越强,责任越大。也许你没有时间去接触强大功能背后的复杂细节。有时你只是想要一个简单的方法来获得一个简单的结果。

澳门新浦京娱乐游戏 20

  1. Transformicons

使用SVG和CSS的动画图标、符号、按钮。

澳门新浦京娱乐游戏 21

CSS实用程序和工具

  1. sanitize.css

让浏览器渲染元素一致,并允许您以当前最佳实践的方式,即装即用。

澳门新浦京娱乐游戏 22

  1. CSS Stats

CSS状态统计可视化工具。

澳门新浦京娱乐游戏 23

  1. cssfmt

自动格式化CSS源代码的工具。

澳门新浦京娱乐游戏 24

  1. PurifyCSS

很方便的检测你的应用使用了那些CSS选择器的工具,并创建一个未被使用的CSS的文件。

澳门新浦京娱乐游戏 25

Flexbox工具

  1. Flexbox in 5 Minutes

CSS 的 flexbox属性主要特性的互动之旅。

澳门新浦京娱乐游戏 26

  1. Flexbugs

Flexbox常见问题及狂浏览器解决方案

澳门新浦京娱乐游戏 27

13. cssPlus

基于 Flexbox 的稳健、快速、跨浏览器的布局脚手架。

澳门新浦京娱乐游戏 28

  1. Sketch Flex Layout

允许CSS Flexbox布局的Sketch 插件

澳门新浦京娱乐游戏 29

CSS工具包

  1. CSSGram

重塑Instagram过滤器的微型CSS库。

澳门新浦京娱乐游戏 30

  1. Flickity

创建画廊与轮播图的CSS库。

澳门新浦京娱乐游戏 31

  1. Marx

澳门新浦京娱乐游戏 32

  1. Pushy

使用CSS转换和过渡效果的响应式导航菜单。

澳门新浦京娱乐游戏 33

  1. Rucksack

CSS 工具包

澳门新浦京娱乐游戏 34

  1. Drop

用于创建下拉菜单和其他浮动元素的库。

澳门新浦京娱乐游戏 35

  1. Tufte CSS

使用Edward Tufte的理念展示文章的工具

澳门新浦京娱乐游戏 36

  1. Gradify

CSS渐变占位符图像

澳门新浦京娱乐游戏 37

  1. Stretchy

表单元素大小自动调整

澳门新浦京娱乐游戏 38

  1. CSSketch

开源的Sketch的CSS插件

澳门新浦京娱乐游戏 39

  1. SassyFlags

为你的网站添加旗帜的简单库

澳门新浦京娱乐游戏 40

  1. ai2html

把Illustrator文档转为HTML和CSS的开源工具

澳门新浦京娱乐游戏 41

CSS工具包

27. Crayon.css

CSS颜色变量名与16进制对应列表。

澳门新浦京娱乐游戏 42

响应的网页框架和用户界面工具包

28. Juiced

Flexbox CSS 框架

澳门新浦京娱乐游戏 43

29. Primer

CSS工具包与指南

澳门新浦京娱乐游戏 44

30. Neutron

创建灵化、简洁网页布局的SASS框架。

澳门新浦京娱乐游戏 45

31. Basscss

基本元素类型和不可改变的实用程序的轻量级集合。

澳门新浦京娱乐游戏 46

32. flexible.gs

灵活的响应式栅格布局CSS框架

澳门新浦京娱乐游戏 47

33. Rin

澳门新浦京娱乐游戏 48

34. Wee

用于创建复杂逻辑、响应式的轻量级前端框架。

澳门新浦京娱乐游戏 49

35. Scooter

SCSS框架和UI库

澳门新浦京娱乐游戏 50

36. spaceBase

基于SASS的响应式CSS框架

澳门新浦京娱乐游戏 51

37. Decorator

HTML, CSS, and JavaScrip 前端框架

澳门新浦京娱乐游戏 52

38. Rebar

Sass/Stylus 栅格布局框架

澳门新浦京娱乐游戏 53

39. Concise CSS

使用SASS的轻量级易用框架

澳门新浦京娱乐游戏 54

40. Workbench

加快开发速度的前端样板

澳门新浦京娱乐游戏 55

41. Lost

SCSS 或 Stylus 栅格布局

澳门新浦京娱乐游戏 56

42. minigrid()

只有2KB的零依赖栅格布局

澳门新浦京娱乐游戏 57

材料设计框架

43. Material

HTML5 UI 框架

澳门新浦京娱乐游戏 58

44. LumX

基于 AngularJS & Material Design 的框架

澳门新浦京娱乐游戏 59

45. MUI

轻量级WEB框架

澳门新浦京娱乐游戏 60

基于Web的CSS工具和应用程序

46. CSS Gradient Animator

动态生成gradients的WEB工具

澳门新浦京娱乐游戏 61

47. CIRCULUS.SVG

SVG圆形菜单生成器

澳门新浦京娱乐游戏 62

48. CSS Ruler

澳门新浦京娱乐游戏 63

49. SVGOMG

优化和配置SVGO的WEB应用

澳门新浦京娱乐游戏 64

50. Blend

生成简单漂亮CSS3 gradients的工具

澳门新浦京娱乐游戏 65

51. Filter Blend

CSS的混合模式和过滤器生成器

澳门新浦京娱乐游戏 66

52. SVG Path Builder App

使用GUI快速创建SVG path

澳门新浦京娱乐游戏 67

53. .resizr

测试  CSS media queries 的轻量级应用

澳门新浦京娱乐游戏 68

54. css2sass

把CSS代码转成SASS的应用

澳门新浦京娱乐游戏 69

【编辑推荐】

发表评论

电子邮件地址不会被公开。 必填项已用*标注