CSS 滤镜与动态特性知识梳理
一、CSS 滤镜(filter)
filter 属性对元素及其内容应用图形效果,类似图像处理软件中的滤镜。它作用于元素自身渲染结果,包括背景、边框、文字和子元素。滤镜在合成阶段生效,不影响文档流。
语法
css
/* filter: <函数>(参数) [<函数>(参数)]* ------ 可叠加多个滤镜 */
css
.element {
/* --- 模糊 --- */
filter: blur(5px); /* 高斯模糊,值越大越模糊 */
/* --- 亮度与对比度 --- */
filter: brightness(1.2); /* >1 提亮, <1 变暗, 0 全黑 */
filter: contrast(1.5); /* >1 增强对比, <1 减弱, 默认 1 */
/* --- 灰度与饱和度 --- */
filter: grayscale(0.8); /* 1 完全灰度, 0 原始色 */
filter: saturate(2); /* >1 更饱和, 0 完全去色 */
/* --- 色相与反色 --- */
filter: sepia(0.7); /* 1 完全棕褐色调 */
filter: hue-rotate(90deg); /* 色相旋转角度 */
filter: invert(0.8); /* 1 完全反相 */
/* --- 透明度与阴影 --- */
filter: opacity(0.5); /* 类似 opacity 属性,但 GPU 加速 */
filter: drop-shadow(4px 4px 6px rgba(0,0,0,.3)); /* 投射阴影 */
/* --- 叠加使用 --- */
filter: blur(2px) brightness(0.8) saturate(1.5);
}
各函数功能
| 函数 | 参数范围 | 效果 | 典型场景 |
|---|---|---|---|
blur() |
长度值(0 起) | 高斯模糊 | 背景虚化、毛玻璃的下层模糊 |
brightness() |
百分比或数值(默认 1) | 线性调整亮度 | 暗色模式下的图片减亮 |
contrast() |
百分比或数值(默认 1) | 调整对比度 | 配合 blur 增强文字可读性 |
grayscale() |
0~1 或百分比 | 转为灰度 | 图片 hover 去色效果 |
saturate() |
百分比或数值(默认 1) | 饱和度 | 品牌色强调、hover 增强 |
sepia() |
0~1 或百分比 | 棕褐色调 | 复古照片效果 |
hue-rotate() |
角度值 | 色相旋转 | 交互式颜色变换、彩虹动效 |
invert() |
0~1 或百分比 | 色彩反相 | 暗色模式图标适配 |
opacity() |
0~1 或百分比 | 透明度 | GPU 加速的透明效果 |
drop-shadow() |
与 box-shadow 语法相似 |
投射阴影 |
drop-shadow 与 box-shadow 的核心区别
drop-shadow() 遵循元素实际渲染形状 的轮廓(包括 alpha 通道),而 box-shadow 始终作用于元素的矩形边框盒子。
css
/* 给 PNG 图标加阴影 */
.icon {
filter: drop-shadow(2px 2px 4px rgba(0,0,0,.3));
/* box-shadow 会在 PNG 的矩形边界加阴影,而非图标轮廓 */
}
这意味着:一个带透明区域的 PNG 图片,drop-shadow 会沿着图标自身轮廓投射阴影,而 box-shadow 只会在矩形边界上加一个矩形阴影。同样的差异也体现在三角形(通过 border 技巧生成)、SVG 路径、使用了 clip-path 的元素上。
滤镜叠加顺序
多个滤镜从左到右依次应用,顺序不同结果不同:
css
/* 先模糊再灰度:模糊后变成灰色模糊 */
filter: blur(3px) grayscale(1);
/* 先灰度再模糊:灰色图像再模糊 */
filter: grayscale(1) blur(3px);
由于 blur 和 grayscale 都是颜色无关操作,这两种顺序肉眼接近;但当涉及 brightness 和 contrast 时,顺序差异显著:
css
/* 先对比度再亮度:高对比度区域被提亮更多 */
filter: contrast(1.5) brightness(1.2);
/* 先亮度再对比度:整体亮度提升后再增强对比 */
filter: brightness(1.2) contrast(1.5);
效果展示
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.box {
width: 500px;
height: 600px;
}
.box img {
width: 100%;
filter: blur(2px);
/* filter: saturate(1.5/150%); */
/* filter: grayscale(100%); */
/* filter: hue-rotate(deg); */
}
</style>
</head>
<body>
<div class="box">
<img src="./3.jpg" alt="">
</div>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.box {
width: 500px;
height: 600px;
}
.box img {
width: 100%;
/* filter: blur(2px); */
filter: saturate(1.5/150%);
/* filter: grayscale(100%); */
/* filter: hue-rotate(deg); */
}
</style>
</head>
<body>
<div class="box">
<img src="./3.jpg" alt="">
</div>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.box {
width: 500px;
height: 600px;
}
.box img {
width: 100%;
/* filter: blur(2px); */
/* filter: saturate(1.5/150%); */
filter: grayscale(100%);
/* filter: hue-rotate(deg); */
}
</style>
</head>
<body>
<div class="box">
<img src="./3.jpg" alt="">
</div>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.box {
width: 500px;
height: 600px;
}
.box img {
width: 100%;
/* filter: blur(2px); */
/* filter: saturate(1.5/150%); */
/* filter: grayscale(100%); */
filter: hue-rotate(90deg);
}
</style>
</head>
<body>
<div class="box">
<img src="./3.jpg" alt="">
</div>
</body>
</html>
二、背景滤镜(backdrop-filter)
backdrop-filter 对元素后方区域 (即被该元素覆盖的底层内容)应用滤镜。它与 filter 的关键差异在于作用对象:
filter:作用于元素自身的渲染结果。backdrop-filter:作用于元素背后的区域,即透过该元素看到的下层内容。
使用条件
backdrop-filter 生效需要元素自身具备一定的透明度或半透明背景------否则后方内容被完全遮挡,滤镜效果就无法被看到。
用 rgba 或者bg : transparent;都可。
css
.overlay {
background: rgba(255, 255, 255, .2);
background: transparent;
backdrop-filter: blur(10px);
滤镜函数
backdrop-filter 支持 filter 的所有函数,除了 drop-shadow()。
css
.backdrop {
backdrop-filter: blur(20px) brightness(0.6) saturate(1.8);
}
效果演示
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
height: 3000px;
}
img {
display: block;
margin: 0 auto;
}
.navbar {
position: fixed;
left: 0;
width: 100%;
height: 120px;
/* background-color: pink; */
}
.nav1 {
top: 0;
backdrop-filter: saturate(1.5) blur(28px);
/* 背景半透明 */
background: transparent;
}
.nav2 {
top: 130px;
border-bottom: 1px solid #ccc;
/* 渐变的背景色 */
background-image: radial-gradient(transparent 1px, #fff 1px);
/* 背景缩放 */
background-size: 4px 4px;
/* 高斯模糊效果 */
backdrop-filter: saturate(.5) blur(4px);
}
</style>
</head>
<body>
<div class="navbar nav1"></div>
<div class="navbar nav2"></div>
<img src="./dh.jpg" alt="">
<!-- <img src="./4.png" alt=""> -->
</body>
</html>
三、动画时间线
动画时间线分为两种:滚动时间线和视图时间线。
滚动时间线
滚动时间线将滚动容器的滚动进度映射为动画的播放进度。
要使用时只需:
- 先创建并对元素使用动画。
- 再加上
animation-timeline: scroll();
有了滚动时间线之后,动画仅需保留动画名和时间函数即可。
效果演示
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.navbar {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100px;
background: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
.content {
width: 1000px;
margin: 0 auto;
background-color: #f5f5f5;
}
.scrollbar {
width: 0;
height: 3px;
background: linear-gradient(90deg, skyblue, pink);
animation: move 2s linear forwards;
animation-timeline: scroll();
}
@keyframes move {
from {
width: 0;
}
to {
width: 100%;
}
}
</style>
</head>
<body>
<div class="navbar">
<div class="scrollbar"></div>
</div>
<div class="content">
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
<p>有很多的文字</p>
</div>
</body>
</html>
视图时间线
视图时间线追踪目标元素自身在滚动容器可视区域内的出现、停留和离开过程。适用场景:元素进入视口时的渐显动画。
使用时在动画后加animation-timeline: view();
效果演示
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 3000px;
}
.box {
/* 到顶部固定 */
position: sticky;
top: 50px;
width: 1000px;
height: 500px;
margin: 800px auto 0;
/* background-color: skyblue; */
}
.box p {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 30px;
}
.box .pic1 {
position: absolute;
top: 0;
left: 0;
width: 200px;
}
.box .pic2 {
position: absolute;
right: 0;
bottom: 0;
width: 200px;
}
.box img {
opacity: 0.2;
animation: anmi 1s linear forwards;
/* view 视图时间线的写法 */
animation-timeline: view();
}
@keyframes anmi {
from {
transform: scale(1);
opacity: .2;
}
to {
transform: scale(1.5);
opacity: 1;
}
}
</style>
</head>
<body>
<div class="box">
<p>专业哈苏人像</p>
<img src="./3.jpg" alt="" class="pic1">
<img src="./4.png" alt="" class="pic2">
</div>
</body>
</html>
四、CSS 变量
定义
CSS 变量以 -- 开头,区分大小写。
作用域分为全局变量和局部变量,局部变量对自身和其子元素生效。
css
:root {
/* 全局变量 */
--color-primary: #2563eb;
--color-primary-hover: #1d4ed8;
--spacing-unit: 8px;
--border-radius: 6px;
--shadow-sm: 0 1px 2px rgba(0,0,0,.05);
--shadow-md: 0 4px 6px rgba(0,0,0,.1);
}
var() 函数
css
/* var(--名称, <回退值>) 回退值是可选的 */
.button {
background: var(--color-primary);
padding: var(--spacing-unit) calc(var(--spacing-unit) * 2);
border-radius: var(--border-radius);
box-shadow: var(--shadow-sm);
}
回退值:
当你要调用的 CSS 变量因为各种原因失效时,浏览器就会使用这个回退值,确保页面不会彻底崩掉。
css
.button {
/* 如果 --color-accent 未定义,使用 #333 作为回退 */
background: var(--color-accent, #333);
}
/* 回退值可以嵌套另一个 var() */
.element {
background: var(--color-brand, var(--color-primary, #333));
/* 查找顺序:--color-brand → --color-primary → #333 */
}
五、计算函数 calc()
calc() 允许在属性值中执行基本数学运算,混合不同单位进行实时计算。
基本语法
css
/*
calc(表达式)
运算符:+ - * /
运算符两侧必须有空格(* 和 / 可以例外)
*/
运算符两侧必须要加空格是但乘法和除法可以不加。
支持的运算
css
/* 加减:不同单位混合 */
width: calc(100% - 48px); /* 全宽减 48px */
/* 乘法:至少一个操作数为纯数字 */
font-size: calc(1rem * 1.2);
margin: calc(var(--space-unit) * 3);
/* 除法:除数必须是纯数字 */
width: calc(100% / 3);
line-height: calc(24px / 16); /* 结果 1.5,无单位 */
/* 嵌套 calc ------ 不必要,但可读 */
width: calc(calc(100% - 40px) / 2); /* 合法,但建议直接展开 */
width: calc((100% - 40px) / 2); /* 推荐:用括号分组 */
calc() 与 CSS 变量配合
让变量值动态参与计算:
css
:root {
--sidebar-width: 260px;
--gap: 24px;
}
.main-content {
width: calc(100% - var(--sidebar-width) - var(--gap));
/* 运行时计算:全宽 - 侧边栏宽 - 间距 */
/* 修改变量值 → 计算结果自动更新 */
}
.sidebar {
width: var(--sidebar-width);
}
任何单位类型只要兼容就可以混合计算:
css
.element {
/* 百分比 + px:经典侧边栏布局 */
width: calc(100% - 200px);
/* rem + px:基于根字体大小的调整 */
padding: calc(1rem + 4px);
/* vw + px:视口相关计算 */
font-size: calc(16px + (24 - 16) * ((100vw - 320px) / (1200 - 320)));
/* 流式字体:视口在 320px~1200px 之间时,字号在 16px~24px 之间线性变化 */
液态玻璃按钮
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>液态玻璃圆形按钮</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
text-decoration: none;
transition: 0.25s;
}
body {
overflow-x: hidden;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
/* 保持原有的网格背景不变 */
--color: #E1E1E1;
background-color: #F3F3F3;
background-image: linear-gradient(0deg, transparent 24%, var(--color) 25%, var(--color) 26%, transparent 27%,transparent 74%, var(--color) 75%, var(--color) 76%, transparent 77%,transparent),
linear-gradient(90deg, transparent 24%, var(--color) 25%, var(--color) 26%, transparent 27%,transparent 74%, var(--color) 75%, var(--color) 76%, transparent 77%,transparent);
background-size: 55px 55px;
}
/* 最外层滤镜,增强明暗对比度 */
.fx-layer {
filter: contrast(3);
}
/* 按钮核心样式 */
.box {
--w: 100px;
--h: 100px;
--r: 9999px;
--tr: 25%;
z-index: 500;
position: relative;
width: var(--w);
height: var(--h);
display: flex;
justify-content: center;
align-items: center;
border-radius: var(--r);
border: 1px double rgba(51, 51, 51, 0.08);
/* 制造玻璃厚度的关键内阴影群 */
box-shadow:
inset 2px -2px 1px -1px rgba(255, 255, 255, 0.9),
inset -2px 2px 1px -1px rgba(255, 255, 255, 0.9),
inset 6px -6px 1px -6px rgba(255, 255, 255, 0.55),
inset -6px 6px 1px -6px rgba(255, 255, 255, 0.55),
inset 0 0 2px rgba(0, 0, 0, 0.8),
0 4px 8px rgba(0, 0, 0, 0.2);
background: rgba(255, 255, 255, 0.04);
backdrop-filter: blur(2px);
cursor: pointer;
filter: brightness(0.9);
}
/* 加号 SVG 阴影 */
.box svg {
width: 28px;
filter: drop-shadow(0 25px 3px rgba(102, 102, 102, 0.2));
}
/* 底部模糊暗影 */
.box:before {
content: '';
position: absolute;
z-index: 1;
top: 35%;
left: 50%;
transform: translateX(-50%);
width: calc(var(--w) - 16px);
height: calc(var(--h) - 16px);
border-radius: var(--r);
border: 1px solid rgba(0, 0, 0, 0.9);
filter: blur(8px);
}
/* 顶部光泽渐变 */
.box:after {
z-index: 501;
content: '';
position: absolute;
width: var(--w);
height: var(--h);
border-radius: var(--r);
filter: blur(3px);
background: linear-gradient(
45deg,
rgba(255, 255, 255, 0.8) 0%,
transparent var(--tr),
transparent calc(100% - var(--tr)),
rgba(255, 255, 255, 0.8) 100%
);
}
/* 次级光圈叠加层 */
.box .circle-overlay {
position: absolute;
width: calc(var(--w) - 9px);
height: calc(var(--h) - 9px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: var(--r);
filter: blur(1px);
}
</style>
</head>
<body>
<div class="fx-layer">
<div class="box">
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="28" height="28">
<path d="M426.666667 426.666667H85.546667A85.418667 85.418667 0 0 0 0 512c0 47.445333 38.314667 85.333333 85.546667 85.333333H426.666667v341.12c0 47.274667 38.186667 85.546667 85.333333 85.546667 47.445333 0 85.333333-38.314667 85.333333-85.546667V597.333333h341.12A85.418667 85.418667 0 0 0 1024 512c0-47.445333-38.314667-85.333333-85.546667-85.333333H597.333333V85.546667A85.418667 85.418667 0 0 0 512 0c-47.445333 0-85.333333 38.314667-85.333333 85.546667V426.666667z" fill="#777" p-id="4929"></path>
</svg>
<div class="circle-overlay"></div>
</div>
</div>
</body>
</html>