Day22_CSS 函数完全指南:从变量到数学计算的现代样式编程

导读:本文系统讲解 CSS 函数体系,涵盖 CSS 自定义属性(变量)、calc() 数学计算、颜色函数、渐变函数等核心内容。每个知识点均配完整可运行示例,并引用 MDN CSS 函数CSS Custom Properties 规范CSS Values and Units 规范 等权威资料。掌握 CSS 函数将让你的样式表更具可维护性、动态性和计算能力。

目录


零、导读与学习价值

0.1 配套示例覆盖清单

本文完整覆盖以下两个核心模块的知识点与实现要点:

序号 主题 核心技能
1 CSS 变量 :root 定义、var() 引用、作用域与继承
2 数学计算 calc() 四则运算、单位混合、边界值处理
3 固定侧边导航栏 position: fixedclassList.toggle、CSS transition 与变量/theme 配合

0.2 核心名词速查

术语 一句话解释
CSS 自定义属性 -- 开头的自定义属性,通过 var() 函数引用,常称为 CSS 变量
:root 伪类 匹配文档树的根元素(HTML 中是 <html>),常用于定义全局 CSS 变量
calc() 函数 允许在 CSS 中进行数学计算的表达式函数
回退值 var() 函数的第二个参数,当变量未定义时使用的默认值
有效计算值 CSS 属性在应用完所有继承和级联规则后的最终值
@property 规则 CSS Houdini API,注册类型化自定义属性,使变量可参与插值动画
oklch/oklab 感知均匀颜色空间,渐变无"灰色死区",2025 年已成 Baseline Widely Available
env() 函数 读取浏览器环境变量,主要用于 safe-area-inset-* 刘海屏适配
clamp() 函数 约束值在 最小值, 最大值 区间内,实现流式响应式设计
感知均匀色彩空间 颜色空间中任意方向等距离的变化在人眼感知中等幅度,避免渐变发灰

0.3 为什么要学本篇

  • 工程价值:CSS 变量实现主题切换、设计令牌管理,是现代前端工程化的基础能力。
  • 动态能力calc() 突破了 CSS 静态属性的限制,实现响应式布局的精确计算。
  • 性能优势:原生 CSS 函数无需 JavaScript 参与,性能更优且支持 SSR。
  • 框架兼容:与 Less、Sass 等预处理器互补,掌握原生 CSS 函数让你在技术选型时更灵活。

0.4 前置知识

