CSS 滤镜与动态特性知识梳理

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);

由于 blurgrayscale 都是颜色无关操作,这两种顺序肉眼接近;但当涉及 brightnesscontrast 时,顺序差异显著:

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>
相关推荐
掘金一周3 小时前
想换一辆电车,JYM有什么推荐 | 沸点周刊 5.21
前端·人工智能·后端
Nian.Baikal3 小时前
Cesium 3D Tiles 加载与优化实战
前端·cesium
KaMeidebaby4 小时前
卡梅德生物技术快报|噬菌体肽库展示技术构建 Mhp168‑Hsp70 定向随机肽库:流程、质控与数据结果
前端·数据库·其他·百度·新浪微博
lchcy4 小时前
前端实现单点登录(SSO登录)
前端
卷帘依旧4 小时前
SPA下的路由模式详解
前端
环信5 小时前
2026年开发者选择即时通讯厂商应注意的几点
前端
卷帘依旧5 小时前
Generator 全面解析 + async/await 深度对比
前端·javascript
yqcoder5 小时前
数据劫持的双雄:深入解析 Object.defineProperty 与 Proxy
开发语言·前端·javascript
lichenyang4535 小时前
鸿蒙聊天 Demo 练习 03:接入 Next.js 后端接口,实现真机前后端联调
前端
小三金6 小时前
EXPO+RN echarts图表库,以及如何使用
前端·javascript·react.js