「行到水穷处,坐看云起时」,是我很喜欢的一句诗,越是山穷水尽,越是无能为力,越应释怀。
扯远了,今天来讨论运用CSS+SVG画朵云
一些基础知识
box-shadow
属性
box-shadow
允许添加一个或多个阴影。
box-shadow: <offsetX> <offsetY> <blurRadius> <spreadRadius> <color>;
offsetX
和offsetY
分别指定阴影在横轴和纵轴上的位置。
blurRadius
指定模糊量,并描述阴影的锐度或模糊程度。
spreadRadius
处理两个值。正值会增加阴影的大小,而负值会减小阴影的大小。
.cloud {
width: 250px; height: 250px;
margin:20px auto;
background:#fff;
box-shadow: 200px 200px 50px 0px #000;
}
filter
属性和<filter>
元素
filter
(滤镜):CSS属性将模糊或颜色偏移等图形效果应用于元素。滤镜通常用于调整图像,背景和边框的渲染,具体参数可参考-filter
我们用到的是url()
:获取指向SVG过滤器的URI,该 SVG filter 可以嵌入到外部XML文件中。
<filter>
元素 为了定义过滤器,SVG 使用了<filter>
元素。该<filter>
元素使用id
属性来唯一标识,没有调用时不会渲染。
<feDisplacementMap>
和<feTurbulence>
<feDisplacementMap>
:映射置换滤镜,通俗来讲就是改变元素和图形的像素位置的,使用feDisplacementMap
重新映射替换一个新的位置,形成一个新的图形。 因此,feDisplacementMap
滤镜在业界的主流应用是对图形进行形变,扭曲,液化。
映射原理: 引自MDN文档
P'(x,y) ← P( x + scale * (XC(x,y) - 0.5), y + scale * (YC(x,y) - 0.5))
- P'(x,y)指的是转换之后的x, y坐标
- x + scale * (XC(x,y) - 0.5), y + scale * (YC(x,y) - 0.5)指的是具体的转换规则。
- XC(x,y)表示当前x,y坐标像素点其X轴方向上设置的对应通道的计算值,范围是0~1。
- YC(x,y)表示当前x,y坐标像素点其Y轴方向上设置的对应通道的计算值,范围是0~1。
- -0.5是偏移值,因此XC(x,y) - 0.5范围是-0.5~0.5, YC(x,y)-0.5范围也是-0.5~0.5。
- scale表示计算后的偏移值相乘的比例,scale越大,则偏移越大。
用法
<feDisplacementMap in2="" in="" scale="" xChannelSelector="" yChannelSelector="" ```
color-interpolation-filters=""
```/>
- in -原始图形
- in2 -用来映射的图形。它的工作原理与in属性相同。
in
和in2
都表示输入,支持的属性值也都是一样的,固定的属性值关键字SourceGraphic
,SourceAlpha
,BackgroundImage
,BackgroundAlpha
,FillPaint
,StrokePaint
;以及自定义的滤镜的原始引用(取值含义可参考MDN)
「 in
一般取SourceGraphic
就好了,表示使用该filter
元素的图形作为原始图像 」
- scale -就是公式里面的缩放比例,可正可负,默认是
0
。通常使用正数值处理,值越大,偏移越大。 - xChannelSelector -表示X轴坐标使用的是哪个颜色通道进行位置偏移。(R\G\B\A四个通道)
- yChannelSelector -表示Y轴坐标使用的是哪个颜色通道进行位置偏移。
- color-interpolation-filters 表示滤镜对颜色进行计算时候采用的颜色模式类型。分为
linearRGB
(默认值)和sRGB
,sRGB
是我们平常用的RGB颜色。
2.<feTurbulence>
该滤镜利用Perlin噪声函数创建了一个图像。它实现了人造纹理比如说云纹、大理石纹的合成。
<feTurbulence baseFrequency="0.01" numOctaves="1" stitchTiles="stitch" seed="53" type="turbulence"/>
属性:
baseFrequency
表示噪声的基本频率参数,默认值是0,频率越高,噪声越密集numOctaves
倍频的数量,默认值是1,不能是小数,只能是整数,如果是小数会当作默认值1处理。倍频的数量越多,噪声看起来越自然,但是也会带来更多的计算,对性能会产生负面影响seed
伪随机数生成的起始值,改变的是噪声的形状和位置stitchTiles
定义了Perlin噪声在边框处的行为表现,noStitch
(默认值,不平滑)|stitch
(平滑)type
滤镜类型turbulence
(默认值。表示湍流、混乱)|fractalNoise
(分形噪声)
结合这两个属性,我们可以得到这样的效果
<div class="cloud"></div>
<svg width="0" height="0">
<filter id="cloud">
<feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" seed="0" />
<feDisplacementMap in="SourceGraphic" scale="170" />
</filter>
</svg>
.cloud {
width: 250px; height: 250px;
margin:20px auto;
background:#fff;
filter: url(#cloud);
}
PS:这些属性着实晦涩难懂,如果你和我一样初学的话,可以实践一下,分别改变这些属性的参数来理解分别影响了什么,如果想要详细深入了解,推荐大佬博客feDisplacementMap和feTurbulence
经实践:
<feDisplacementMap>
中scale
越大,云会越“碎”,即偏离的越多;
<feTurbulence>
中baseFrequency
越大,噪点越多;numOctaves
越大细节越丰富
真实的云
给云加个圆角,此时云的形状已经出来了
.cloud {
width: 250px; height: 250px;
margin:20px auto;
background:#fff;
filter: url(#cloud);
border-radius: 50%;
}
为了增加模糊的效果,我们把背景颜色去掉而改用阴影实现,云的效果实现
.cloud {
width: 250px; height: 250px;
margin:20px auto;
/*background:#fff;*/
box-shadow: 400px 400px 60px 0px #fff;
filter: url(#cloud);
border-radius: 50%;
position: absolute;
top: -320px;
left: -320px;
}
此时的云缺乏层次,为了更真实一点,我们需要给它增添一点阴影
<div class="bg">
<div class="cloud">
<i class="cloud-basic"></i>
<i class="cloud-mid"></i>
<i class="cloud-shadow"></i>
</div>
<svg width="0" height="0" style="position:absolute;">
<filter id="filter-basic">
<feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" seed="0" />
<feDisplacementMap in="SourceGraphic" scale="170" />
</filter>
<filter id="filter-mid">
<feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" seed="0"/>
<feDisplacementMap in="SourceGraphic" scale="150" />
</filter>
<filter id="filter-shadow">
<feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="2" seed="0"/>
<feDisplacementMap in="SourceGraphic" scale="100" />
</filter>
</svg>
</div>
.bg{
width:900px;
height:600px;
background-color: #203f64;
overflow: hidden;
position: relative;
}
.cloud {
width: 500px; height: 250px;
margin: 3rem auto;
}
.cloud > i {
position: absolute;
width: inherit; height: inherit;
border-radius: 50%;
top: -280px;
left: -320px;
position: absolute;
}
.cloud-basic {
filter: url(#filter-basic);
box-shadow: 300px 300px 30px -20px #fff;
}
.cloud-mid {
filter: url(#filter-mid);
box-shadow: 300px 340px 70px -60px rgba(158, 168, 179, 0.5);
left: -25vw;
}
.cloud-shadow {
filter: url(#filter-shadow);
box-shadow: 300px 370px 60px -100px rgba(0, 0, 0, 0.3);
left: -25vw;
}
换个颜色
~手动分割~
附一张前段时间油画棒涂的云