阅读本文前,建议已掌握:

  • CSS 基础语法和选择器(类选择器、ID 选择器、属性选择器)
  • CSS 盒模型(widthpaddingmarginborder
  • CSS 颜色表示法(十六进制、rgb()rgba()、命名颜色)
  • CSS 单位(px%emremvwvh

0.5 建议练习路线

#mermaid-svg-zy9XmbDKkZ8s6VLv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zy9XmbDKkZ8s6VLv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zy9XmbDKkZ8s6VLv .error-icon{fill:#552222;}#mermaid-svg-zy9XmbDKkZ8s6VLv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zy9XmbDKkZ8s6VLv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zy9XmbDKkZ8s6VLv .marker.cross{stroke:#333333;}#mermaid-svg-zy9XmbDKkZ8s6VLv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zy9XmbDKkZ8s6VLv p{margin:0;}#mermaid-svg-zy9XmbDKkZ8s6VLv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zy9XmbDKkZ8s6VLv .cluster-label text{fill:#333;}#mermaid-svg-zy9XmbDKkZ8s6VLv .cluster-label span{color:#333;}#mermaid-svg-zy9XmbDKkZ8s6VLv .cluster-label span p{background-color:transparent;}#mermaid-svg-zy9XmbDKkZ8s6VLv .label text,#mermaid-svg-zy9XmbDKkZ8s6VLv span{fill:#333;color:#333;}#mermaid-svg-zy9XmbDKkZ8s6VLv .node rect,#mermaid-svg-zy9XmbDKkZ8s6VLv .node circle,#mermaid-svg-zy9XmbDKkZ8s6VLv .node ellipse,#mermaid-svg-zy9XmbDKkZ8s6VLv .node polygon,#mermaid-svg-zy9XmbDKkZ8s6VLv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zy9XmbDKkZ8s6VLv .rough-node .label text,#mermaid-svg-zy9XmbDKkZ8s6VLv .node .label text,#mermaid-svg-zy9XmbDKkZ8s6VLv .image-shape .label,#mermaid-svg-zy9XmbDKkZ8s6VLv .icon-shape .label{text-anchor:middle;}#mermaid-svg-zy9XmbDKkZ8s6VLv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zy9XmbDKkZ8s6VLv .rough-node .label,#mermaid-svg-zy9XmbDKkZ8s6VLv .node .label,#mermaid-svg-zy9XmbDKkZ8s6VLv .image-shape .label,#mermaid-svg-zy9XmbDKkZ8s6VLv .icon-shape .label{text-align:center;}#mermaid-svg-zy9XmbDKkZ8s6VLv .node.clickable{cursor:pointer;}#mermaid-svg-zy9XmbDKkZ8s6VLv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zy9XmbDKkZ8s6VLv .arrowheadPath{fill:#333333;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zy9XmbDKkZ8s6VLv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zy9XmbDKkZ8s6VLv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zy9XmbDKkZ8s6VLv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zy9XmbDKkZ8s6VLv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zy9XmbDKkZ8s6VLv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zy9XmbDKkZ8s6VLv .cluster text{fill:#333;}#mermaid-svg-zy9XmbDKkZ8s6VLv .cluster span{color:#333;}#mermaid-svg-zy9XmbDKkZ8s6VLv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zy9XmbDKkZ8s6VLv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zy9XmbDKkZ8s6VLv rect.text{fill:none;stroke-width:0;}#mermaid-svg-zy9XmbDKkZ8s6VLv .icon-shape,#mermaid-svg-zy9XmbDKkZ8s6VLv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zy9XmbDKkZ8s6VLv .icon-shape p,#mermaid-svg-zy9XmbDKkZ8s6VLv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zy9XmbDKkZ8s6VLv .icon-shape .label rect,#mermaid-svg-zy9XmbDKkZ8s6VLv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zy9XmbDKkZ8s6VLv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zy9XmbDKkZ8s6VLv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zy9XmbDKkZ8s6VLv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 01-CSS变量
02-calc计算
综合实战
主题切换系统

【代码注释】学习路线图:从 CSS 变量基础开始,掌握 calc() 数学计算,最后综合实现主题切换系统。每步都基于前一步知识,逐步深入。建议按顺序实践配套示例。

阶段 知识点 本步验收标准
变量基础 CSS 自定义属性与 var() 掌握 :root 定义与 var() 引用
数学计算 calc() 四则运算 掌握 calc() 四则运算与单位处理
综合应用 主题切换系统 实现 CSS 变量与 JS 结合的动态主题
页面实战 固定侧边导航栏 侧栏滑入、scrollTo 回顶、悬停展开标签

0.6 CSS 函数族谱(本节梳理)

已接触过的函数(复习):

复制代码
url()  rgb()  rgba()  hsl()  hsla()
linear-gradient()  radial-gradient()
repeating-linear-gradient()  repeating-radial-gradient()

【代码注释】以上函数在更早章节已用于背景图、文字色与条纹;本章不重复展开语法,只强调与 var/calc 的组合方式。

本章重点(原生新能力):

复制代码
var()   calc()   min()   max()   clamp()

【代码注释】渐变与 rgb/hsl 属于「生成值」类函数;var/calc 属于「级联与计算」类,可改变布局尺寸的解析方式。规范索引见 MDN CSS 函数
#mermaid-svg-pextkMlPwQhMHqil{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pextkMlPwQhMHqil .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pextkMlPwQhMHqil .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pextkMlPwQhMHqil .error-icon{fill:#552222;}#mermaid-svg-pextkMlPwQhMHqil .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pextkMlPwQhMHqil .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pextkMlPwQhMHqil .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pextkMlPwQhMHqil .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pextkMlPwQhMHqil .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pextkMlPwQhMHqil .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pextkMlPwQhMHqil .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pextkMlPwQhMHqil .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pextkMlPwQhMHqil .marker.cross{stroke:#333333;}#mermaid-svg-pextkMlPwQhMHqil svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pextkMlPwQhMHqil p{margin:0;}#mermaid-svg-pextkMlPwQhMHqil .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-pextkMlPwQhMHqil .cluster-label text{fill:#333;}#mermaid-svg-pextkMlPwQhMHqil .cluster-label span{color:#333;}#mermaid-svg-pextkMlPwQhMHqil .cluster-label span p{background-color:transparent;}#mermaid-svg-pextkMlPwQhMHqil .label text,#mermaid-svg-pextkMlPwQhMHqil span{fill:#333;color:#333;}#mermaid-svg-pextkMlPwQhMHqil .node rect,#mermaid-svg-pextkMlPwQhMHqil .node circle,#mermaid-svg-pextkMlPwQhMHqil .node ellipse,#mermaid-svg-pextkMlPwQhMHqil .node polygon,#mermaid-svg-pextkMlPwQhMHqil .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pextkMlPwQhMHqil .rough-node .label text,#mermaid-svg-pextkMlPwQhMHqil .node .label text,#mermaid-svg-pextkMlPwQhMHqil .image-shape .label,#mermaid-svg-pextkMlPwQhMHqil .icon-shape .label{text-anchor:middle;}#mermaid-svg-pextkMlPwQhMHqil .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pextkMlPwQhMHqil .rough-node .label,#mermaid-svg-pextkMlPwQhMHqil .node .label,#mermaid-svg-pextkMlPwQhMHqil .image-shape .label,#mermaid-svg-pextkMlPwQhMHqil .icon-shape .label{text-align:center;}#mermaid-svg-pextkMlPwQhMHqil .node.clickable{cursor:pointer;}#mermaid-svg-pextkMlPwQhMHqil .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pextkMlPwQhMHqil .arrowheadPath{fill:#333333;}#mermaid-svg-pextkMlPwQhMHqil .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pextkMlPwQhMHqil .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pextkMlPwQhMHqil .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pextkMlPwQhMHqil .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pextkMlPwQhMHqil .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pextkMlPwQhMHqil .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pextkMlPwQhMHqil .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pextkMlPwQhMHqil .cluster text{fill:#333;}#mermaid-svg-pextkMlPwQhMHqil .cluster span{color:#333;}#mermaid-svg-pextkMlPwQhMHqil div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pextkMlPwQhMHqil .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pextkMlPwQhMHqil rect.text{fill:none;stroke-width:0;}#mermaid-svg-pextkMlPwQhMHqil .icon-shape,#mermaid-svg-pextkMlPwQhMHqil .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pextkMlPwQhMHqil .icon-shape p,#mermaid-svg-pextkMlPwQhMHqil .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pextkMlPwQhMHqil .icon-shape .label rect,#mermaid-svg-pextkMlPwQhMHqil .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pextkMlPwQhMHqil .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pextkMlPwQhMHqil .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pextkMlPwQhMHqil :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 计算与引用
var 自定义属性
calc 四则运算
min / max / clamp
值生成
url
rgb / hsl / color-mix
linear / radial / conic-gradient

【代码注释】电商详情页中:var(--form-red) 管品牌色,calc(100vh - 顶栏) 管主区域高度,clamp() 可替代部分媒体查询做流式字号。

0.7 数学扩展函数展望

笔记中列出的 pow()sqrt()sin()cos()tan() 属于 CSS Values 4 数学函数,浏览器支持度低于 calc/min/max,日常布局仍以 calc 为主;它们在几何布局、动画轨迹、数据可视化中更有用。

函数 典型用途 示例思路
pow(x, y) 指数缩放 width: calc(pow(2, 3) * 1px) → 8px
sqrt(x) 对角线、圆半径推导 配合 hypot() 求距离
sin() / cos() / tan() 角度驱动的位移 圆形菜单项坐标、波浪形 clip-path
css 复制代码
/* 演示:用 sin 做水平波浪偏移(需支持数学函数的浏览器) */
.wave-item {
  --i: 0;
  transform: translateX(calc(sin(var(--i) * 30deg) * 20px));
}

【代码注释】角度参数需带单位(deg/rad);不支持时整条声明无效,应提供无 transform 的回退布局。生产环境优先用 clip-path: path() 或 SVG,数学函数作渐进增强。

calc 的关系: calc 解决「加减乘除与单位混合」;pow/sqrt/trig 解决「非线性关系」。二者可嵌套:calc(100px + sin(45deg) * 10px)(以浏览器实现为准)。学习路径:先熟练 var + calc + clamp,再按需查 MDN 数学函数兼容性表。


一、CSS 自定义属性(变量)

名词解释

  • CSS 自定义属性(Custom Properties) :以 -- 开头的属性名,用于存储可复用的值
  • var() 函数:用于引用已定义的 CSS 自定义属性
  • 作用域 :CSS 变量的可见范围,定义在 :root 中为全局作用域
  • 继承性:CSS 变量会从父元素继承到子元素,除非被覆盖

概念与底层原理

CSS 自定义属性由 CSS Custom Properties and Cascading Variables 规范 定义,其核心特性包括:

1. 声明与引用

css 复制代码
:root {
    --primary-color: #e1251b;
    --spacing-unit: 16px;
}

.button {
    background: var(--primary-color);
    padding: var(--spacing-unit);
}

【代码注释】CSS 变量标准声明与引用::root 定义全局变量,所有元素可访问;var() 获取变量值。变量名以 -- 开头,区分大小写。市面应用 :Bootstrap 5 用 --bs-primary 存储主题色,Tailwind 用 --spacing-* 存储间距系统。

根据规范,自定义属性名必须以 -- 开头,区分大小写,允许的字符包括字母、数字、-(除开头外)、以及非 ASCII 字符(如中文)。

2. 作用域与继承

css 复制代码
:root {
    --global-color: blue;
}

.container {
    --local-color: red;
}

.child {
    /* 可访问 --global-color 和 --local-color */
    color: var(--local-color);
}

【代码注释】CSS 变量作用域演示::root 定义的变量全局可访问,.container 定义的变量仅在该元素及后代可见。子元素可访问父级定义的所有变量。市面应用 :组件库组件级变量覆盖(.card { --card-bg: #fff; })。

CSS 变量遵循 CSS 级联规则,特指度由选择器决定。变量在声明处及后代元素中可见,这是 DOM 树的作用域模型。

3. 回退值机制

css 复制代码
.text {
    color: var(--undefined-color, #333);
}

【代码注释】回退值机制:var(--undefined-color, #333)#333 是回退值,当变量未定义时使用。回退值可包含嵌套 var() 调用(var(--a, var(--b, value)))。市面应用 :组件库默认值(color: var(--text-color, #333) 确保即使未定义变量也有合理默认值)。

var() 函数的第二个参数是回退值,当变量未定义或无效时使用。根据规范,回退值可包含嵌套的 var() 调用(var(--name, var(--fallback)))。

4. 与预处理器的区别

特性 CSS 变量 Less/Sass 变量
处理时机 运行时(浏览器) 编译时
作用域 DOM 作用域 词法作用域
动态修改 支持 JS 修改 不支持
继承 支持 DOM 继承 不支持
浏览器兼容 IE 不支持,现代浏览器全支持 编译后纯 CSS,全兼容

根据 CSS Custom Properties 规范,CSS 变量的 inherit 关键字语义明确,可通过 window.getComputedStyle() 读取计算值。

mermaid 图:CSS 变量解析流程

#mermaid-svg-cjVZbOVMYyqQOMLN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cjVZbOVMYyqQOMLN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cjVZbOVMYyqQOMLN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cjVZbOVMYyqQOMLN .error-icon{fill:#552222;}#mermaid-svg-cjVZbOVMYyqQOMLN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cjVZbOVMYyqQOMLN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cjVZbOVMYyqQOMLN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cjVZbOVMYyqQOMLN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cjVZbOVMYyqQOMLN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cjVZbOVMYyqQOMLN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cjVZbOVMYyqQOMLN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cjVZbOVMYyqQOMLN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cjVZbOVMYyqQOMLN .marker.cross{stroke:#333333;}#mermaid-svg-cjVZbOVMYyqQOMLN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cjVZbOVMYyqQOMLN p{margin:0;}#mermaid-svg-cjVZbOVMYyqQOMLN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cjVZbOVMYyqQOMLN .cluster-label text{fill:#333;}#mermaid-svg-cjVZbOVMYyqQOMLN .cluster-label span{color:#333;}#mermaid-svg-cjVZbOVMYyqQOMLN .cluster-label span p{background-color:transparent;}#mermaid-svg-cjVZbOVMYyqQOMLN .label text,#mermaid-svg-cjVZbOVMYyqQOMLN span{fill:#333;color:#333;}#mermaid-svg-cjVZbOVMYyqQOMLN .node rect,#mermaid-svg-cjVZbOVMYyqQOMLN .node circle,#mermaid-svg-cjVZbOVMYyqQOMLN .node ellipse,#mermaid-svg-cjVZbOVMYyqQOMLN .node polygon,#mermaid-svg-cjVZbOVMYyqQOMLN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cjVZbOVMYyqQOMLN .rough-node .label text,#mermaid-svg-cjVZbOVMYyqQOMLN .node .label text,#mermaid-svg-cjVZbOVMYyqQOMLN .image-shape .label,#mermaid-svg-cjVZbOVMYyqQOMLN .icon-shape .label{text-anchor:middle;}#mermaid-svg-cjVZbOVMYyqQOMLN .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cjVZbOVMYyqQOMLN .rough-node .label,#mermaid-svg-cjVZbOVMYyqQOMLN .node .label,#mermaid-svg-cjVZbOVMYyqQOMLN .image-shape .label,#mermaid-svg-cjVZbOVMYyqQOMLN .icon-shape .label{text-align:center;}#mermaid-svg-cjVZbOVMYyqQOMLN .node.clickable{cursor:pointer;}#mermaid-svg-cjVZbOVMYyqQOMLN .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cjVZbOVMYyqQOMLN .arrowheadPath{fill:#333333;}#mermaid-svg-cjVZbOVMYyqQOMLN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cjVZbOVMYyqQOMLN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cjVZbOVMYyqQOMLN .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cjVZbOVMYyqQOMLN .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cjVZbOVMYyqQOMLN .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cjVZbOVMYyqQOMLN .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cjVZbOVMYyqQOMLN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cjVZbOVMYyqQOMLN .cluster text{fill:#333;}#mermaid-svg-cjVZbOVMYyqQOMLN .cluster span{color:#333;}#mermaid-svg-cjVZbOVMYyqQOMLN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cjVZbOVMYyqQOMLN .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cjVZbOVMYyqQOMLN rect.text{fill:none;stroke-width:0;}#mermaid-svg-cjVZbOVMYyqQOMLN .icon-shape,#mermaid-svg-cjVZbOVMYyqQOMLN .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cjVZbOVMYyqQOMLN .icon-shape p,#mermaid-svg-cjVZbOVMYyqQOMLN .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cjVZbOVMYyqQOMLN .icon-shape .label rect,#mermaid-svg-cjVZbOVMYyqQOMLN .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cjVZbOVMYyqQOMLN .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cjVZbOVMYyqQOMLN .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cjVZbOVMYyqQOMLN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是





CSS 解析器
遇到 var--name
在当前元素作用域查找 --name
找到?
使用该值
向父元素继承链查找
找到?
有回退值?
使用回退值
使用无效值 invalid

【代码注释】流程图展示 var() 解析过程:先在当前元素作用域查找,未找到则向父元素继承链查找,最终仍无则使用回退值或标记为无效。理解此流程有助于排查变量不生效问题(作用域错误、名称拼写错误、未在有效继承链内)。

可运行示例(入门):CSS 变量基础用法

将下面内容保存为 demo-css-vars.html,放在本文所在目录后双击打开:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>CSS 变量基础演示</title>
    <style>
        :root {
            /* 定义全局变量 */
            --primary-color: #e1251b;
            --secondary-color: #f90;
            --spacing-base: 20px;
            --border-radius: 8px;
        }

        .card {
            /* 使用变量 */
            background: var(--primary-color);
            padding: var(--spacing-base);
            border-radius: var(--border-radius);
            color: #fff;
            margin: 10px;
            max-width: 400px;
        }

        .card-secondary {
            /* 覆盖 primary-color 变量 */
            --primary-color: var(--secondary-color);
            background: var(--primary-color);
        }

        .card-fallback {
            /* 使用回退值 */
            background: var(--undefined-color, #666);
        }
    </style>
</head>
<body>
    <div class="card">
        <h3>主色卡片</h3>
        <p>使用 --primary-color 变量(#e1251b)</p>
    </div>

    <div class="card card-secondary">
        <h3>次色卡片</h3>
        <p>局部覆盖 --primary-color 为 --secondary-color(#f90)</p>
    </div>

    <div class="card card-fallback">
        <h3>回退值卡片</h3>
        <p>使用未定义变量,回退到 #666</p>
    </div>
</body>
</html>

【代码注释】:root 定义全局变量,所有元素可访问;.card-secondary 局部覆盖 --primary-color,只影响该元素及后代;回退值确保变量未定义时有合理默认值。市面应用:Bootstrap 5、Tailwind CSS 均用 CSS 变量存储设计令牌(颜色、间距、断点)。

可运行示例(变量引用)::rootvar() 直接引用

保存为 demo-var-classroom.html 后打开:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>CSS 变量配套示例</title>
  <style>
    :root {
      --len: 1000px;
      --form-red: #e1251b;
      --btn-red: #f90;
    }
    .item {
      width: var(--len);
      padding: 20px;
      background: var(--form-red);
      border: 6px dashed var(--btn-red);
    }
    .box {
      width: 600px;
      padding: 20px;
      background: var(--form-red);
    }
  </style>
</head>
<body>
  <div class="item">块级元素使用 --len 控制宽度</div>
  <p class="item">同一类名可复用在 p、div 上,变量随 DOM 继承</p>
  <div class="box">局部 width 覆盖 --len 的视觉效果(600px 而非 1000px)</div>
</body>
</html>

【代码注释】变量只在本元素及后代 有效;若在 .box 内写 --len: 600px 可局部覆盖。Less 的 @form-red 编译后消失,而 --form-red 留在计算样式里,可用 JS document.documentElement.style.setProperty('--form-red', '#00f') 动态改色。

JS 动态改主题(加深):

javascript 复制代码
document.documentElement.style.setProperty('--form-red', '#1890ff');
document.documentElement.style.setProperty('--btn-red', '#096dd9');

【代码注释】修改 :root(即 documentElement)上的变量,全站引用 var(--form-red) 的区域同步更新,无需改每条 CSS 规则。配合 classList.toggle('dark') 可切换多套变量表。

可运行示例(补充):跟随系统深色模式

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>prefers-color-scheme</title>
  <style>
    :root {
      --bg: #f5f5f5;
      --text: #333;
      --brand: #e1251b;
    }
    @media (prefers-color-scheme: dark) {
      :root {
        --bg: #1a1a1a;
        --text: #eee;
        --brand: #ff6b6b;
      }
    }
    body {
      margin: 0;
      min-height: 100vh;
      background: var(--bg);
      color: var(--text);
      font-family: sans-serif;
      padding: 24px;
    }
    .btn {
      background: var(--brand);
      color: #fff;
      border: none;
      padding: 10px 20px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <p>切换系统「浅色/深色」外观,本页颜色自动跟随(无需 JS)。</p>
  <button class="btn" type="button">品牌按钮</button>
</body>
</html>

【代码注释】prefers-color-scheme 在媒体查询里覆盖 :root 变量,与 JS setProperty 手动换肤可并存:系统偏好作默认,用户点击再强制 .dark class 覆盖。

可运行示例(实战):电商品牌色系统

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>电商品牌色系统</title>
    <style>
        :root {
            /* 品牌色系 */
            --brand-red: #e1251b;
            --brand-red-dark: #c81623;
            --brand-red-light: #ff6b6b;

            /* 功能色系 */
            --success-color: #52c41a;
            --warning-color: #faad14;
            --error-color: #f5222d;
            --info-color: #1890ff;

            /* 中性色系 */
            --gray-1: #ffffff;
            --gray-2: #fafafa;
            --gray-3: #f5f5f5;
            --gray-6: #666666;
            --gray-9: #000000;

            /* 间距系统 */
            --space-xs: 4px;
            --space-sm: 8px;
            --space-md: 16px;
            --space-lg: 24px;
            --space-xl: 32px;

            /* 字号系统 */
            --font-size-sm: 12px;
            --font-size-base: 14px;
            --font-size-lg: 16px;
            --font-size-xl: 20px;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            color: var(--gray-9);
            background: var(--gray-3);
            margin: 0;
            padding: var(--space-lg);
        }

        .product-card {
            background: var(--gray-1);
            border-radius: var(--space-sm);
            padding: var(--space-md);
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
            max-width: 500px;
            margin: 0 auto;
        }

        .product-header {
            border-bottom: 2px solid var(--brand-red);
            padding-bottom: var(--space-sm);
            margin-bottom: var(--space-md);
        }

        .product-title {
            font-size: var(--font-size-xl);
            color: var(--gray-9);
            margin: 0;
        }

        .product-price {
            font-size: 28px;
            color: var(--brand-red);
            font-weight: bold;
            margin: var(--space-md) 0;
        }

        .product-actions {
            display: flex;
            gap: var(--space-md);
            margin-top: var(--space-lg);
        }

        .btn {
            padding: var(--space-sm) var(--space-lg);
            border-radius: var(--space-xs);
            border: none;
            font-size: var(--font-size-base);
            cursor: pointer;
            transition: all 0.3s;
        }

        .btn-primary {
            background: var(--brand-red);
            color: var(--gray-1);
        }

        .btn-primary:hover {
            background: var(--brand-red-dark);
        }

        .btn-secondary {
            background: var(--gray-3);
            color: var(--gray-6);
        }

        .btn-secondary:hover {
            background: var(--gray-2);
        }

        .product-tags {
            display: flex;
            gap: var(--space-sm);
            margin: var(--space-md) 0;
        }

        .tag {
            padding: var(--space-xs) var(--space-sm);
            border-radius: var(--space-xs);
            font-size: var(--font-size-sm);
        }

        .tag-success {
            background: #f6ffed;
            color: var(--success-color);
            border: 1px solid #b7eb8f;
        }

        .tag-warning {
            background: #fffbe6;
            color: var(--warning-color);
            border: 1px solid #ffe58f;
        }
    </style>
</head>
<body>
    <div class="product-card">
        <div class="product-header">
            <h1 class="product-title">Apple iPhone 15 Pro Max</h1>
        </div>

        <div class="product-price">¥9,999</div>

        <div class="product-tags">
            <span class="tag tag-success">正品保障</span>
            <span class="tag tag-warning">限时优惠</span>
        </div>

        <div class="product-actions">
            <button class="btn btn-primary">立即购买</button>
            <button class="btn btn-secondary">加入购物车</button>
        </div>
    </div>
</body>
</html>

【代码注释】本示例展示完整的电商设计令牌系统:品牌色、中性色、间距、字号统一定义在 :root,所有组件引用变量。修改 --brand-red 一处即可全局换肤。市面应用 :京东、淘宝的设计系统均采用此模式,配合 dark 类名实现深色模式。

【实战要点】

  • 经典应用场景:设计令牌系统(品牌色、间距、字号)、主题切换(明/暗模式)、响应式断点、组件库主题定制
  • 常见坑 :变量名拼写错误(--color vs --Color 大小写敏感)、作用域错误(未在继承链内)、循环依赖导致无效值、@property 未注册时变量不参与过渡动画
  • 性能与最佳实践 :将常用变量定义在 :root 减少继承链查找;用语义化命名(--spacing-md 而非 --s1);配合 JavaScript 使用 CSS.registerProperty 实现变量动画;生产环境可配合 PurgeCSS 删除未使用的变量

【本章小结】

特性 说明 应用场景
声明 --name: value 在选择器内定义 :root 全局定义
引用 var(--name, fallback) 获取值 属性值中使用
作用域 DOM 作用域,支持继承 组件级变量覆盖
动态性 可通过 JS 实时修改 主题切换、用户偏好

记忆口诀:"两个横杠开头,var 引用别忘,作用域看 DOM,回退值保平安"

【面试考点】

Q1:CSS 变量与 Less/Sass 变量的本质区别?

A:CSS 变量在运行时 由浏览器解析,可通过 element.style.setProperty 动态修改,支持 DOM 继承;Less/Sass 变量在编译时替换,浏览器看不到变量名,无运行时开销。CSS 变量适合主题切换、SSR 场景;预处理器变量适合复杂计算、嵌套逻辑。追问「性能」时答:CSS 变量解析有轻微开销,但可忽略;预处理器编译后无开销。

Q2:如何实现基于 CSS 变量的主题切换?

A:1)在 :root 定义默认主题变量;2)创建 .dark 等主题类覆盖变量值;3)JS 切换 <html><body> 的 class。根据 CSS Custom Properties 规范,变量继承遵循 DOM 树,切换根元素 class 即可全局生效。配合 prefers-color-scheme 媒体查询可自动跟随系统主题。

Q3:var(--name, fallback) 的回退值何时生效?

A:当变量未定义(--name 不存在或不在有效继承链内)或值为 initial/inherit 等无效时使用。回退值支持嵌套 var()var(--a, var(--b, value))),回退值本身也会被计算。注意:变量定义但值为空时不使用回退值,而是使用空值(等价于不设置该属性)。

Q4:CSS 变量能参与动画吗?

A:默认自定义属性在数值变化时不会 自动插值动画;可用 @property 注册为 <length> / <color> 等类型后,对 transition 友好的属性(如 background-color: var(--x))才能平滑过渡。简单主题切换用 class 换一套变量值即可,不必强行动画每一个 var()

Q5:CSS 变量设为空值 vs initial 有何区别?

A:--x: ;(空值)是合法的,var(--x) 会插入空字符串,属性值可能无效;--x: initial 会使 var(--x) 回退为属性的初始值(相当于未设置)。二者都不触发回退值参数,只有变量未定义 (未声明)时才触发 var(--x, fallback)。区分这三种状态对调试变量很重要。

深化:@property 注册自定义属性

@propertyCSS Houdini Properties and Values API 的核心规则,允许在 CSS 中注册强类型自定义属性,解决普通 CSS 变量无法参与插值动画的根本问题。

为什么普通变量不能动画?

浏览器把未注册的 CSS 变量视为「字符串」,字符串无法插值("#e1251b""#1890ff" 之间不存在中间值),因此 transition 对字符串只有离散跳变,无过渡效果。

@property 解决方案:

css 复制代码
/* 注册 --brand-hue 为角度类型 */
@property --brand-hue {
  syntax: "<angle>";      /* 类型:角度(deg/rad/turn) */
  inherits: true;         /* 是否继承父元素值 */
  initial-value: 0deg;    /* 必填:初始值(syntax 非 * 时必须提供) */
}

:root { --brand-hue: 0deg; }

.theme-btn {
  background: hsl(var(--brand-hue), 80%, 50%);
  transition: --brand-hue 0.6s ease;  /* 现在可以平滑过渡! */
}

.theme-btn.active {
  --brand-hue: 200deg;   /* 从红色(0deg)平滑过渡到蓝色(200deg) */
}

【代码注释】@property 告诉浏览器「--brand-hue 是一个角度值」,浏览器就能在 0deg200deg 之间做逐帧插值。插值计算被 GPU 接管(而不是 JS 主线程),性能更优。syntax: "<angle>" 类型检查防止意外赋值(赋 "red" 时浏览器忽略,回退 initial-value)。市面应用:渐变角度动画、进度条平滑填充、颜色主题切换动画。

@property 实战:渐变进度条动画

css 复制代码
@property --progress {
  syntax: "<percentage>";
  inherits: false;    /* 不继承:每个进度条独立控制 */
  initial-value: 0%;
}

.progress-bar {
  --progress: 0%;
  width: 300px;
  height: 8px;
  background: linear-gradient(
    to right,
    #e1251b var(--progress),   /* 进度填充区 */
    #f3f3f3 var(--progress)    /* 未填充区 */
  );
  border-radius: 4px;
  animation: fill 2s ease forwards;
}

@keyframes fill {
  to { --progress: 75%; }
}

【代码注释】linear-gradient 中的颜色停止点 var(--progress) 本质是字符串替换,但注册为 <percentage> 后,@keyframes 可对它做 0%75% 的平滑插值,实现原生 CSS 进度条动画------无需 JS、无需 width 变化、无需 scaleX()注意@property 须定义在全局作用域,不能嵌套在选择器或媒体查询内。

@property 注意事项:

问题 原因 处理方法
initial-value 缺失 syntax* 时必须提供 补充合理的初始值
嵌套在选择器内 @property 必须在顶层 移到 CSS 文件顶部
动画仍然离散 syntax 写错(如 <color > 多空格) 核对 MDN 语法类型
JS 覆盖 CSS 注册 CSS.registerProperty() 优先于 @property 选一种注册方式

二、calc() 数学计算函数

名词解释

  • calc() 函数 :CSS 数学计算函数,支持 +-*/ 四则运算
  • 计算表达式calc() 内的数学表达式,可混合不同单位
  • 有效计算值:表达式计算后的最终值,用于 CSS 属性赋值
  • 类型检查calc() 要求操作数类型兼容,如长度只能与长度运算

概念与底层原理

calc() 函数由 CSS Values and Units Module Level 4 规范定义,其核心特性包括:

1. 四则运算规则

css 复制代码
/* 加法:两个操作数必须有单位 */
width: calc(100% + 20px);

/* 减法:两个操作数必须有单位 */
width: calc(100% - 40px);

/* 乘法:只能有一个操作数有单位 */
width: calc(10 * 20px);  /* 200px */
width: calc(20px * 10);  /* 200px */

/* 除法:除数(右边操作数)必须无单位 */
width: calc(200px / 2);  /* 100px */

【代码注释】calc() 四则运算的核心规则:加减法要求两边都有单位(不能 calc(100% + 0)),乘除法只能一边有单位。这是 CSS 规范的强制要求,违反会导致整条声明失效。市面应用 :响应式宽度计算(calc(100% - 侧边栏))。

根据规范,+- 要求两侧操作数是相同类型(长度 + 长度、百分比 + 百分比等);* 要求至少一个操作数无单位;/ 要求右操作数无单位。

2. 单位混合计算

css 复制代码
/* 百分比与像素混合 */
width: calc(50% + 100px);

/* 视口单位与像素混合 */
height: calc(100vh - 60px);

/* em 与 px 混合 */
margin: calc(1em + 10px);

【代码注释】calc() 的强大之处在于混合不同单位:%(相对父容器)、px(绝对像素)、vh(视口高度)、em(字号倍数)。浏览器自动转换为统一单位计算。市面应用 :粘性头部偏移(top: calc(100vh + 10px))、响应式间距。

calc() 的强大之处在于混合不同单位 ,这在响应式布局中极为有用。规范要求最终计算结果必须能解析为有效 CSS 值(如 calc(100% + 10px)width 有效,但对 color 无效)。

3. 优先级与嵌套

css 复制代码
/* calc() 内支持括号 */
width: calc((100% - 40px) / 2);

/* 可嵌套 calc() */
width: calc(calc(100% - 20px) / 2);

/* 可与 var() 结合使用 */
width: calc(var(--base-width) + var(--spacing));

【代码注释】calc() 支持标准数学优先级(括号 > 乘除 > 加减),可嵌套使用(编译器会自动合并)。与 CSS 变量结合可实现动态计算(calc(var(--base-width) + var(--spacing)))。市面应用 :网格等分(calc((100% - gap * 2) / 3))。

calc() 支持标准数学优先级(括号 > 乘除 > 加减),嵌套 calc() 会自动合并。与 CSS 变量结合可实现动态计算。

4. 浏览器兼容性

浏览器 支持版本 前缀
Chrome 26+
Firefox 16+
Safari 7+ -webkit-
Edge 12+
IE 10+ 部分支持

现代浏览器全支持,移动端基本无问题。根据 Can I Use,全球支持率超过 98%。

mermaid 图:calc() 计算流程

#mermaid-svg-a6M9LBbVcmbJVwEL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-a6M9LBbVcmbJVwEL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-a6M9LBbVcmbJVwEL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-a6M9LBbVcmbJVwEL .error-icon{fill:#552222;}#mermaid-svg-a6M9LBbVcmbJVwEL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-a6M9LBbVcmbJVwEL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-a6M9LBbVcmbJVwEL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-a6M9LBbVcmbJVwEL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-a6M9LBbVcmbJVwEL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-a6M9LBbVcmbJVwEL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-a6M9LBbVcmbJVwEL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-a6M9LBbVcmbJVwEL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-a6M9LBbVcmbJVwEL .marker.cross{stroke:#333333;}#mermaid-svg-a6M9LBbVcmbJVwEL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-a6M9LBbVcmbJVwEL p{margin:0;}#mermaid-svg-a6M9LBbVcmbJVwEL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-a6M9LBbVcmbJVwEL .cluster-label text{fill:#333;}#mermaid-svg-a6M9LBbVcmbJVwEL .cluster-label span{color:#333;}#mermaid-svg-a6M9LBbVcmbJVwEL .cluster-label span p{background-color:transparent;}#mermaid-svg-a6M9LBbVcmbJVwEL .label text,#mermaid-svg-a6M9LBbVcmbJVwEL span{fill:#333;color:#333;}#mermaid-svg-a6M9LBbVcmbJVwEL .node rect,#mermaid-svg-a6M9LBbVcmbJVwEL .node circle,#mermaid-svg-a6M9LBbVcmbJVwEL .node ellipse,#mermaid-svg-a6M9LBbVcmbJVwEL .node polygon,#mermaid-svg-a6M9LBbVcmbJVwEL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-a6M9LBbVcmbJVwEL .rough-node .label text,#mermaid-svg-a6M9LBbVcmbJVwEL .node .label text,#mermaid-svg-a6M9LBbVcmbJVwEL .image-shape .label,#mermaid-svg-a6M9LBbVcmbJVwEL .icon-shape .label{text-anchor:middle;}#mermaid-svg-a6M9LBbVcmbJVwEL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-a6M9LBbVcmbJVwEL .rough-node .label,#mermaid-svg-a6M9LBbVcmbJVwEL .node .label,#mermaid-svg-a6M9LBbVcmbJVwEL .image-shape .label,#mermaid-svg-a6M9LBbVcmbJVwEL .icon-shape .label{text-align:center;}#mermaid-svg-a6M9LBbVcmbJVwEL .node.clickable{cursor:pointer;}#mermaid-svg-a6M9LBbVcmbJVwEL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-a6M9LBbVcmbJVwEL .arrowheadPath{fill:#333333;}#mermaid-svg-a6M9LBbVcmbJVwEL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-a6M9LBbVcmbJVwEL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-a6M9LBbVcmbJVwEL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a6M9LBbVcmbJVwEL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-a6M9LBbVcmbJVwEL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a6M9LBbVcmbJVwEL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-a6M9LBbVcmbJVwEL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-a6M9LBbVcmbJVwEL .cluster text{fill:#333;}#mermaid-svg-a6M9LBbVcmbJVwEL .cluster span{color:#333;}#mermaid-svg-a6M9LBbVcmbJVwEL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-a6M9LBbVcmbJVwEL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-a6M9LBbVcmbJVwEL rect.text{fill:none;stroke-width:0;}#mermaid-svg-a6M9LBbVcmbJVwEL .icon-shape,#mermaid-svg-a6M9LBbVcmbJVwEL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a6M9LBbVcmbJVwEL .icon-shape p,#mermaid-svg-a6M9LBbVcmbJVwEL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-a6M9LBbVcmbJVwEL .icon-shape .label rect,#mermaid-svg-a6M9LBbVcmbJVwEL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a6M9LBbVcmbJVwEL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-a6M9LBbVcmbJVwEL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-a6M9LBbVcmbJVwEL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否



CSS 解析器遇到 calc
解析表达式字符串
语法是否有效?
丢弃 calc 声明
检查操作数类型
类型是否兼容?
执行数学计算
返回计算结果
赋值给 CSS 属性

【代码注释】流程图展示 calc() 解析与计算过程:先验证语法和类型兼容性,再执行计算。常见错误:calc(50% * 2)(乘法两边都有单位)、calc(100px / 20px)(除数有单位)。理解此流程有助于排查 calc() 不生效问题。

可运行示例(入门):calc() 基础运算

将下面内容保存为 demo-calc-basic.html,放在本文所在目录后双击打开:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>calc 基础运算演示</title>
    <style>
        .container {
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }

        .box {
            margin: 10px 0;
            padding: 20px;
            background: #f5f5f5;
            border: 2px solid #ddd;
        }

        /* 加法:百分比 + 像素 */
        .addition {
            width: calc(100% + 50px);
            background: #ffe6e6;
        }

        /* 减法:百分比 - 像素 */
        .subtraction {
            width: calc(100% - 100px);
            background: #e6f7ff;
        }

        /* 乘法:无单位数 * 像素 */
        .multiplication {
            width: calc(3 * 100px);
            background: #fff7e6;
        }

        /* 除法:像素 / 无单位数 */
        .division {
            width: calc(300px / 3);
            background: #f6ffed;
        }

        /* 混合单位:百分比 + 视口单位 */
        .mixed {
            width: calc(50% + 10vw);
            background: #f9f0ff;
        }

        /* 嵌套 calc */
        .nested {
            width: calc((100% - 40px) / 2);
            background: #fff0f0;
        }
    </style>
</head>
<body>
    <div class="container">
        <h2>calc() 基础运算</h2>

        <div class="box addition">
            <h3>加法:100% + 50px</h3>
            <p>宽度为父容器 100% 加上 50px</p>
        </div>

        <div class="box subtraction">
            <h3>减法:100% - 100px</h3>
            <p>宽度为父容器 100% 减去 100px</p>
        </div>

        <div class="box multiplication">
            <h3>乘法:3 * 100px</h3>
            <p>宽度为 300px(只有一边有单位)</p>
        </div>

        <div class="box division">
            <h3>除法:300px / 3</h3>
            <p>宽度为 100px(除数无单位)</p>
        </div>

        <div class="box mixed">
            <h3>混合单位:50% + 10vw</h3>
            <p>宽度为父容器 50% 加上视口宽度的 10%</p>
        </div>

        <div class="box nested">
            <h3>嵌套:(100% - 40px) / 2</h3>
            <p>宽度为父容器减去 40px 后的一半</p>
        </div>
    </div>
</body>
</html>

【代码注释】本示例覆盖 calc() 所有运算场景。注意:加法减法两边都必须有单位(不能 calc(100% + 0.5)),乘法除法只能一边有单位(calc(10px * 2) 有效,calc(10px * 2px) 无效)。市面应用 :Bootstrap 栅格系统、响应式侧边栏布局均大量使用 calc()

可运行示例(四则运算):calc() 四则运算与 var() 结合

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>calc 配套示例</title>
  <style>
    .box {
      --len: 1000px;
      width: calc(400px + 200px);           /* 加:两边都要有单位 → 600px */
      height: calc(var(--len) - 800px);   /* 减:变量与 px → 200px */
      padding: calc(400px / 10);          /* 除:除数不能带单位 → 40px */
      margin-top: calc(10 * 2px);         /* 乘:仅一边带单位 → 20px */
      width: calc(50% + 100px);           /* 后写覆盖前写,最终宽度为此式 */
      background: #ccc;
      box-sizing: border-box;
    }
  </style>
</head>
<body>
  <div class="box">注意 DevTools 里最终 width 是 calc(50% + 100px),前面的 600px 被覆盖。</div>
</body>
</html>

【代码注释】同一选择器内重复声明 width 时,后一条生效 (层叠顺序),配套示例用多行 width 演示四则运算,最终生效的是 calc(50% + 100px)。生产环境每个属性只保留一条 widthheight 仍由 calc(var(--len) - 800px) 决定。

四则运算口诀(与 MDN calc() 一致):

运算 写法示例 单位规则 无效示例
calc(400px + 200px) 两边都有单位 calc(100% + 0)
calc(var(--len) - 800px) 两边都有单位 calc(100% - 0)
calc(10 * 2px) 仅一边有单位 calc(10px * 2px)
calc(400px / 10) 除数无单位 calc(400px / 10px)

【代码注释】calc 两侧建议留空格:calc(100% - 20px);旧引擎对 calc(100%-20px) 偶发解析失败。0 无单位不能参与加减。

可运行示例(补充):clamp() 流式字号与卡片宽度

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>clamp 演示</title>
  <style>
    :root { --min-fs: 14px; --max-fs: 28px; --fluid: 2.5vw; }
    h1 { font-size: clamp(var(--min-fs), var(--fluid), var(--max-fs)); margin: 24px; }
    p { font-size: clamp(14px, 1.2vw + 12px, 18px); line-height: 1.6; padding: 0 24px; }
    .card {
      width: clamp(280px, 90%, 640px);
      margin: 16px auto;
      padding: clamp(12px, 3vw, 24px);
      background: #fff7e6;
      border: 1px solid #ffd591;
      box-sizing: border-box;
    }
  </style>
</head>
<body>
  <h1>标题随视口在 14px~28px 之间变化</h1>
  <div class="card">
    <p>卡片宽度 clamp(280px, 90%, 640px);内边距 clamp(12px, 3vw, 24px)。</p>
    <p>等价于 max(最小, min(理想, 最大)),一条声明替代多段媒体查询。</p>
  </div>
</body>
</html>

【代码注释】clamp 三参数顺序为「最小、理想、最大」;理想值可用 vw 或带 calc 的表达式。改 :root--min-fs/--max-fs 即可全局调整标题上下限。

可运行示例(实战):响应式圣杯布局

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>响应式圣杯布局</title>
    <style>
        :root {
            --header-height: 60px;
            --footer-height: 50px;
            --sidebar-width: 250px;
            --gap: 20px;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            line-height: 1.6;
        }

        /* 顶部导航 */
        .header {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            height: var(--header-height);
            background: #e1251b;
            color: #fff;
            display: flex;
            align-items: center;
            padding: 0 var(--gap);
            z-index: 100;
        }

        .header h1 {
            font-size: 20px;
        }

        /* 主体容器 */
        .layout {
            display: flex;
            margin-top: var(--header-height);
            min-height: calc(100vh - var(--header-height) - var(--footer-height));
        }

        /* 侧边栏 */
        .sidebar {
            width: var(--sidebar-width);
            background: #f5f5f5;
            padding: var(--gap);
            flex-shrink: 0;
        }

        .sidebar nav ul {
            list-style: none;
        }

        .sidebar nav li {
            margin-bottom: 10px;
        }

        .sidebar nav a {
            display: block;
            padding: 10px 15px;
            color: #333;
            text-decoration: none;
            border-radius: 4px;
            transition: background 0.3s;
        }

        .sidebar nav a:hover {
            background: #e0e0e0;
        }

        /* 主内容区 */
        .main {
            flex: 1;
            padding: var(--gap);
            /* 关键:主内容宽度 = 100% - 侧边栏 - 间隙 */
            width: calc(100% - var(--sidebar-width) - var(--gap) * 2);
        }

        .main article {
            background: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
            margin-bottom: 20px;
        }

        /* 底部 */
        .footer {
            height: var(--footer-height);
            background: #333;
            color: #fff;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        /* 移动端适配 */
        @media (max-width: 768px) {
            .layout {
                flex-direction: column;
            }

            .sidebar {
                width: 100%;
                order: 2;
            }

            .main {
                width: 100%;
                order: 1;
            }
        }
    </style>
</head>
<body>
    <header class="header">
        <h1>响应式圣杯布局</h1>
    </header>

    <div class="layout">
        <aside class="sidebar">
            <nav>
                <h3>导航菜单</h3>
                <ul>
                    <li><a href="#">首页</a></li>
                    <li><a href="#">产品中心</a></li>
                    <li><a href="#">解决方案</a></li>
                    <li><a href="#">关于我们</a></li>
                    <li><a href="#">联系我们</a></li>
                </ul>
            </nav>
        </aside>

        <main class="main">
            <article>
                <h2>使用 calc() 实现精确布局</h2>
                <p>本示例展示如何使用 <code>calc()</code> 函数实现响应式圣杯布局。主内容区的宽度通过计算得出:</p>
                <pre><code>width: calc(100% - var(--sidebar-width) - var(--gap) * 2);</code></pre>
                <p>这种写法比使用百分比或固定像素更灵活,能够自动适应容器宽度变化。</p>
            </article>

            <article>
                <h2>calc() 的优势</h2>
                <ul>
                    <li>混合不同单位:可以同时使用百分比、像素、em、rem、vw、vh 等</li>
                    <li>精确计算:避免手动计算像素值</li>
                    <li>响应式友好:配合媒体查询和 CSS 变量实现动态布局</li>
                    <li>代码可读性:语义化的计算表达式比魔法数字更易理解</li>
                </ul>
            </article>
        </main>
    </div>

    <footer class="footer">
        <p>&copy; 2024 CSS 函数完全指南</p>
    </footer>
</body>
</html>

【代码注释】圣杯布局核心是主内容区宽度计算:calc(100% - 侧边栏宽度 - 间隙)。配合 CSS 变量,修改 --sidebar-width 即可调整布局,无需重新计算。移动端通过媒体查询改变 flex 方向,侧边栏宽度变为 100%市面应用:后台管理系统、文档站、博客系统均采用此布局模式。

【实战要点】

  • 经典应用场景 :响应式布局(calc(100% - 侧边栏))、流体网格(calc((100% - gap) / 列数))、粘性定位偏移(top: calc(100% + 10px))、动态间距
  • 常见坑calc() 内不能有空格外的注释;calc(50% - 0) 无意义(减数需有单位);除数为零时结果为 Infinity(无效值);与 transform 结合时注意变换原点
  • 性能与最佳实践calc() 在样式解析时计算一次,不影响渲染性能;避免在动画属性中使用 calc()(会导致每帧重新计算);用 CSS 变量存储常用值提升可维护性;注意浏览器兼容性(IE10 部分支持)

【本章小结】

运算 语法 单位要求 应用场景
加法 calc(a + b) 两边都有单位 响应式宽度调整
减法 calc(a - b) 两边都有单位 留白、偏移计算
乘法 calc(a * b) 只一边有单位 比例缩放
除法 calc(a / b) 除数无单位 等分、栅格

记忆口诀:"加减都有单位,乘除一边无,括号定优先,变量可嵌入"

【面试考点】

Q1:calc(100% / 3) 为何会出现小数精度问题?

A:JavaScript/IEEE 754 浮点数精度限制导致 100 / 3 = 33.333...,CSS 引擎渲染时可能产生 1px 子像素渲染误差。解决方案:1)用 calc(100% / 3 * 3) 修正最后一列;2)用 Flexbox/Grid 布局替代百分比;3)接受 1px 误差(视觉无影响)。根据 CSS Values 规范,计算结果需截断到有效精度。

Q2:calc() 与 CSS 变量结合的性能如何?

A:calc(var(--x) + var(--y)) 在样式解析时计算一次,后续变量变化需重新计算。频繁修改变量(如动画帧)可能影响性能,建议:1)动画用 transform/opacity;2)变量变化配合 requestAnimationFrame;3)用 will-change 提示浏览器优化。现代浏览器对 calc() 优化良好,一般场景无需担心。

Q3:如何在 calc() 中使用 clamp()min()max() 等现代 CSS 函数?

A:可直接嵌套(width: calc(min(100%, 500px) - 20px)),浏览器按从内到外顺序计算。clamp() 限制值在范围内(clamp(100px, 50%, 500px)),min()/max() 取最小/最大值。这些函数由 CSS Values 4 定义,现代浏览器支持良好。可实现流畅的响应式断点(无需媒体查询)。

Q4:calc() 里能写注释吗?

A:不能。calc(100% - 20px /* 留白 */) 会使整条声明无效。注释只能写在属性行外;复杂式子用 CSS 变量拆开:--offset: 20px; width: calc(100% - var(--offset));

Q5:calc() 中如何避免除以零?

A:CSS 规范规定 calc(10px / 0) 结果为 infinity(或 -infinity),该值会导致属性无效(如 width: infinity 将被忽略)。解决方法:确保除数为变量时提供合理范围的初始值,或在 JS 中设置变量前做防零检查:if (divisor !== 0) element.style.setProperty('--divisor', divisor)

深化:CSS Values 4 新数学函数 round()/mod()/rem()

CSS Values and Units Level 4calc 体系之上引入了更多数学函数,Chrome 109+/Firefox 118+/Safari 15.4+ 已支持:

round() --- 按步长舍入

css 复制代码
/* round(策略, 值, 步长) */
.pixel-snapped {
  /* 将宽度舍入到最近的 10px 整数倍 */
  width: round(nearest, 43.7px, 10px);  /* → 40px */
  width: round(up, 43.7px, 10px);       /* → 50px (向上取整) */
  width: round(down, 43.7px, 10px);     /* → 40px (向下取整) */
}

/* 实用:流体字体舍入到整 px,避免亚像素模糊 */
h1 { font-size: round(nearest, clamp(16px, 2vw, 32px), 1px); }

【代码注释】round() 解决的是精确控制舍入方向的问题,常用场景:1)与栅格对齐(步长 8px);2)动态值舍入为整像素减少字体渲染模糊;3)配合 CSS 变量动态步长。策略参数 nearest/up/down/to-zero 对应四种数学舍入规则。

