11-技巧篇:阴影与滤镜
juejin_logo copyCreated with Sketch.

前言

阴影与滤镜能让视觉元素看上去更具立体感,阴影为视觉元素提供边界轮廓,滤镜为视觉元素提供多变外观。随着浏览器不断升级,阴影与滤镜的兼容性得到了大大提升。

阴影与滤镜在一般情况下可有可无,它们更多是为了点缀视觉元素而存在。早期的视觉元素为了实现这两种效果,只能使用图像实现,每次维护都需重新切图重新替换,确实麻烦。

如今CSS3为阴影与滤镜提供了相应属性,可通过编码的方式完成这些效果,就无须使用图像实现了。

阴影

阴影效果有三剑客,分别是box-shadowtext-shadowdrop-shadow()box-shadowtext-shadow都是一个属性,而drop-shadow()filter中的滤镜函数。

三者都能产生阴影效果,如何区分它们的场景?其实从字面意思也大概能猜出各自的场景。

  • 想要盒子轮廓产生阴影效果,使用box-shadow
  • 想要文本轮廓产生阴影效果,使用text-shadow
  • 想要透明图像的非透明部分轮廓产生阴影效果,使用fliter:drop-shadow()

三个阴影都具备以下参数,只要认识这些参数,阴影效果随时能上手。

  • OffsetX:水平偏移,阴影的水平位置(必选)
    • Offset:偏移,可用任何长度单位,允许负值,正值向右负值向左(默认0)
  • OffsetY:垂直偏移,阴影的垂直位置(必选)
    • Offset:偏移,可用任何长度单位,允许负值,正值向下负值向上(默认0)
  • Blur:模糊半径,阴影的清晰程度(虚色)
    • Length:长度,可用任何长度单位,值越大边缘越模糊(默认0)
  • Spread:扩展距离,阴影的实体尺寸(实色)
    • Length:长度,可用任何长度单位,允许负值,正值扩大负值缩小(默认0)
  • Color:投影颜色
    • transparent:透明(默认)
    • Keyword:颜色关键字
    • HEX:十六进制色彩模式
    • RGBRGBA:RGB/A色彩模式
    • HSLHSLA:HSL/A色彩模式
  • Position:投影位置
    • outset:阴影显示在外部(默认)
    • inset:阴影显示在内部

上述参数都是box-shadow标配的,而text-shadowdrop-shadow()除了spreadposition,其余全部标配。三个阴影的用法都一样,无特殊区别,以下着重讲述box-shadow的技巧,另外两个属性也可参照该属性适当扩展场景。

box-shadow: offset-x offset-y blur spread color position
text-shadow: offset-x offset-y blur color
filter: drop-shadow(offset-x, offset-y, blur, color)

多重阴影

backgound/mask一样可声明多重效果,使用逗号隔开。先声明的阴影层叠等级最高,会遮挡后面声明的阴影,排列方向由position决定。后面声明的阴影接着上一个排列下去,此时需将blurspread增大,防止被先声明的阴影遮挡。

模拟边框

众所周知,border参与到盒模型的计算与布局中,占据了一定的位置。若希望边框只是一件附属物,不纳入盒模型的计算与布局中,可用outline代替border,而outline的用法与参数与border一样,效果中无太大区别,唯一的区别是outline绘制的轮廓不纳入盒模型的计算与布局中。

box-shadow也能代替border产生边框效果,当然也不纳入盒模型的计算与布局中。

  • 阴影不影响布局,可能会覆盖其他节点及其阴影
  • 阴影不触发滚动条,也不会增加滚动区域大小

blur渲染阴影是虚色,而spread渲染阴影是实色,所以可将其余参数声明为0spread声明为正值,形式为box-shadow:0 0 0 10px #f66。还可结合border-radius让阴影变成圆角。

模拟边框

.shadow {
	border: 1px solid #f66;
	width: 200px;
	height: 200px;
	box-shadow: 0 0 0 10px #f66;
}
.shadow {
	width: 200px;
	height: 200px;
	box-shadow: 0 0 0 10px #f66;
	&.borders {
		margin-left: 100px;
		box-shadow: 0 0 0 10px #f66, 0 0 0 20px #66f;
	}
}
定向阴影

巧妙声明spreadblur的负值可产生定向阴影,这样是为了抵消阴影的扩散。还记得offset-xoffset-y的取值吗,正负决定了偏移方向。当然该技巧只适用于box-shadow

  • offset-x:正值向右负值向左
  • offset-y:正值向下负值向上

