【译】来,用svg&css给你画一朵真实的云

栏目: CSS · 发布时间: 4年前

内容简介:原文:这是作者最终实现的效果:......哦,不,应该是这张:

原文: Drawing Realistic Clouds with SVG and CSS

这是作者最终实现的效果:

【译】来,用svg&css给你画一朵真实的云

......哦,不,应该是这张:

【译】来,用svg&css给你画一朵真实的云
在线查看效果:cloud demo

正文开始啦~

希腊神话讲述了一个关于宙斯创造云女神涅斐勒的故事。和其他希腊神话一样,这个故事极其怪异并且有点限制级。下面的表述则是一个比较简短且含蓄的版本( 限制级,非战斗人员请撤离 )。

涅斐勒(云神) ,据说是宙斯按照自己美丽妻子的形象创造的。传说有个凡人遇见了涅斐勒,一见钟情爱上了她并且在一起了,后来她们一起睡了一个觉,然后奇怪的事情发生了,一朵云生下了一个半人半马的小孩,传说这就半人马的祖先。

很不可思议对吗?就我个人而言,我搞不懂。但庆幸的是,浏览器中创建云的过程要简单得多,也没有那么不可描述。

【译】来,用svg&css给你画一朵真实的云
这是@袁川画的云demo

最近,我发现开发者 @袁川 已经用代码实现了仿真的云烟。对我来说,在浏览器中实现一直是个神话。

通过简单扫一下这个demo里面的代码,我们可以现象,逼真而又独特的云朵是可以通过使用 cssbox-shadow 和一个包含两个元素的SVG过滤器 <filter> 去实现。

我们想要的仿真效果是通过 feTurbulencefeDisplacementMap 之间的微妙混合来实现的。SVG过滤器功能强大、复杂,并且提供了令人非常兴奋的功能(还包括奥斯卡获奖算法)。然而,在它的底层,它们的复杂性可能有点吓人!

译者:奥斯卡获奖算法,这么牛逼?无知限制了我的想象。

虽然SVG的物理特性超出了本文的范畴,但是在MDN和w3.org上有大量的文档。一个免费的关于 feTurbulencefeDisplacement 非常有用的页面(同时被作为这本惊奇的书的一个章节)

对于本文,我们专注学习如何使用SVG的过滤器实现惊人的效果。我们不需要深入研究其底层的算法,正如艺术家不需要了解分子的结构也能绘出令人惊叹的风景一样。

先从一些基础开始

CSS的 box-shadow 属性有五个值需要搞懂:

box-shadow: <offsetX> <offsetY> <blurRadius> <spreadRadius> <color>;
复制代码

让我们把这些值调高(可能比任何理智的开发人员调得都要高):

#cloud-square {
  background: turquoise;
  box-shadow: 200px 200px 50px 0px #000;
  width: 180px;
  height: 180px;
}

#cloud-circle {
  background: coral;
  border-radius: 50%;
  box-shadow: 200px 200px 50px 0px #000;
  width: 180px;
  height: 180px;
}
复制代码

会得到下面的效果图:

【译】来,用svg&css给你画一朵真实的云

你曾经应该也玩过或者看过影子木偶对吗?像下面这样:

【译】来,用svg&css给你画一朵真实的云

译者:看见这个,想起小时候自己也玩过, 两个拇指叉在一块能摆出鸽子的投影。

就像一只手改变形状可以改变投影一样,我们改变HTML的“源形状”也可以使渲染在浏览器中的投影变形。 box-shadow 复制了原始尺寸和 border-radius 上的“渐变”特性,SVG过滤器则同时应用于元素及其阴影。

<svg width="0" height="0"> 
  <filter id="filter">
    <feTurbulence type="fractalNoise" baseFrequency=".01" numOctaves="10" />
    <feDisplacementMap in="SourceGraphic" scale="10" />
  </filter>
</svg>
复制代码