mod()rem() --- 取模运算

css 复制代码
/* mod(被除数, 除数) --- 结果符号与除数一致(像 Python % )*/
/* rem(被除数, 除数) --- 结果符号与被除数一致(像 C/JS % ) */

.zebra-nth {
  --nth: 3;
  /* 奇偶交替背景:mod 为 0 时视为偶数行 */
  background: hsl(calc(mod(var(--nth), 2) * 180deg), 60%, 90%);
}

【代码注释】mod()/rem() 在日常布局中较少用,更多出现在 CSS 艺术(条纹、循环序列、圆形排列)中。区分 modrem 的关键是「负数符号归属」,正数时两者相同。生产环境优先用 :nth-child() 做奇偶样式,mod() 用于更复杂的数学关系。

可运行示例(入门):min() / max()calc 嵌套

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>min max 演示</title>
  <style>
    .bar {
      width: min(100%, 480px);
      margin: 12px auto;
      padding: 16px;
      background: #e6f7ff;
    }
    .hero {
      font-size: max(18px, min(4vw, 32px));
      text-align: center;
      padding: 24px;
      background: #fff7e6;
    }
    .panel {
      width: calc(100% - max(20px, 5vw));
      margin: 0 auto;
      padding: 12px;
      background: #f6ffed;
      box-sizing: border-box;
    }
  </style>
