CSS filter 滤镜属性简介
filter
属性定义了元素(通常是<img>)的可视效果(例如:模糊与饱和度)。 注意: 滤镜通常使用百分比 (如:75%), 当然也可以使用小数来表示 (如:0.75)。
虽然 MDN 上的例子基本都是图片,但 filter 对任何元素都有效——文字、边框、背景、伪元素统统会被处理,因为它作用的是元素渲染完成后的位图,不是某个具体的样式属性。这一点是理解 filter 各种行为的关键。
全部滤镜函数
.demo {
/* 模糊,参数是高斯模糊的标准差,只能用长度单位,不接受百分比 */
filter: blur(5px);
/* 亮度,0 全黑,1 原样,可以大于 1 提亮 */
filter: brightness(0.5);
/* 对比度,0 全灰,1 原样 */
filter: contrast(200%);
/* 阴影,语法同 box-shadow 但不支持 inset 和扩散半径 */
filter: drop-shadow(4px 4px 8px rgba(0, 0, 0, 0.5));
/* 灰度,0 原样,1 完全灰白 */
filter: grayscale(100%);
/* 色相旋转,参数是角度 */
filter: hue-rotate(90deg);
/* 反色 */
filter: invert(100%);
/* 透明度,效果类似 opacity */
filter: opacity(50%);
/* 饱和度,0 等同灰度,大于 1 更艳 */
filter: saturate(300%);
/* 褐色老照片效果 */
filter: sepia(100%);
/* 引用 SVG 里定义的 <filter> */
filter: url(#my-svg-filter);
}
多个函数可以串联,顺序会影响结果,因为它们是流水线式依次作用在上一步的输出上:
/* 先灰度再提亮,和先提亮再灰度结果不同 */
filter: grayscale(1) brightness(1.5);
blur 的两个特殊之处
blur() 的参数不接受百分比,只能是长度值。blur(50%) 是无效声明,整条 filter 会被丢弃。这是它和其他滤镜函数最不一样的地方。
另外模糊会让元素边缘的像素向外扩散,扩散区域采样到的是透明像素,所以直接给一张铺满容器的图加 blur 会看到四边发白/透明。常规做法是把元素放大一点再用 overflow: hidden 裁掉边缘:
.blur-bg {
overflow: hidden;
}
.blur-bg img {
/* 放大 1.1 倍,让模糊的边缘落在可视区外 */
transform: scale(1.1);
filter: blur(10px);
}
filter 会创建包含块和层叠上下文
这是实际开发里最容易被坑的一点:任何非 none 的 filter 值都会让元素成为固定定位元素的包含块,同时创建一个新的层叠上下文。
具体后果有两个:
- 元素内部的
position: fixed子元素会相对这个元素定位,而不是相对视口——固定定位「失效」了。 - 元素内部的
z-index变成局部的,子元素再怎么调z-index都不可能盖到这个元素外面的兄弟节点上。
/* 这个 hover 效果会让内部的 fixed 弹窗定位错乱 */
.card:hover {
filter: brightness(1.1);
}
我排查过一个「弹窗在某个卡片里就跑位」的问题,根因就是祖先节点上挂了个 filter。同样的规则也适用于 transform、perspective、will-change、contain: paint 等属性,filter 只是其中一个触发条件。
filter 与 backdrop-filter
两者名字像但作用对象完全不同:
filter处理元素自己及其子元素的渲染结果。backdrop-filter处理元素背后那一层的内容,元素自身不受影响。毛玻璃效果就靠它。
.glass {
background: rgba(255, 255, 255, 0.2);
/* 背景内容被模糊,卡片里的文字依然清晰 */
backdrop-filter: blur(12px) saturate(180%);
}
backdrop-filter 有个前提:元素自身背景必须半透明或透明,否则背后的内容被挡住了,模糊了也看不见。Safari 上还需要 -webkit-backdrop-filter 前缀(较老版本)。
性能注意
filter 会强制元素进入合成层并逐帧重新做像素处理,blur 尤其昂贵——高斯模糊的开销随半径平方增长。做过渡动画时如果卡顿,两个方向:
/* 把 filter 提前提交给合成器 */
.item {
will-change: filter;
transition: filter 0.3s;
}
或者干脆换思路,用一个预先模糊好的伪元素做 opacity 过渡,把逐帧模糊换成一次性模糊。opacity 和 transform 的动画不需要重绘,比动画化 filter 便宜得多。
兼容性
所有滤镜函数在现代浏览器里都无需前缀。需要注意的只有两点:老版 Safari 需要 -webkit-filter(Safari 9 之前);backdrop-filter 在 Firefox 上到 103 版才默认开启。IE 完全不支持标准 filter(IE 那个 filter: progid:... 是另一套私有语法,和这里讲的没关系)。

还没有留言,来发表第一条吧~