跳到主要内容

CSS 滤镜实战:用 filter 把模糊、亮度、投影组合成一行

讲清 CSS filter 的 blur / brightness / contrast / grayscale / drop-shadow 各个函数怎么用,怎么按顺序组合多个滤镜做出毛玻璃和图片效果,以及它对性能的影响。

发布于 作者 李雷
#CSS #filter #滤镜 #前端 #视觉效果

CSS 滤镜实战:用 filter 把模糊、亮度、投影组合成一行

很多人对图片处理的第一反应还是切图、改源文件,或者上 Photoshop。其实在浏览器里,一个 filter 属性就能在不动一个像素源文件的前提下,把照片、卡片、文字调出复古、磨砂、染色、投影这些效果。它跑在 GPU 上,改一个数字就能实时看到结果,这是手工修图给不了的速度。

这篇把 filter 的几个核心函数拆开讲,再说怎么把它们组合成干净的一行 CSS,以及一个绕不开的话题:性能。

filter 的每个函数都在改什么

filter 接受一串函数,每个函数负责一个维度。先记住一个关键区别,它会救你很多次:

  • brightness()contrast()saturate():100% 是中性基线,大于它增强,小于它减弱。brightness(100%) 等于什么都没做。
  • grayscale()sepia()invert()opacity():100% 是最大效果,0% 才是不变。把 grayscale 设成 100% 会得到完全去色的图,而不是轻微效果。
  • blur():接长度单位,blur(0) 是不变,blur(4px) 模糊半径 4 像素。
  • hue-rotate():接角度,把所有色相沿色轮旋转同一个度数,hue-rotate(90deg) 整体偏色。
  • drop-shadow(x y 模糊 颜色):投影,但它跟着元素真实的 alpha 形状走,不是矩形边框。

最后这条很值钱。box-shadow 永远沿着矩形边框盒画影子,而 drop-shadow() 会贴着透明 PNG 的轮廓、渐变文字、SVG 图标的剪影。给一个抠图 logo 加投影,基本只能用 filter: drop-shadow(...)

把多个滤镜组合成一行

filter 的多个函数按从左到右的顺序依次作用,顺序是有意义的。我自己踩过一次:给一张图写成 drop-shadow(...) blur(8px),结果整张图连同投影一起被糊掉,因为 blur 作用在了已经加完投影的结果上。正确写法是视觉调整放前面、投影放最后,让投影从最终成像投出去。

下面是一段我经常用的暖复古缩略图滤镜,直接能贴进 CSS:

.thumb {
  filter: sepia(30%) saturate(130%) contrast(95%) brightness(105%);
}

再看一个禁用 / 加载态的写法,灰度加半透明,一条声明用一个类一开一关:

.is-loading {
  filter: grayscale(100%) opacity(60%);
}

写组合时有个细节容易忽略:停在默认值的通道要省掉。brightness(100%) contrast(100%) 这种是纯废操作,既增加字符又没有任何效果。手写时记得删,或者用 CSS 滤镜生成器 拖滑块,它会自动丢掉所有默认值通道,输出永远是干净的一行,例如 filter: blur(2px) saturate(150%) drop-shadow(0 6px 18px #0a0e1a);

图片效果和毛玻璃,差在一个前缀

复古照片、单色图标换色、loading 态,这些都是 filter 直接能做的图片效果。比如给一套黑色 SVG 图标换成品牌青色,可以组合 invert(100%) 把黑翻成白,再用 saturatehue-rotate 推向青色,不用动任何源文件。

但有一个高频误区:想只模糊面板背后的背景,却用了 filter: blur()filter: blur() 会把元素连同它的所有子元素(包括文字)一起模糊,你的标题会变成一坨。真正的磨砂玻璃要用 backdrop-filter: blur(),它只模糊元素背后透出来的东西,前景文字保持清晰。

实操里我会先用 filter 在卡片上快速试出"多少模糊加多少亮度才像磨砂",比如 blur(4px) brightness(110%) saturate(120%),判断好量,再把同样的数字搬到 backdrop-filter 上。要直接搭带降级方案的完整玻璃面板,用 玻璃拟态生成器 更省事,它把背景模糊、半透明底色、边框高光这些都配好了。

性能:filter 不是免费的

filter 跑在 GPU 上,大部分情况很流畅,但有两类开销要心里有数。

第一,blur() 半径越大越贵。GPU 要对每个像素采样周围一片区域,blur(20px)blur(2px) 重得多,在大面积元素或低端设备上可能掉帧。能用小半径就别堆大半径。

第二,filter 会创建新的层叠上下文和合成层。给一个频繁变化或滚动的元素挂 filter,浏览器可能每帧重新合成。如果只是要透明,用 opacity 属性比 filter: opacity() 便宜,因为前者是单独一步合成,后者会拉起整条 filter 管线。动画里尤其注意:对 filter 做 transition 时,把变化范围控制小一点,别让大模糊跟着动。

一个经验法则:静态展示尽管用,滚动和动画里的 filter 要测真机帧率再决定留不留。

小结

filter 把图片处理搬进了 CSS,一行声明就能做复古、染色、投影、磨砂判断。记住三件事就够用:100% 在不同函数里含义不同,多个滤镜的顺序会影响结果,大半径模糊和动画里的 filter 要留意性能。剩下的微调,拖滑块对着实时预览比脑补参数快得多。


Made by Toolora · Updated 2026-06-13