</head>
<body>
  <div class="bar">width: min(100%, 480px) --- 窄屏占满,宽屏不超过 480px</div>
  <div class="hero">font-size: max(18px, min(4vw, 32px))</div>
  <div class="panel">width: calc(100% - max(20px, 5vw)) --- 两侧留白随视口放大</div>
</body>
</html>

【代码注释】min()/max() 在样式解析阶段求值,可替代部分媒体查询;与 calc 嵌套时注意括号。clamp(a,b,c) 等价于 max(a, min(b, c)),流式字体一行搞定。


三、颜色函数与渐变函数

名词解释

  • 颜色函数 :生成或操作颜色值的 CSS 函数,如 rgb()hsl()color-mix()
  • 渐变函数 :生成图像数据的颜色过渡函数,如 linear-gradient()radial-gradient()
  • 颜色空间:描述颜色的数学模型,如 sRGB、HSL、LAB、P3
  • 颜色插值:渐变或混合时计算中间色的算法

概念与底层原理

1. 颜色函数族

根据 CSS Color Module Level 4,CSS 支持以下颜色函数:

函数 颜色空间 示例 透明度
rgb() / rgba() sRGB rgb(255, 0, 0) 可选第四参数
hsl() / hsla() HSL hsl(0, 100%, 50%) 可选第四参数
hwb() HWB hwb(0, 0%, 0%) 可选第四参数
lab() CIELAB lab(50%, 50, 50) 可选第四参数
lch() CIELCH lch(50%, 50, 50) 可选第四参数
color() 多色彩空间 color(display-p3 1 0 0) 可选第四参数

