CSS Secret——Visual Effect
各种特殊的阴影
阴影有5个值:
box-shadow: 0 5px 4px -4px black;
浏览器创建阴影的大概过程是这样的:
先创建一个和原有元素大小相同的块,颜色由最后一个值指定。
接下来由前两个值指定左偏移和上偏移。
第三个值来给定模糊的大小,你给了4,就意味着在现在块的边界向外向里分别模糊4。
第四个值用来在现有的块的基础上调整块的大小,给-4相当于在4个方向上都缩小4。
只有一边有的阴影
利用上面这些创建只有一边的阴影就很容易了。假设创建只有下面有的:
使用最后一个值将阴影缩小到正好被元素覆盖,在使用上偏移,将其下面的部分露出来。
box-shadow: 0 5px 4px -4px black;
只有相对的两边有阴影
啊。。。这个只有使用两个阴影才能实现了。。。
box-shadow: 5px 0 5px -5px black,
-5px 0 5px -5px black;
不规则阴影
面对矩形或使用圆角属性创建出来的图形的时候,之前的阴影可以很好的起到作用,但是当有伪元素或透明背景等会使元素外形不规则的情形时,之前的阴影就不那么好用了。
这里有一个新的玩意,叫Filter Effects specification。
这个玩意是从SVG里借鉴来的,但是使用上不需要SVG的知识,简单的函数就好,比如blur()、grayscale()、drop-shadow()。
这里我们要用到的就是drop-shadow(),接收的参数和box-shadow差不多,没有改变大小的那个。
#irregularShadow{
height:100px;
color: deeppink;
border: 10px dashed;
text-shadow: .1em .2em yellow;
-webkit-filter: drop-shadow(.1em .1em .5em rgba(255,255,0,1));
filter: drop-shadow(.05em .05em .1em gray);
}
这个其实是对这个元素中所有不透明的部分应用了阴影,这时如果你使用text-shadow,就会多一层阴影哦。
这个阴影非常灵活,基本就意味着这个元素(包括其伪元素)在光照下哪里会有阴影,这里就会在哪里生成阴影。
色彩渲染图片滤镜
就是在图片上添加滤镜的效果咯。
以前我们使用图片编辑软件来编辑出各种不同效果的图片来达成目的,但这样不仅增加了HTTP请求,也使得维护变得更加困难。
还有一种是通过在图片上面覆盖一层透明的覆盖层,模拟给图片加上滤镜的效果,这样确实可以模拟有限的效果,但是这样做并不能模拟所有的效果。
使用CSS的Filter和Blending可以很好的达到效果。
使用JS的canvas可以将图片转换到画布中,这样可以在画布中获得对所有点的颜色的完全控制,如果你想编写自己的滤镜的算法的话,那这个非常适合,但是如果使用CSS中的Filter和Blending就可以达到的效果,使用这个方法无论是从速度,开销还是我们自己的工作量来说都是不划算的。
Filter
我们可以合并多个filter来达成我们的效果。而且,这个属性还可以使用动画。可以做出炫酷的效果哦。
#filter{
width:200px;
transition: 1s filter, 1s -webkit-filter;
-webkit-filter: sepia() saturate(4) hue-rotate(295deg);
filter: sepia() saturate(4) hue-rotate(295deg);
}
#filter:hover,
#filter:focus {
-webkit-filter: none;
filter: none;
}
Blending
这个就像是PS中的混合,有时filter并不能完全达到我们想要的效果时我们就可以使用这个。
这个东西在控制顶层的图层如何与底层的图层混合,我们将背景色放在背景图片下,再使用混合来混合这两个图层。
#blend{
width:200px;
height:200px;
background-size: cover;
background-position: center;
background-color: hsl(335, 100%, 50%);
background-blend-mode: luminosity;
transition: .5s background-color;
background-image: url("../img/tiger.jpg");
}
#blend:hover {
background-color: transparent;
}
毛玻璃效果
在背景很复杂的情况下,我们需要呈现文字的时候就需要在文字下面一个半透明的底。
但有时半透明的底也还是不够,我们想参照macOS那样将背景高斯模糊一下。
我们当然不能在本元素上进行高斯模糊,这样内容也会被模糊,那么我们就使用伪元素吧。
对于背景元素,我们就简单的设置下背景图片,这里有一点是要注意的,首先一定要创建一个不为auto且不为负的z轴放置上下文,这个一会儿解释。
#blur {
position: relative;
padding:20px;
height:400px;
background: url("../img/tiger.jpg") 0/cover fixed;
z-index: 1;
}
里面放置文字内容的元素放一个半透明的背景,伪元素模糊过的背景将放在这个半透明背景的下面。这里的z轴放置上下文一定要为默认值auto。
#blur .content{
position: relative;
max-width:400px;
margin:0 auto;
border-radius: 20px;
padding:20px;
background: hsla(0,0%,100%,.3);
overflow: hidden;
font: normal 22px/40px serif;
}
伪元素:
#blur .content:before{
content: '';
position: absolute;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
-webkit-filter: blur(20px);
filter: blur(20px);
background: url("../img/tiger.jpg") 0/cover fixed;
z-index: -1;
margin: -30px;
}
伪元素这里要说的比较多。
首先,我们这里是放一个伪装的图片用来模糊,所以这张图片显示的位置一定要保证和大背景位置相同才行,这里使用的是fixed的背景位置,如果你不喜欢使用别的也没问题,能保证位置一致就好。
其次,之前创建的z轴上下文在这里就用到了,我们想要的效果是将被模糊的伪装图片放在伪元素的父元素(在这里就是其生成元素)的透明背景的下面,但是要放在其父元素的父元素(真正背景所在元素)的背景的上面。
z-index: -1会使这个伪元素放到其z轴上下文的背景前,内容下面。在这里#blur创建了z轴上下文,.content因为还是默认值auto,所以没有创建。那么这个伪元素就理所当然的放在了我们想放的地方。
最后,因为模糊在边缘部分是有渐变的,模糊的半径会越来越小直至为0,我们不想要这样的效果,我们想要的是清晰的边界。那么margin: -30px就起到了这个作用,再配合其父元素的overflow:hidden,我们就将这部分渐变隐藏起来了。
折角效果
以前的实现是添加两个伪元素一个用来遮盖元素的一角,一个用来模仿折过来的角。
这样的解决方法不够灵活,有更灵活的嘛?
45度时的方案
首先利用线性渐变创建一个切角的元素。
#folded-corner{
width:200px;
height:200px;
background: #58a; /* Fallback */
background:
linear-gradient(-135deg, transparent 2em, #58a 0);
}
然后我们再用线性渐变创建一个小小的矩形背景,这个矩形的对角线正好与切角的那条边重合,矩形的左下半部分作为折过去的角,右上半部分保持透明就好。
#folded-corner{
width:200px;
height:200px;
background: #58a; /* Fallback */
background:
linear-gradient(-135deg,transparent 50%, rgba(0,0,0,.4) 0) no-repeat 100% 0 / 2em 2em,
linear-gradient(-135deg, transparent 1.5em, #58a 0);
}
其他角度
其他角度可就不像45度这么简单咯。。。
首先你得计算好。。。其次这回折过来的角其实应该是反着的,用一个矩形小背景的办法行不通了,得用伪元素了。
我们首先来搞定形状的问题:
我们需要根据切角的角度和大小来计算伪元素的长宽。这里使用scss将会有很大的优势。
@mixin folded-corner($background, $size, $angle: 30deg) {
$x: $size / sin($angle);
$y: $size / cos($angle);
&::before {
content: '';
position: absolute;
top: 0; right: 0;
width: $x; height: $y;
background: linear-gradient(to left bottom,
transparent 50%, rgba(0,0,0,.4) 0)
100% 0 no-repeat;
}
}
这时乍一看是完成了,但你找个真正的纸折一下就会发现,其实并不对。。。
伪元素还需要旋转一定的角度才行。
最后就是这样咯:
@mixin folded-corner($background, $size, $angle: 30deg) {
position: relative;
background: $background; /* Fallback */
background:
linear-gradient($angle - 180deg,
transparent $size, $background 0);
border-radius: .5em;
$x: $size / sin($angle);
$y: $size / cos($angle);
&::before {
content: '';
position: absolute;
top: 0; right: 0;
background: linear-gradient(to left bottom,
transparent 50%, rgba(0,0,0,.2) 0,
rgba(0,0,0,.4)) 100% 0 no-repeat;
width: $y; height: $x;
transform: translateY($y - $x)
rotate(2*$angle - 90deg);
transform-origin: bottom right;
border-bottom-left-radius: inherit;
box-shadow: -.2em .2em .3em -.1em rgba(0,0,0,.2);
}
}