根据上述offset-xoffset-y的偏移方向,可确定以下定向阴影的方向相应参数。

  • 向左:offset-x为负,offset-y0
  • 向右:offset-x为正,offset-y0
  • 向上:offset-x0offset-y为负
  • 向下:offset-x0offset-y为正

若想多几个方向产生定向阴影,可结合多重阴影的规则实现。

定向阴影

<ul class="aside-shadow">
	<li class="left"></li>
	<li class="up"></li>
	<li class="left"></li>
	<li class="down"></li>
	<li class="left-up"></li>
	<li class="left-down"></li>
	<li class="right-up"></li>
	<li class="right-down"></li>
</ul>
.aside-shadow {
	display: flex;
	flex-wrap: wrap;
	padding: 20px;
	width: 500px;
	li {
		border: 1px solid #f66;
		width: 100px;
		height: 100px;
		&:not(:nth-child(4n-3)) {
			margin-left: 20px;
		}
		&:nth-child(n+5) {
			margin-top: 20px;
		}
		&.left {
			box-shadow: -10px 0 5px -5px #f66;
		}
		&.right {
			box-shadow: 10px 0 5px -5px #f66;
		}
		&.up {
			box-shadow: 0 -10px 5px -5px #f66;
		}
		&.down {
			box-shadow: 0 10px 5px -5px #f66;
		}
		&.left-up {
			box-shadow: -10px 0 5px -5px #f66, 0 -10px 5px -5px #f66;
		}
		&.left-down {
			box-shadow: -10px 0 5px -5px #f66, 0 10px 5px -5px #f66;
		}
		&.right-up {
			box-shadow: 10px 0 5px -5px #f66, 0 -10px 5px -5px #f66;
		}
		&.right-down {
			box-shadow: 10px 0 5px -5px #f66, 0 10px 5px -5px #f66;
		}
	}
}

彩虹色带

彩虹色带很漂亮,可用box-shadow将其渲染得淋漓尽致。实现原理主要是使用多重阴影,另外也可用第7章的clip-path实现。

彩虹色带

<div class="rainbow-bar bar-1"></div>
<div class="rainbow-bar bar-2"></div>
$rainbow: 0 0 0 8px #f66 inset,
	0 0 0 16px #f90 inset,
	0 0 0 24px #ff3 inset,
	0 0 0 32px #3c9 inset,
	0 0 0 40px #9c3 inset,
	0 0 0 48px #09f inset,
	0 0 0 56px #66f inset;
.rainbow-bar {
	width: 250px;
	&.bar-1 {
		overflow: hidden;
		position: relative;
		height: 125px;
		&::after {
			display: block;
			border-radius: 100%;
			width: 100%;
			height: 200%;
			box-shadow: $rainbow;
			content: "";
		}
	}
	&.bar-2 {
		margin: 125px 0 0 50px;
		border-radius: 100%;
		height: 250px;
		box-shadow: $rainbow;
		clip-path: polygon(0 0, 100% 0, 100% 50%, 0 50%);
	}
}

专栏头像

上述谈到阴影与滤镜能让视觉元素看上去更具立体感,实际上阴影起了最大作用。box-shadowtext-shadow结合起来能让视觉元素更立体更动感。

专栏头像

<div class="article-avatar">
	<p class="left">JowayYoung</p>
	<p class="right">谈前端</p>