2. 渐变函数族

根据 CSS Images Module Level 4,CSS 渐变函数包括:

css 复制代码
/* 线性渐变 */
background: linear-gradient(to right, red, blue);

/* 径向渐变 */
background: radial-gradient(circle, red, blue);

/* 重复线性渐变 */
background: repeating-linear-gradient(to right, red 0px, red 10px, blue 10px, blue 20px);

/* 重复径向渐变 */
background: repeating-radial-gradient(circle, red 0px, red 10px, blue 10px, blue 20px);

/* 锥形渐变 */
background: conic-gradient(from 0deg, red, blue);

【代码注释】线性渐变沿直线过渡,径向渐变从圆心向外扩散,锥形渐变围绕中心点旋转(适合饼图)。repeating- 系列函数重复渐变模式,可用于条纹背景。市面应用:Instagram 首页背景用径向渐变,加载动画用锥形渐变。

3. 现代颜色混合

css 复制代码
/* 颜色混合(CSS Color 5) */
background: color-mix(in srgb, red 50%, blue 50%);

/* 相对颜色 */
color: color-mod(red lightness(20%));

【代码注释】color-mix() 是 CSS Color 5 新增函数,按指定比例混合两种颜色,需指定颜色空间(in srgb/in hsl)。color-mod() 基于基准颜色调整属性(亮度、色相)。市面应用 :主题悬停效果(color-mix(in srgb, primary 80%, white) 生成变体)。

mermaid 图:渐变函数解析

#mermaid-svg-mmH3PD6FFzepAr5n{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mmH3PD6FFzepAr5n .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mmH3PD6FFzepAr5n .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mmH3PD6FFzepAr5n .error-icon{fill:#552222;}#mermaid-svg-mmH3PD6FFzepAr5n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mmH3PD6FFzepAr5n .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mmH3PD6FFzepAr5n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mmH3PD6FFzepAr5n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mmH3PD6FFzepAr5n .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mmH3PD6FFzepAr5n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mmH3PD6FFzepAr5n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mmH3PD6FFzepAr5n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mmH3PD6FFzepAr5n .marker.cross{stroke:#333333;}#mermaid-svg-mmH3PD6FFzepAr5n svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mmH3PD6FFzepAr5n p{margin:0;}#mermaid-svg-mmH3PD6FFzepAr5n .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mmH3PD6FFzepAr5n .cluster-label text{fill:#333;}#mermaid-svg-mmH3PD6FFzepAr5n .cluster-label span{color:#333;}#mermaid-svg-mmH3PD6FFzepAr5n .cluster-label span p{background-color:transparent;}#mermaid-svg-mmH3PD6FFzepAr5n .label text,#mermaid-svg-mmH3PD6FFzepAr5n span{fill:#333;color:#333;}#mermaid-svg-mmH3PD6FFzepAr5n .node rect,#mermaid-svg-mmH3PD6FFzepAr5n .node circle,#mermaid-svg-mmH3PD6FFzepAr5n .node ellipse,#mermaid-svg-mmH3PD6FFzepAr5n .node polygon,#mermaid-svg-mmH3PD6FFzepAr5n .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mmH3PD6FFzepAr5n .rough-node .label text,#mermaid-svg-mmH3PD6FFzepAr5n .node .label text,#mermaid-svg-mmH3PD6FFzepAr5n .image-shape .label,#mermaid-svg-mmH3PD6FFzepAr5n .icon-shape .label{text-anchor:middle;}#mermaid-svg-mmH3PD6FFzepAr5n .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mmH3PD6FFzepAr5n .rough-node .label,#mermaid-svg-mmH3PD6FFzepAr5n .node .label,#mermaid-svg-mmH3PD6FFzepAr5n .image-shape .label,#mermaid-svg-mmH3PD6FFzepAr5n .icon-shape .label{text-align:center;}#mermaid-svg-mmH3PD6FFzepAr5n .node.clickable{cursor:pointer;}#mermaid-svg-mmH3PD6FFzepAr5n .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mmH3PD6FFzepAr5n .arrowheadPath{fill:#333333;}#mermaid-svg-mmH3PD6FFzepAr5n .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mmH3PD6FFzepAr5n .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mmH3PD6FFzepAr5n .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mmH3PD6FFzepAr5n .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mmH3PD6FFzepAr5n .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mmH3PD6FFzepAr5n .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mmH3PD6FFzepAr5n .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mmH3PD6FFzepAr5n .cluster text{fill:#333;}#mermaid-svg-mmH3PD6FFzepAr5n .cluster span{color:#333;}#mermaid-svg-mmH3PD6FFzepAr5n div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mmH3PD6FFzepAr5n .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mmH3PD6FFzepAr5n rect.text{fill:none;stroke-width:0;}#mermaid-svg-mmH3PD6FFzepAr5n .icon-shape,#mermaid-svg-mmH3PD6FFzepAr5n .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mmH3PD6FFzepAr5n .icon-shape p,#mermaid-svg-mmH3PD6FFzepAr5n .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mmH3PD6FFzepAr5n .icon-shape .label rect,#mermaid-svg-mmH3PD6FFzepAr5n .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mmH3PD6FFzepAr5n .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mmH3PD6FFzepAr5n .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mmH3PD6FFzepAr5n :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} linear-gradient参数
解析方向 to right
解析颜色序列 red blue
确定渐变轴
沿轴插值颜色
生成渐变图像
赋值给 background

【代码注释】流程图展示渐变函数解析过程:先解析方向/形状参数确定渐变轴,再沿轴对颜色序列进行插值计算。理解此流程有助于调试渐变效果(方向错误、颜色停止点位置错误)。