这是我们目前的SVG代码,它不会被渲染,因为我们还没有定义任何可见的东西。它唯一的目的就是保存我们为 SourceGraphic (也就是我们的 <div> )提供的过滤器。

我们借助SVG过滤器的 ID ,通过添加CSS规则将HTML元素( #cloud-circle )和SVG过滤器进行关联:

#cloud-circle {
  filter: url(#filter);
  box-shadow: 200px 200px 50px 0px #fff;
}
复制代码

嗯!很棒,就是这样

【译】来,用svg&css给你画一朵真实的云
在线查看demo

别急!我们只是了解了皮毛,还有很多好东西要看。

尝试使用feDisplacementMap的scale属性

使用这一属性进行一些非科学试验可以产生显著的效果。现在,我们保持 feTurbulence 的值不变,简单调整 feDisplacementMapscale 属性值。

随着 scale 的增加(以30为增量),我们的源 <div> 变得扭曲,投射的阴影反应出天空中云出现的随机形式。

<feDisplacementMap in="SourceGraphic" scale="180"/>
复制代码
【译】来,用svg&css给你画一朵真实的云
在线查看demo

好了,我们有进展了!让我们稍微改变颜色,以形成更具说服力的云。

body {
  background: linear-gradient(165deg, #527785 0%, #7FB4C7 100%);
}

#cloud-circle {
    width: 180px;
    height: 180px;
    background: #000;
    border-radius: 50%;
    filter: url(#filter);
    box-shadow: 200px 200px 50px 0px #fff;
}
复制代码

现在,我们越来越接近真实的云朵效果了!

【译】来,用svg&css给你画一朵真实的云

修改box-shadow的模糊度

下面一套图片展示了 box-shadow 属性的模糊度作用的效果,这里,我们以10px递增模糊值:

【译】来,用svg&css给你画一朵真实的云
随着模糊值增加,云朵也变得更加柔和。

为了增加一点积云的效果,我们可以稍微扩宽源 <div> 的宽度:

#cloud-circle {
  width: 500px; 
  height: 275px;
  background: #000;
  border-radius: 50%;
  filter: url(#filter);
  box-shadow: 200px 200px 60px 0px #fff;
}
复制代码
【译】来,用svg&css给你画一朵真实的云
很好,我们的源元素开始碍事了

:tired_face:

等等,我们扩宽了源元素的宽度,但它现在遮挡在我们云层(白色阴影)的上方。让我们在更远的位置重新投影,这样我们的云就不会再被源图像遮挡了(你可以想象成把你的手往远离墙的方向移动,这样它就不会挡住你的影子木偶的视线了)。

这点我们通过CSS定位可以很好地实现。 <body> 是父元素,默认是静态定位的,我们给源 <div> 添加绝对定位。最初地,这也会重新定位我们的阴影,因此我们还需要增加阴影和元素之间的距离。

#cloud-circle {
  width: 500px;
  height: 275px;
  background: #000;
  border-radius: 50%;
  filter: url(#filter);
  box-shadow: 400px 400px 60px 0px #fff; /* 增加投影位移 */
  position: absolute;
  top: -320px;
  left: -320px;
}
复制代码

是的,我们已经实现了一个极具说服力的云:这里查看

【译】来,用svg&css给你画一朵真实的云

浏览器上展示的已经是一个相当完美的云了,但我不确定......这片云真的能公正地描述云女神涅斐勒吗?我相信我们还可以做得更好!

通过层次传达深度

这是我们想要的效果:

【译】来,用svg&css给你画一朵真实的云

从这张照片中云层的深度、纹理和丰富性来看,宙斯一定是读过艺术专业的。至少,他一定读过《通用设计法则》,这本书阐述了一个强大而又普通的概念:

照明偏差在深度和自然度的解释中起着重要作用,设计师可以通过多种方式操纵照明偏差,利用明暗区域之间的对比度来改变深度的外观。

这段话给了我们一个提示,我们可以将不同形状、大小和颜色的图层堆叠在一起,可以实现像参考图片中那样具有高保真度的云。我们要做的也只是多次调用SVG过滤器。

【译】来,用svg&css给你画一朵真实的云

使用三个SVG过滤器绘制前中后三朵云:

<svg width="0" height="0">
    <!-- 后层 -->
    <filter id="filter-back">
      <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" />
      <feDisplacementMap  in="SourceGraphic" scale="170" />
    </filter>
    <!-- 中层 -->
    <filter id="filter-mid">
      <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" />
      <feDisplacementMap  in="SourceGraphic" scale="150" />
    </filter>
    <!-- 前层 -->
    <filter id="filter-front">
      <feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" />
      <feDisplacementMap  in="SourceGraphic" scale="100" />
    </filter>
</svg>
复制代码

通过分层的应用,我们有机会去探索 feTurbulence 并认识它的多样性。我们选择了较为平滑的类型: fractalNoise ,对于 numOctaves 的值最高只调到了6。

上面这些意味着什么?我们来看一下 baseFrequency 这个属性,下面几张图片是不同 baseFrequency 值下的效果:

【译】来,用svg&css给你画一朵真实的云
值越低,图像就越圆,越模糊。

从效果看,介于0.005~0.01的值比较符合我们想要的积云效果。

用numOctaves添加细节

增加 numOctaves 值允许我们以更细的粒度去渲染图像,这个过程需要大量的计算,因此需要注意:高值会严重影响性能。

【译】来,用svg&css给你画一朵真实的云
numOctaves的值设置得越高,云的效果就越精细。

幸运的是我们不需要为达到精细的效果而设置太高的值,介于4~5就够了。

最后的效果

查看效果

【译】来,用svg&css给你画一朵真实的云

用seed属性进行无限变形

关于 seed 属性有很多可以说,但就我们的目的而言, seed 的作用可以归结为: 不同的值,不同的形状

柏林噪音函数 使用这个值作为其随机数生成器的起点。选择不包含此属性则将 seed 值默认为0;当包含时,无论我们设置何值,都不需要担心会影响性能。

【译】来,用svg&css给你画一朵真实的云
不同的 seed 值,对应生成不同的形状。

上面的GIF代表了 seed 作用的效果。请记住,每个云都是分层的复合云(虽然我调整了每一层的属性,但我保持了它们的 seed 值一致)。

【译】来,用svg&css给你画一朵真实的云

仔细观察上面这张参考图片,我将3个云层 <div> 堆砌在一个基础的 div 上,通过反复试验不同的 seed 值,最终得到了与图中比较相似的形状。如下图:

【译】来,用svg&css给你画一朵真实的云
在线查看demo

天空的极限

显然,认为我们用 <div> 在浏览器上绘制的云比涅斐勒高级是很荒谬的。

但是,我们能够梳理出CSS和SVG过滤器的神秘感越多,我们就越有能力去创造在视觉上令人惊叹的东西,并且高度保真于雷神的创作。那么,我们可以做进一步的试验了!

在这篇文章中,我们刚刚涉足了一个充满力量和复杂性的知识海洋,SVG过滤器通常看起来复杂地难以理解。

不过,就像A Single Div Project和Smith's绘画技术中的例子一样,有趣和实验性的方法总会给人惊艳的效果。

我希望这篇文章能让你对web上进行摄影写实开发感到兴奋,欢迎下方评论交流你的想法~


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java性能优化权威指南

Java性能优化权威指南

Charlie Hunt、Binu John / 柳飞、陆明刚 / 人民邮电出版社 / 2014-3 / 109.00 元

Java性能优化圣经!Java之父重磅推荐! 本书由曾任职于Oracle/Sun的性能优化专家编写,系统而详细地讲解了性能优化的各个方面,帮助你学习Java虚拟机的基本原理、掌握一些监控Java程序性能的工具,从而快速找到程序中的性能瓶颈,并有效改善程序的运行性能。 Java性能优化的任何问题,都可以从本书中找到答案!一起来看看 《Java性能优化权威指南》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具