</div>
.article-avatar {
	display: flex;
	flex-flow: column wrap;
	justify-content: center;
	align-items: center;
	border-radius: 100%;
	width: 250px;
	height: 250px;
	background-color: #f66;
	box-shadow: 0 0 50px 5px rgba(#000, .2) inset;
	line-height: 50px;
	text-shadow: 5px 5px 10px rgba(#000, .5);
	font-weight: bold;
	font-size: 30px;
	color: #fff;
	.left {
		border-top: 3px solid #fff;
		text-indent: -1em;
	}
	.right {
		text-indent: 2em;
		font-size: 40px;
	}
}

聚焦区域

有无遇到一些迭代新功能的网站,进去时会有一些导航提示,告诉你网站更新了哪些内容。

该导航提示通常都是一个矩形区域定位在更新内容上方,区域内部透明,凸显更新内容,而区域外部带上一层蒙层,遮盖其他内容。当然该效果可用box-shadow实现,还记得阴影可调制各种透明颜色吗?将spread延长到9999px足以覆盖整个网站了。

聚焦区域

<div class="img-cliper">
	<img src="https://jowayyoung.github.io/static/img/code/icss/gz.jpg">
	<i></i>
</div>
.img-cliper {
	overflow: hidden;
	position: relative;
	img {
		width: 400px;
	}
	i {
		position: absolute;
		left: 50px;
		top: 30px;
		border-radius: 100%;
		width: 100px;
		height: 50px;
		box-shadow: 0 0 0 9999px rgba(#000, .5);
	}
}

滤镜

玩过Photoshop的同学都知道,其内置的强大滤镜能让图像焕然一新。曾经只能切图完成这些图像滤镜效果,如今可用CSS3提供的filter完成这些滤镜效果了。

以前每次修改网页滤镜效果都需重新切图,再换上新的图像,使用filter就能免去这些烦恼。不妨看看filter提供的那些滤镜函数吧。

filter包括十个函数,每个函数包括以下参数。

  • blur():模糊
    • Length:长度,可用任何长度单位,值为0显示原图,值越大越模糊
  • brightness():亮度
    • Percentage:百分比,可用0~1代替,值为0显示全黑,值为100%显示原图
  • contrast():对比度
    • Percentage:百分比,可用0~1代替,值为0显示全黑,值为100%显示原图
  • drop-shadow():阴影
    • 参考上述阴影
  • grayscale():灰度
    • Percentage:百分比,可用0~1代替,值为0显示原图,值为100%显示全灰
  • hue-rotate():色相旋转
    • Angle:角度,值为0显示原图,值为0~360deg减弱原图色彩,值超过360deg则相当绕N圈再计算剩余的值
  • invert():反相
    • Percentage:百分比,可用0~1代替,值为0显示原图,值为100%完全反转原图色彩
  • opacity():透明度
    • Percentage:百分比,可用0~1代替,值为0显示透明,值为100%显示原图
  • saturate():饱和度
    • Percentage:百分比,可用0~1代替,值为0完全不饱和原图,值为100%显示原图
  • sepia():褐色
    • Percentage:百分比,可用0~1代替,值为0显示原图,值为100%显示褐

滤镜更偏向设计方向,若学过设计的同学可能对滤镜的调制会更顺手。filter怎样用?问设计师索取图像在图像软件的滤镜参数声明filter即可。当然filterbackgound/mask一样可声明多重效果。

滤镜调制

其实filter上手不难,难就难在每个人的审美不同,很难做出较唯美的滤镜效果,更多是看个人在设计方向的进修程度。

无设计基础的同学,可参照CSSgram官网源码学习滤镜调制,其源码通过filter复现了Instagram网站内置的图像滤镜效果。

Instagram滤镜

悼念模式

一行代码全站进入悼念模式,把<html>替换成<html style="filter:grayscale(1)">,简单粗暴。当然核心代码是filter:grayscale(1),意思是把当前节点及其后代节点声明为100%的灰度模式。

悼念模式

<img class="mourning-mode" src="https://jowayyoung.github.io/static/img/icss/car.jpg">
.mourning-mode {
	width: 400px;
	filter: grayscale(100%);
}

可能有些同学在使用上述技巧时会发现声明position:absolute/fixed的节点会出现异常,导致某些布局排版错乱。因为节点声明不为nonefilter时,若自身及其后代节点声明了position:absolute/fixed,则为其创建一个新容器,使得这些定位节点其定位基准相对新容器进行。

相信遇到上述问题的同学,都是在<body>或某个主要节点中声明filter吧。根据上述原理,把filter:grayscale(1)声明到<html>中。

因为不管如何设置定位基准,<html>都是最顶层的容器,即使创建了新的定位基准节点,也不会对自身及其后代节点产生不符合预期的影响。

这也就是为何开头直接把<html>替换为<html style="filter:grayscale(1)">,当然我贴出来的示例也是为了讲述声明filter:grayscale(1)后出现的坑,同样原理,也可解决其他因为声明filter而导致布局排版错乱的问题。

留言
Ctrl + Enter
全部评论(6)
南极一块修炼千年的大冰块的头像
删除
高级摸鱼师 @ 🏆 掘金
点赞
1
删除
(作者)
这个使用scss写完编译过的
点赞
回复
lumi41803的头像
删除
web前端开发
滤镜调制那边,那个网站叫CSSGram,写成Cssarm了
1
1
删除
(作者)
修复了
点赞
回复
RainBus的头像
删除
菜🐔
定向阴影里有一处笔误:
向右:offset-x为0,offset-y为正
应该是向下。
点赞
1
删除
(作者)
修正了
点赞
回复