可运行示例(入门):颜色函数对比

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>颜色函数对比演示</title>
    <style>
        .color-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            padding: 20px;
            max-width: 1200px;
            margin: 0 auto;
        }

        .color-box {
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            color: #fff;
            font-weight: bold;
        }

        /* RGB 颜色 */
        .rgb-red { background: rgb(255, 0, 0); }
        .rgb-blue { background: rgb(0, 0, 255); }
        .rgb-alpha { background: rgba(255, 0, 0, 0.5); }

        /* HSL 颜色 */
        .hsl-red { background: hsl(0, 100%, 50%); }
        .hsl-green { background: hsl(120, 100%, 50%); }
        .hsl-blue { background: hsl(240, 100%, 50%); }

        /* HWB 颜色 */
        .hwb-white { background: hwb(0, 100%, 0%); color: #000; }
        .hwb-black { background: hwb(0, 0%, 100%); }
        .hwb-mix { background: hwb(0, 50%, 50%); }

        /* 线性渐变 */
        .gradient-linear {
            background: linear-gradient(to right, #e1251b, #f90);
        }

        /* 径向渐变 */
        .gradient-radial {
            background: radial-gradient(circle, #e1251b, #f90);
        }

        /* 锥形渐变 */
        .gradient-conic {
            background: conic-gradient(from 0deg, #e1251b, #f90, #e1251b);
        }
    </style>
</head>
<body>
    <div class="color-grid">
        <div class="color-box rgb-red">
            <h3>RGB Red</h3>
            <p>rgb(255, 0, 0)</p>
        </div>

        <div class="color-box rgb-blue">
            <h3>RGB Blue</h3>
            <p>rgb(0, 0, 255)</p>
        </div>

        <div class="color-box rgb-alpha" style="background: linear-gradient(45deg, #ccc 25%, transparent 25%), linear-gradient(-45deg, #ccc 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #ccc 75%), linear-gradient(-45deg, transparent 75%, #ccc 75%); background-size: 20px 20px; background-position: 0 0, 0 10px, 10px -10px, -10px 0px;">
            <h3>RGBA Alpha</h3>
            <p>rgba(255, 0, 0, 0.5)</p>
        </div>

        <div class="color-box hsl-red">
            <h3>HSL Red</h3>
            <p>hsl(0, 100%, 50%)</p>
        </div>

        <div class="color-box hsl-green">
            <h3>HSL Green</h3>
            <p>hsl(120, 100%, 50%)</p>
        </div>

        <div class="color-box hsl-blue">
            <h3>HSL Blue</h3>
            <p>hsl(240, 100%, 50%)</p>
        </div>

        <div class="color-box gradient-linear">
            <h3>Linear Gradient</h3>
            <p>linear-gradient(to right, #e1251b, #f90)</p>
        </div>

        <div class="color-box gradient-radial">
            <h3>Radial Gradient</h3>
            <p>radial-gradient(circle, #e1251b, #f90)</p>
        </div>

        <div class="color-box gradient-conic">
            <h3>Conic Gradient</h3>
            <p>conic-gradient(from 0deg, #e1251b, #f90, #e1251b)</p>
        </div>
    </div>
</body>
</html>

【代码注释】本示例对比各颜色函数视觉效果:RGB/RGBA 基于红绿蓝分量,HSL 基于色相/饱和度/亮度(更符合人类直觉),HWB 基于白/黑/色调。渐变函数可用于背景、边框、文本等。市面应用:Instagram 徽标用渐变,Stripe 用渐变营造科技感。

【实战要点】

  • 经典应用场景 :主题色透明变体(color-mix(in srgb, primary 50%, white))、悬停效果(渐变移动)、视觉深度(径向渐变阴影)、数据可视化(颜色插值)
  • 常见坑 :HSL 轻度 100% 在深色背景上不可见;渐变角度与期望不符(to right vs 90deg);锥形渐变圆心定位易错;color-mix 兼容性需前缀或回退
  • 性能与最佳实践 :渐变生成位图,复杂渐变可能影响性能;硬件加速可优化;用 image-rendering 控制缩放质量;考虑用 SVG 替代复杂渐变;P3 广色域用 color(display-p3 ...) 提升视觉

【本章小结】

函数类型 代表函数 颜色空间 应用场景
基础颜色 rgb() sRGB 精确颜色控制
直观颜色 hsl() HSL 主题变体、色轮
现代颜色 lab() CIELAB 感知均匀颜色
线性渐变 linear-gradient() N/A 进度条、背景
径向渐变 radial-gradient() N/A 圆形效果、阴影
锥形渐变 conic-gradient() N/A 饼图、加载动画

记忆口诀:"RGB 精确,HSL 直观,渐变分三种,混合靠 color-mix"

【面试考点】

Q1:hsl()rgb() 的选择依据?

A:HSL 更符合人类直觉(色相环旋转生成彩虹色),适合主题变体(hsl(h, 100%, 50%) 固定饱和度/亮度)、渐变生成;RGB 适合精确匹配设计稿(PS 取色值为 RGB)。根据 CSS Color 4,HSL 与 RGB 可无损转换,但 HSL 的亮度计算与人眼感知不完全一致。

Q2:如何实现平滑的颜色过渡动画?

A:避免直接插值 RGB(会经过灰色区间),用 HSL 插值色相或用 color-mix()。原生 CSS transitioncolor/background-color 自动插值;自定义渐变动画需用 @property 注册自定义属性(允许颜色过渡)。现代浏览器还支持 color-interpolation-method 指定插值颜色空间(in hsl vs in oklch)。

Q3:HSL 渐变为什么会出现"灰色死区"?oklch 如何解决?

A:HSL 渐变跨色相时(如红→绿),中间色相角经过灰色区域(饱和度不均匀),导致渐变看起来"发灰"。oklch(OKLab 极坐标形式)采用感知均匀色彩空间,任意两色间的渐变亮度变化线性、色相变化均匀,人眼感知一致。color-mix(in oklch, red, green)color-mix(in hsl, red, green) 产生的中间色更鲜亮。

深化:感知均匀颜色空间 oklch() 与 oklab()

为什么 RGB/HSL 不够用?

sRGB(rgb())和 HSL 色彩空间的颜色分布对人眼不均匀:例如 HSL 中蓝色区域明度变化比黄色区域快得多,导致渐变、调色出现视觉断层。

Oklab/Oklch --- 感知均匀颜色空间

Björn Ottosson 于 2020 年提出 Oklab,2025 年已成为 Baseline Widely Available,Chrome 111 / Firefox 113 / Safari 15.4+ 全面支持。

函数 坐标系 参数含义 适合场景
oklab(L a b) 直角坐标 L=明度 0~1,a=绿↔红轴,b=蓝↔黄轴 颜色灰度化、饱和度调节
oklch(L C H) 极坐标 L=明度 0~1,C=色度 0~0.4,H=色相角 0~360deg 色相平移、调色板生成
css 复制代码
/* oklch 语法 */
:root {
  /* 品牌红:明度 0.55,色度 0.22,色相 25deg(橙红区) */
  --brand: oklch(0.55 0.22 25deg);

  /* 悬停变体:只改明度,色相/色度不变 → 颜色不漂移 */
  --brand-hover: oklch(0.45 0.22 25deg);

  /* 浅色变体:同色相,调低色度+提高明度 */
  --brand-light: oklch(0.92 0.06 25deg);
}

【代码注释】与 HSL 相比,oklch 调整明度(L)时不会改变色相感知 (HSL 调明度容易让颜色变"脏")。同一色相族的设计令牌(dark/base/light)只需改 L 和 C,色相 H 保持一致,调出来的颜色更协调。市面应用 :Tailwind v4、shadcn/ui 2025 版均迁移到 oklch 管理设计令牌。

oklch 实战:一键生成完整色阶

css 复制代码
:root {
  /* 仅改明度,其余不动,生成 5 个色阶 */
  --brand-50:  oklch(0.97 0.04 25deg);
  --brand-100: oklch(0.92 0.07 25deg);
  --brand-300: oklch(0.75 0.14 25deg);
  --brand-500: oklch(0.55 0.22 25deg);   /* 主色 */
  --brand-700: oklch(0.40 0.20 25deg);
  --brand-900: oklch(0.25 0.14 25deg);
}

【代码注释】sRGB 色阶需要设计师手工调,oklch 中只要明度线性递减,色阶感知就均匀------因为 L 轴直接对应人眼亮度感知。与 Tailwind 色板生成工具(oklch.com)联动,复制 oklch 值即可。

oklch 渐变 vs hsl 渐变对比

css 复制代码
/* HSL 渐变:穿越灰色区 */
.gradient-hsl {
  background: linear-gradient(to right,
    hsl(0, 100%, 50%),    /* 红 */
    hsl(120, 100%, 50%)   /* 绿 */
  );
}

/* oklch 渐变:全程鲜亮,无灰色死区 */
.gradient-oklch {
  background: linear-gradient(in oklch to right,
    oklch(0.63 0.26 25deg),    /* 红 */
    oklch(0.52 0.17 145deg)    /* 绿 */
  );
}

【代码注释】linear-gradient(in oklch ...) 指定在 oklch 色彩空间插值(CSS Color 4 语法),中间色经过鲜艳的黄/橙,而非 HSL 中出现的发灰绿。若需穿越短色相弧(in oklch shorter hue)或长色相弧(longer hue),可进一步控制渐变路径。


四、现代 CSS 函数应用场景

名词解释

  • clamp() 函数:将值限制在最小值和最大值之间
  • min() 函数:取参数中的最小值
  • max() 函数:取参数中的最大值
  • 形状函数circle()ellipse()polygon()path() 用于 clip-path
  • 变换函数rotate()scale()translate()skew() 用于 transform

概念与底层原理

1. 比较函数

css 复制代码
/* clamp(min, val, max) 等价于 max(min, min(val, max)) */
font-size: clamp(16px, 2vw, 24px);

/* min() 取最小值 */
width: min(100%, 500px);

/* max() 取最大值 */
width: max(50%, 300px);

【代码注释】clamp() 约束值在 [min, max] 区间,val 超出边界时取边界值;min()/max() 取参数中最小/最大值。这三个函数支持混合单位(%pxvw),在样式解析时计算一次。市面应用clamp(16px, 2vw, 24px) 实现流式字体,无需媒体查询。

根据 CSS Values 4,比较函数在样式解析时计算,支持混合单位。clamp() 常用于响应式字体(不用媒体查询),min()/max() 用于容器约束。

2. 形状函数

css 复制代码
/* 圆形裁剪 */
clip-path: circle(50% at 50% 50%);

/* 椭圆裁剪 */
clip-path: ellipse(50% 30% at 50% 50%);

/* 多边形裁剪 */
clip-path: polygon(50% 0%, 100% 100%, 0% 100%);

/* 路径裁剪 */
clip-path: path('M 10 10 L 90 10 L 90 90 L 10 90 Z');

【代码注释】clip-path 创建裁剪区域,超出部分隐藏。circle()/ellipse() 控制圆心位置和半径,polygon() 通过多组坐标定义多边形,path() 使用 SVG 路径语法。市面应用:不规则头像、徽章、创意布局、加载动画。

根据 CSS Masking Level 1,形状函数创建裁剪区域,超出部分隐藏。用于创意图片处理、徽章效果、加载动画。

3. 变换函数

css 复制代码
/* 2D 变换 */
transform: translate(10px, 20px) rotate(45deg) scale(1.5);

/* 3D 变换 */
transform: translateZ(100px) rotateX(45deg) perspective(500px);

【代码注释】transform 函数在元素自身坐标系操作,从左到右链式应用。translate 平移、rotate 旋转、scale 缩放、skew 倾斜。3D 变换需设置父容器 perspective 属性创建景深。市面应用:悬停卡片抬起、3D 翻转效果、移动端下拉刷新动画。

根据 CSS Transforms Module Level 1,变换函数在元素自身坐标系操作,支持链式调用(从左到右应用)。3D 变换需设置 perspective 创建景深。

mermaid 图:现代 CSS 函数应用分层

#mermaid-svg-BK5kvoIkp3U6E2Rc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BK5kvoIkp3U6E2Rc .error-icon{fill:#552222;}#mermaid-svg-BK5kvoIkp3U6E2Rc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BK5kvoIkp3U6E2Rc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BK5kvoIkp3U6E2Rc .marker.cross{stroke:#333333;}#mermaid-svg-BK5kvoIkp3U6E2Rc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BK5kvoIkp3U6E2Rc p{margin:0;}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge{stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section--1 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section--1 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section--1 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section--1 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section--1 text{fill:#ffffff;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth--1{stroke-width:17;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-0 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-0 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-0 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-0 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-0 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-0{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-0{stroke-width:14;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-1 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-1 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-1 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-1 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-1 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-1{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-1{stroke-width:11;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-2 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-2 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-2 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-2 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-2 text{fill:#ffffff;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-2{stroke-width:8;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-3 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-3 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-3 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-3 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-3 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-3{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-3{stroke-width:5;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-4 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-4 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-4 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-4 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-4 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-4{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-4{stroke-width:2;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-5 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-5 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-5 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-5 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-5 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-5{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-5{stroke-width:-1;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-6 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-6 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-6 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-6 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-6 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-6{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-6{stroke-width:-4;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-7 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-7 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-7 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-7 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-7 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-7{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-7{stroke-width:-7;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-8 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-8 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-8 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-8 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-8 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-8{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-8{stroke-width:-10;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-9 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-9 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-9 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-9 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-9 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-9{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-9{stroke-width:-13;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-10 rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-10 path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-10 circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-10 polygon,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-10 text{fill:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .node-icon-10{font-size:40px;color:black;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge-depth-10{stroke-width:-16;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:lightgray;}#mermaid-svg-BK5kvoIkp3U6E2Rc .disabled text{fill:#efefef;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-root rect,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-root path,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-root circle,#mermaid-svg-BK5kvoIkp3U6E2Rc .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-root text{fill:#ffffff;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-root span{color:#ffffff;}#mermaid-svg-BK5kvoIkp3U6E2Rc .section-2 span{color:#ffffff;}#mermaid-svg-BK5kvoIkp3U6E2Rc .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-BK5kvoIkp3U6E2Rc .edge{fill:none;}#mermaid-svg-BK5kvoIkp3U6E2Rc .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-BK5kvoIkp3U6E2Rc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 现代 CSS 函数
布局计算
calc 四则运算
clamp 响应式约束
min/max 容器限制
视觉效果
color-mix 颜色混合
gradient 渐变
clip-path 裁剪
动画交互
transform 变换
filter 滤镜
@property 自定义属性动画
响应式
clamp 流式字体
min/max 断点
视口单位 vw/vh

【代码注释】思维导图展示现代 CSS 函数的四大应用领域:布局计算(精确尺寸)、视觉效果(颜色与形状)、动画交互(变换与过滤)、响应式(流式设计)。每个领域都有典型函数组合使用。

可运行示例(综合):现代 CSS 函数综合应用

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>现代 CSS 函数综合应用</title>
    <style>
        :root {
            --primary: #e1251b;
            --secondary: #f90;
            --bg-color: #f5f5f5;
            --text-color: #333;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            margin: 0;
            padding: 20px;
            background: var(--bg-color);
            color: var(--text-color);
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
        }

        /* 流式字体:不用媒体查询 */
        h1 {
            font-size: clamp(24px, 4vw, 48px);
            text-align: center;
            margin-bottom: 20px;
        }

        .card-grid {
            display: grid;
            /* 自动列宽,每列最小 300px 最大 1fr */
            grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
            gap: 20px;
            margin: 40px 0;
        }

【代码注释】clamp(24px, 4vw, 48px) 让字体在 24px-48px 之间随视口宽度线性缩放;minmax(min(300px, 100%), 1fr) 确保列宽不小于 300px 且不超出容器,移动端自动堆叠。这两个函数结合实现完全流式布局,无需任何媒体查询。市面应用:现代响应式网站(Vercel、Stripe)大量使用此模式。

复制代码
    .card {
        background: #fff;
        padding: 20px;
        border-radius: 12px;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
        transition: transform 0.3s, box-shadow 0.3s;
    }

    .card:hover {
        transform: translateY(-5px);
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
    }

    /* 渐变边框 */
    .gradient-border {
        position: relative;
        background: linear-gradient(white, white) padding-box,
                    linear-gradient(135deg, var(--primary), var(--secondary)) border-box;
        border: 3px solid transparent;
        border-radius: 12px;
        padding: 20px;
        margin: 20px 0;
    }


【代码注释】渐变边框技巧:用两层 `linear-gradient`,`padding-box` 层为白色内容区,`border-box` 层为渐变边框区,通过 `border: transparent` 透出渐变层。此方法比 `border-image` 更灵活(支持圆角)。**市面应用**:CTA 按钮、卡片高亮、品牌强调元素。

        /* 圆形头像 */
        .avatar {
            width: 100px;
            height: 100px;
            border-radius: 50%;
            /* 径向渐变模拟光泽 */
            background: radial-gradient(circle at 30% 30%, #ff6b6b, var(--primary));
            margin: 0 auto 20px;
        }

【代码注释】radial-gradient(circle at 30% 30%, ...) 将高光点偏移到左上角(30% 30%),模拟光源照射产生的立体感。渐变色从浅到深创建球体效果。市面应用:用户头像、图标设计、3D 按钮效果。

复制代码
    /* 多边形徽章 */
    .badge {
        display: inline-block;
        padding: 5px 15px;
        background: var(--primary);
        color: #fff;
        /* 三角形裁剪 */
        clip-path: polygon(10px 0%, calc(100% - 10px) 0%, 100% 50%, calc(100% - 10px) 100%, 10px 100%, 0% 50%);
    }


【代码注释】`polygon()` 通过六组坐标定义六边形徽章,左右角用 `calc()` 切角 10px。坐标值可用 `calc()` 动态计算,实现响应式裁剪。相比图片,纯 CSS 裁剪性能更好且可调色。**市面应用**:标签系统("热门"、"新品")、创意按钮、加载动画。

        /* 加载动画 */
        .spinner {
            width: 50px;
            height: 50px;
            border: 4px solid #f3f3f3;
            border-top: 4px solid var(--primary);
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        /* 响应式间距 */
        .responsive-spacing {
            padding: clamp(10px, 2vw, 30px);
        }

        /* 混合模式 */
        .blend-mode {
            background: color-mix(in srgb, var(--primary) 80%, var(--secondary) 20%);
            color: #fff;
            padding: 15px;
            border-radius: 8px;
            margin: 10px 0;
        }

【代码注释】color-mix(in srgb, primary 80%, secondary 20%) 按 8:2 比例混合主题色和次要色,生成新色调。sRGB 颜色空间保证混合结果与人眼感知一致。此函数可用于悬停变体、层级阴影、数据可视化。市面应用:主题色派生系统(悬停、禁用、激活状态)。

复制代码
    /* 锥形渐变饼图 */
    .pie-chart {
        width: 150px;
        height: 150px;
        border-radius: 50%;
        background: conic-gradient(
            var(--primary) 0% 33%,
            var(--secondary) 33% 66%,
            #52c41a 66% 100%
        );
        margin: 20px auto;
    }


【代码注释】`conic-gradient()` 围绕中心点旋转渐变,适合绘制饼图、环形图。语法为 `conic-gradient(颜色1 起始% 结束%, 颜色2 起始% 结束%, ...)`,百分比表示颜色在圆周上的位置。**市面应用**:数据可视化(饼图、仪表盘)、加载动画、创意背景。
    </style>
</head>
<body>
    <div class="container">
        <h1>现代 CSS 函数综合应用</h1>

        <div class="card-grid">
            <div class="card">
                <div class="avatar"></div>
                <h3>渐变头像</h3>
                <p>使用 radial-gradient 创建光泽效果</p>
            </div>

            <div class="card">
                <h3>多边形徽章</h3>
                <p><span class="badge">热门</span></p>
                <p>使用 clip-path: polygon() 创建六边形徽章</p>
            </div>

            <div class="card">
                <h3>加载动画</h3>
                <div style="display: flex; justify-content: center; margin: 20px 0;">
                    <div class="spinner"></div>
                </div>
                <p>使用 transform: rotate() 和 keyframes</p>
            </div>

            <div class="card">
                <h3>流式字体</h3>
                <p style="font-size: clamp(14px, 2vw, 20px);">
                    本段字体大小使用 clamp(14px, 2vw, 20px),
                    在不同视口宽度下自动缩放,无需媒体查询。
                </p>
            </div>

            <div class="card">
                <h3>颜色混合</h3>
                <div class="blend-mode">
                    color-mix(in srgb, primary 80%, secondary 20%)
                </div>
                <p>使用 color-mix() 混合两种颜色</p>
            </div>

            <div class="card">
                <h3>饼图</h3>
                <div class="pie-chart"></div>
                <p>使用 conic-gradient() 创建饼图</p>
            </div>
        </div>

        <div class="gradient-border">
            <h3>渐变边框效果</h3>
            <p>使用 linear-gradient 双层背景实现:一层为 padding-box(白色),一层为 border-box(渐变)。</p>
        </div>

        <div class="responsive-spacing">
            <h3>响应式间距</h3>
            <p>本区块的 padding 使用 clamp(10px, 2vw, 30px),在移动端和桌面端自动调整。</p>
        </div>
    </div>
</body>
</html>

【代码注释】本示例综合展示现代 CSS 函数:clamp() 实现流式字体和响应式间距,minmax(min(300px, 100%), 1fr) 确保网格不会溢出,color-mix() 混合主题色,conic-gradient() 绘制饼图,clip-path() 创建多边形。市面应用:Vercel、Stripe 等现代网站大量使用这些函数实现精美 UI。

【实战要点】

  • 经典应用场景 :响应式字体(clamp())、自适应网格(minmax())、主题变体(color-mix())、图标设计(clip-path())、数据可视化(渐变、锥形)、创意动效(transform + filter
  • 常见坑clamp(min, val, max)val < min 时取 min,无动画过渡;clip-path 可能截断阴影;color-mix 需指定颜色空间(默认 srgb);渐变角度在圆心附近可能产生锯齿
  • 性能与最佳实践calc()/clamp() 解析后为固定值,性能开销可忽略;渐变和 clip-path 生成位图,复杂图形考虑 GPU 加速;transform 触发硬件加速层;避免在 @keyframes 中使用 calc() 每帧重新计算;用 will-change 提示浏览器优化

【本章小结】

函数类型 代表函数 核心价值 应用场景
比较函数 clamp() 值域约束 响应式字体、容器约束
网格函数 minmax() 弹性布局 自适应网格
颜色函数 color-mix() 颜色混合 主题变体、交互状态
裁剪函数 clip-path() 形状定制 徽章、头像、创意布局
渐变函数 conic-gradient() 视觉效果 饼图、加载动画

记忆口诀:"clamp 约束值域,minmax 弹性网格,color-mix 混色,clip-path 裁剪,渐变分三类"

【面试考点】

Q1:clamp(min, val, max)min()/max() 的选择依据?

A:clamp() 等价于 max(min, min(val, max)),适合"有最小值和最大值限制的响应式值"(字体、间距、尺寸);min()/max() 适合"取小/大者"场景(min(100%, 500px) 限制最大宽度)。根据 CSS Values 4clamp()valNaNInfinity 时仍有效(取边界值)。

Q2:clip-pathmask 的区别?

A:clip-path 是裁剪区域(超出隐藏),支持 circle()/polygon() 等形状函数,性能较好;mask 是遮罩层(基于透明度),支持图片、渐变,可实现淡入淡出等效果。clip-path 适合硬边裁剪,mask 适合柔和遮罩。两者可组合使用实现复杂效果。

Q3:linear-gradientrepeating-linear-gradient 如何选?

A:linear-gradient一次 从色 A 到色 B 的过渡(Banner、按钮高光);repeating-linear-gradient 在指定色标间距内重复 相同条纹(进度条刻度、斑马纹背景)。色标写法 red 0px, red 10px, blue 10px, blue 20px 控制重复周期;周期过小在高 DPI 屏上可能出现摩尔纹,可适当加大间距。

Q4:clip-path 动画如何实现平滑过渡?

A:clip-path 支持 transition/animation 前提是两个状态使用相同类型、相同顶点数 的形状。例如两个 polygon() 都是 4 个顶点可以过渡,circle()polygon() 之间不能插值(形状类型不同)。实用技巧:起始状态用退化的形状(如将 polygon 某顶点挤到一起)模拟展开/收起动画。

深化:env() 环境变量函数与移动端安全区域

env() 函数读取浏览器(用户代理)暴露的环境变量 ,最重要的是 safe-area-inset-* 系列,用于处理刘海屏/圆角屏/Home 条遮挡内容的问题。

安全区域问题背景:

iPhone X 引入刘海设计后,viewport-fit=cover 允许内容延伸到屏幕边缘(沉浸式),但顶部刘海/底部 Home 条会遮挡内容。env(safe-area-inset-*) 提供设备实际安全区域的像素值:

变量名 含义 iPhone 14 Pro 竖屏约值
env(safe-area-inset-top) 顶部安全距离(刘海/灵动岛) ~59px
env(safe-area-inset-bottom) 底部安全距离(Home 条) ~34px
env(safe-area-inset-left) 左侧安全距离(横屏刘海) 横屏时 ~44px
env(safe-area-inset-right) 右侧安全距离(横屏刘海) 横屏时 ~44px

使用方法:

第一步,在 HTML 启用全屏:

html 复制代码
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">

【代码注释】viewport-fit=cover 让页面内容延伸到屏幕边缘(包括刘海/圆角区域),是使用 env(safe-area-inset-*) 的前提。不加此属性时,浏览器默认留出安全区域(viewport-fit=auto),env() 的值会为 0

第二步,在 CSS 中使用 env()

css 复制代码
/* 固定底部导航栏适配 Home 条 */
.bottom-nav {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 56px;
  /* 底部额外填充 Home 条高度,兼容不支持 env() 的浏览器 */
  padding-bottom: env(safe-area-inset-bottom, 0px);
  background: #fff;
  border-top: 1px solid #eee;
}

/* 与 calc() 配合:留出 Home 条 + 额外间距 */
.bottom-nav {
  padding-bottom: max(env(safe-area-inset-bottom, 0px), 8px);
}

【代码注释】env(safe-area-inset-bottom, 0px) 第二参数是回退值(矩形屏浏览器 env 不支持或值为 0 时)。配合 max() 可保证最小底部间距(max(safe-area, 最小值))。实战意义:微信小程序、H5 全屏游戏、PWA 必备处理。

env() 与 CSS 变量配合(推荐模式):

css 复制代码
/* 在 :root 统一定义,全局复用 */
:root {
  --safe-top:    env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left:   env(safe-area-inset-left, 0px);
  --safe-right:  env(safe-area-inset-right, 0px);
}

.header {
  padding-top: calc(16px + var(--safe-top));
}
.footer {
  padding-bottom: calc(8px + var(--safe-bottom));
}

【代码注释】env() 的语法和 var() 相似,但 env() 不可动态更改(设备屏幕物理属性),var() 可通过 JS 修改。将 env() 存入 CSS 变量后,各组件直接用 var(--safe-*) 即可,不用重复写 env()

深化:attr() 函数 --- 读取 HTML 属性值

attr() 函数让 CSS 能读取 HTML 元素的属性值 ,最常见用途是配合 content 生成伪元素内容:

css 复制代码
/* 传统用法:content 中读取 data-* 属性 */
[data-tooltip]::after {
  content: attr(data-tooltip);      /* 读取 data-tooltip 属性的字符串值 */
  position: absolute;
  background: #333;
  color: #fff;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  /* 伪元素定位 */
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  pointer-events: none;
}

.tooltip-host {
  position: relative;
  display: inline-block;
}
.tooltip-host::after { opacity: 0; transition: opacity 0.2s; }
.tooltip-host:hover::after { opacity: 1; }

【代码注释】[data-tooltip]::after 用属性选择器匹配所有含 data-tooltip 的元素,再通过 attr(data-tooltip) 读取属性值注入伪元素。bottom: calc(100% + 6px) 让气泡始终悬浮在元素上方 6px,transform: translateX(-50%) 水平居中。pointer-events: none 防止伪元素阻挡鼠标事件触发 tooltip 自身。

html 复制代码
<!-- HTML 端只需添加 data 属性 -->
<button class="tooltip-host" data-tooltip="保存到本地">保存</button>
<a class="tooltip-host" data-tooltip="跳转到首页" href="/">首页</a>

【代码注释】attr(data-tooltip) 从元素的 data-tooltip 属性读取字符串,注入 ::aftercontent。这种方式实现纯 CSS tooltip:HTML 维护文本,CSS 负责样式,无 JS。注意attr() 目前(2026)仅稳定支持 content 属性,用于 width/color 等布局属性的 CSS 4 级扩展语法(attr(data-width px))浏览器支持仍有限,生产环境需谨慎。

电商详情页实战:Less 变量与原生 CSS 变量并存

项目中常见两套「变量」并存,职责不同:

来源 写法 生效时机 典型用途
Less @form-red: #ea4a36 编译为常量写入 CSS 静态品牌色、嵌套选择器
原生 CSS --form-red:root 运行时,可被 JS 改 主题切换、A/B 色

【代码注释】本课先学原生 var(),完整电商项目里 Less 仍负责大部分布局;二者不冲突。需要运行时换肤 时用 CSS 变量;仅需构建时换肤用 Less 变量或构建脚本替换即可。

固定侧边导航栏(页面实战)

侧栏本体以 定位 + 过渡 为主;固定侧边导航栏完整页的 Less 中未使用 var()/calc(),但可与 CSS 函数组合做「主区域占满剩余视口」等增强。

滑入/滑出 CSS:

css 复制代码
.page-siderbar {
    position: fixed;
    right: -294px;
    top: 0;
    width: 300px;
    height: 100%;
    display: flex;
    transition: right 0.3s ease-in-out;
}
.page-siderbar.open {
    right: 0;
}
.page-siderbar.open .menu-btn {
    background-image: url(../images/cross.png);
}

【代码注释】width: 300px 中可见条 6px + 内容区 294pxright: -294px 只露出左侧 6px 导航条。transition 作用于 right,避免用 JS 逐帧改位置。

悬停展开文字标签(纯 CSS,无 JS):

css 复制代码
.page-siderbar .nav-item a span {
    position: absolute;
    left: 35px;
    top: 0;
    width: 62px;
    line-height: 35px;
    background: #c81122;
    transition: left 0.3s ease-in-out 0.1s;
}
.page-siderbar .nav-item:hover a span {
    left: -60px;
}

【代码注释】标签默认在图标右侧(left: 35px),悬停时移到 left: -60px 向左「滑出」显示文字;0.1s 延迟与侧栏 right 动画错开,视觉更顺。雪碧图 toolbars.pngbackground-position 切换图标,与 CSS 函数无关但常与本节同页调试。

可选:用 calc 约束主内容最小高度

css 复制代码
:root {
    --header-stack: 92px; /* 顶栏+导航等近似高度 */
}
.page-main {
    min-height: calc(100vh - var(--header-stack));
}

【代码注释】侧栏 height: 100% 依赖视口;主区域用 calc(100vh - 顶栏) 可避免短内容页 footer 悬空。--header-stack 宜与真实 DOM 测量值一致,或改用 flex 布局让主区 flex: 1

JS 核心:

javascript 复制代码
(function () {
    var pageSierbar = document.querySelector('#pageSierbar');
    var menuBtn = document.querySelector('#menuBtn');
    var topBtn = document.querySelector('#topBtn');

    menuBtn.onclick = function () {
        pageSierbar.classList.toggle('open');
    };

    topBtn.onclick = function () {
        window.scrollTo({ top: 0, behavior: 'smooth' });
    };
})();

【代码注释】classList.toggle 在有无 open 间切换,比手动 add/remove 简洁;scrollTobehavior: 'smooth' 需现代浏览器,旧版可回退 scrollTop = 0。悬停展开文字标签用 span { left: -60px } 纯 CSS,不占用本节 JS。

可运行示例(实战):迷你固定侧栏 + 回顶

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>固定侧栏演示</title>
  <style>
    body { min-height: 200vh; margin: 0; font-family: sans-serif; }
    .page-siderbar {
      position: fixed; right: -100px; top: 0; width: 120px; height: 100%;
      background: #7a6e6e; color: #fff; transition: right .3s ease-in-out;
      display: flex; flex-direction: column; padding: 8px 0;
    }
    .page-siderbar.open { right: 0; }
    .nav-item { position: relative; width: 36px; height: 36px; margin: 4px 0; background: #7a6e6e; }
    .nav-item a { display: block; width: 36px; height: 36px; line-height: 36px; text-align: center; color: #fff; text-decoration: none; }
    .nav-item span {
      position: absolute; left: 36px; top: 0; width: 56px; height: 36px; line-height: 36px;
      text-align: center; background: #c81122; transition: left .3s ease .1s;
    }
    .nav-item:hover { background: #c81122; }
    .nav-item:hover span { left: -52px; }
    .page-siderbar button {
      margin: 6px 0; padding: 8px 12px; border: none; cursor: pointer;
      background: #c81122; color: #fff; border-radius: 4px; width: 36px;
    }
  </style>
</head>
<body>
  <p style="padding:20px">向下滚动后点「回顶」;悬停左侧图标可看标签滑出</p>
  <aside class="page-siderbar" id="bar">
    <button type="button" id="menu">≡</button>
    <div class="nav-item"><a href="#">①<span>会员</span></a></div>
    <div class="nav-item"><a href="#">②<span>购物车</span></a></div>
    <button type="button" id="top">↑</button>
  </aside>
  <script>
    var bar = document.getElementById('bar');
    document.getElementById('menu').onclick = function () { bar.classList.toggle('open'); };
    document.getElementById('top').onclick = function () { window.scrollTo({ top: 0, behavior: 'smooth' }); };
  </script>
</body>
</html>

【代码注释】缩小版侧栏含 toggle 滑入、scrollTo 回顶,以及 .nav-item:hover span 标签滑出,与完整详情页悬停逻辑一致,便于单文件调试。


总结

知识点回顾(思维导图)

渲染错误: Mermaid 渲染失败: Parse error on line 5: ...--name 声明 var() 引用 :root 全局作 ----------------------^ Expecting 'NODE_DESCR', got 'NODE_DEND'

【代码注释】思维导图总结全文知识体系:从 CSS 变量与 @property 实现类型化设计令牌,到 calc() 族实现精确响应式布局,到 oklch 感知均匀颜色空间,再到 env() 移动端安全区域适配,最后到现代比较函数和裁剪函数实现创意交互。掌握这些函数让 CSS 代码更具表达力和工程质量。

高频面试题速查

  1. CSS 变量 vs Less/Sass 变量 --- 运行时 vs 编译时;可动态修改 vs 不可修改;DOM 作用域 vs 词法作用域
  2. var(--name, fallback) 回退值 --- 变量未定义/无效时使用;空值 --x: ; 不触发回退
  3. calc() 运算规则 --- 加减两边有单位,乘除只有一边有单位,支持单位混合;+/- 两侧必须有空格
  4. calc(100% / 3) 精度问题 --- IEEE 754 浮点数误差,解决方案:calc(100% / 3 * 3) 修正最后一列
  5. HSL vs oklch 渐变 --- HSL 渐变穿越灰色区(非感知均匀);oklch 感知均匀,渐变无"灰色死区";2025 已 Baseline Widely Available
  6. clamp() vs min()/max() --- clamp(min, val, max) 约束值域,min()/max() 取最值;clamp 等价于 max(min, min(val, max))
  7. clip-path vs mask --- clip-path 硬边裁剪(性能好),mask 柔和遮罩(基于透明度);clip-path 动画要求形状类型+顶点数相同
  8. 主题切换实现 --- CSS 变量 + class 切换 + prefers-color-scheme 媒体查询
  9. @property 作用 --- 注册类型化自定义属性,启用插值动画;syntax/inherits/initial-value 三字段必填(syntax* 时)
  10. env() 用途 --- 读取 safe-area-inset-* 适配刘海屏;需搭配 viewport-fit=cover;可与 max() 组合保证最小安全距离
  11. attr() 用途 --- 在 content 中读取元素属性(tooltip 常用模式);布局属性中的用法浏览器支持有限
  12. calc 重复属性 --- 同选择器后声明覆盖前声明
  13. Less @x vs CSS --x --- 编译时替换 vs 运行时可改
  14. 固定侧栏 --- fixed + 负 right + .open + transition
  15. round()/mod()/rem() 用途 --- CSS Values 4 新函数;round() 按步长舍入(Chrome 109+),日常布局仍以 calc/clamp 为主
  16. pow/sqrt/sin 用途 --- 几何/动画进阶(CSS Values 4),布局仍以 calc/clamp 为主
  17. 悬停标签 --- spanleft + transition,非 calc

验收自检清单

  • 变量示例::root 定义 --len / 品牌色,var().item 生效
  • calc 示例:四则运算无无效声明(注意重复 width 层叠)
  • 能写出 calc(100% - 侧边栏宽度) 圣杯主区宽度
  • 会用 clamp(min, val, max) 做流式标题
  • setProperty:root 变量后全页颜色更新
  • 固定侧栏:toggle('open') 滑入,回顶 scrollTo({ behavior: 'smooth' })
  • 悬停 .nav-item 时文字标签向左展开

常见错误排查表

现象 原因 处理
calc() 整条无效 乘除两边都有单位,或除数带单位 对照四则口诀改写法
var() 无效果 变量未定义或作用域不对 检查是否在祖先上声明 --x
宽度与预期不符 同一属性写了两次 DevTools 看生效的那条
侧栏不滑出 未加 .open 或选择器拼写 核对 #pageSierbar 与 class
Less 改变量不生效 改的是 @ 而非 -- 编译后改 CSS 或改用原生变量
clamp 字号不变 三参数顺序写反 应为 clamp(最小, 理想, 最大)
数学函数无效 浏览器不支持 sin/pow 查 Can I Use,提供回退样式
悬停标签不弹出 未悬停 .nav-itemspan 被裁切 检查 overflowz-index
@property 动画仍离散 syntax 类型错误或缺 initial-value 对照 MDN 补全三个必填字段
@property 被忽略 嵌套在选择器/媒体查询内 移到 CSS 文件顶层作用域
env() 无效果 未设置 viewport-fit=cover meta viewport 补上该属性
oklch 颜色显示异常 超出 sRGB 色域 改 L/C 值或提供 rgb() 回退

学习建议

  1. 基础练习:先跑通「变量基础示例」「数学运算示例」两个 HTML,再读本文扩展章节
  2. 实战项目
    • 实现主题切换(setProperty + prefers-color-scheme
    • calc() + var() 做圣杯布局主内容宽度
    • 在固定侧边导航栏完整页调试 togglescrollTo 与悬停标签
    • clamp() / min() 做流式标题,减少媒体查询
    • :root 增加 --header-stack,用 calc(100vh - var(--header-stack)) 拉齐主区高度
  3. 进阶方向
    • @property 注册类型化变量,实现渐变进度条、颜色平滑动画
    • 将品牌色从 #e1251b 转换到 oklch 表达,体验感知均匀色阶
    • 移动端页面添加 viewport-fit=cover + env(safe-area-inset-*) 刘海屏适配
    • 探索 attr() + data-tooltip 实现纯 CSS tooltip 组件
    • 研究容器查询(@container)与 calc() 结合实现组件级响应式
    • 学习 P3 广色域(color(display-p3 ...))和 round() 等 CSS Values 4 新函数
    • 关注 Houdini API(CSS Paint API)扩展 CSS 能力的未来方向
  4. 参考资源

相关资源:

相关推荐
lichenyang45312 小时前
#鸿蒙基础复盘:生命周期、启动链路、路由跳转与真实需求定位
前端
ZengLiangYi12 小时前
Prompt 工程:让 LLM 输出结构化 JSON
前端·javascript·后端
Asmewill12 小时前
LangGraph学习笔记四(Node和Edge)
前端
何乐乐12 小时前
【Taro 5.0 技术与实践】 - 高性能 iOS 渲染层与 TaroUI 跨端框架介绍
android·前端·ios
米丘12 小时前
React19.x 一个示例来看 Diff 算法
javascript·react.js
猩球中的木子12 小时前
什么是DNS解析
前端·vue.js·面试
Ticnix12 小时前
从零封装 Ollama AI 服务:TypeScript 流式对话工具开发
前端·ollama
十五年专注C++开发12 小时前
C++ 序列化 Protocol Buffers:高效数据交换
开发语言·c++·序列化·反序列化·protobuf
zithern_juejin12 小时前
手写instanceof
javascript