导读:本文系统讲解 CSS 函数体系,涵盖 CSS 自定义属性(变量)、
calc()数学计算、颜色函数、渐变函数等核心内容。每个知识点均配完整可运行示例,并引用 MDN CSS 函数、CSS Custom Properties 规范、CSS Values and Units 规范 等权威资料。掌握 CSS 函数将让你的样式表更具可维护性、动态性和计算能力。
目录
- 零、导读与学习价值
- [0.1 配套示例覆盖清单](#0.1 配套示例覆盖清单)
- [0.2 核心名词速查](#0.2 核心名词速查)
- [0.3 为什么要学本篇](#0.3 为什么要学本篇)
- [0.4 前置知识](#0.4 前置知识)
- [0.5 建议练习路线](#0.5 建议练习路线)
- [0.6 CSS 函数族谱(本节梳理)](#0.6 CSS 函数族谱(本节梳理))
- [0.7 数学扩展函数展望](#0.7 数学扩展函数展望)
- [一、CSS 自定义属性(变量)](#一、CSS 自定义属性(变量))
- 名词解释
- 概念与底层原理
- [mermaid 图:CSS 变量解析流程](#mermaid 图:CSS 变量解析流程)
- [可运行示例(入门):CSS 变量基础用法](#可运行示例(入门):CSS 变量基础用法)
- [可运行示例(变量引用):
:root与var()直接引用](#可运行示例(变量引用)::root 与 var() 直接引用) - 可运行示例(补充):跟随系统深色模式
- 可运行示例(实战):电商品牌色系统
- 【实战要点】
- 【本章小结】
- 【面试考点】
- [深化:
@property注册自定义属性](#深化:@property 注册自定义属性)
- [二、calc() 数学计算函数](#二、calc() 数学计算函数)
- 名词解释
- 概念与底层原理
- [mermaid 图:calc() 计算流程](#mermaid 图:calc() 计算流程)
- [可运行示例(入门):calc() 基础运算](#可运行示例(入门):calc() 基础运算)
- [可运行示例(四则运算):
calc()四则运算与var()结合](#可运行示例(四则运算):calc() 四则运算与 var() 结合) - [可运行示例(补充):
clamp()流式字号与卡片宽度](#可运行示例(补充):clamp() 流式字号与卡片宽度) - 可运行示例(实战):响应式圣杯布局
- 【实战要点】
- 【本章小结】
- 【面试考点】
- [深化:CSS Values 4 新数学函数
round()/mod()/rem()](#深化:CSS Values 4 新数学函数 round()/mod()/rem()) - [可运行示例(入门):
min()/max()与calc嵌套](#可运行示例(入门):min() / max() 与 calc 嵌套)
- 三、颜色函数与渐变函数
- [四、现代 CSS 函数应用场景](#四、现代 CSS 函数应用场景)
- 名词解释
- 概念与底层原理
- [mermaid 图:现代 CSS 函数应用分层](#mermaid 图:现代 CSS 函数应用分层)
- [可运行示例(综合):现代 CSS 函数综合应用](#可运行示例(综合):现代 CSS 函数综合应用)
- 【实战要点】
- 【本章小结】
- 【面试考点】
- [深化:
env()环境变量函数与移动端安全区域](#深化:env() 环境变量函数与移动端安全区域) - [深化:
attr()函数 --- 读取 HTML 属性值](#深化:attr() 函数 — 读取 HTML 属性值) - [电商详情页实战:Less 变量与原生 CSS 变量并存](#电商详情页实战:Less 变量与原生 CSS 变量并存)
- 固定侧边导航栏(页面实战)
- [可运行示例(实战):迷你固定侧栏 + 回顶](#可运行示例(实战):迷你固定侧栏 + 回顶)
- 总结
零、导读与学习价值
0.1 配套示例覆盖清单
本文完整覆盖以下两个核心模块的知识点与实现要点:
| 序号 | 主题 | 核心技能 |
|---|---|---|
| 1 | CSS 变量 | :root 定义、var() 引用、作用域与继承 |
| 2 | 数学计算 | calc() 四则运算、单位混合、边界值处理 |
| 3 | 固定侧边导航栏 | position: fixed、classList.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 盒模型(
width、padding、margin、border) - CSS 颜色表示法(十六进制、
rgb()、rgba()、命名颜色) - CSS 单位(
px、%、em、rem、vw、vh)
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 变量存储设计令牌(颜色、间距、断点)。
可运行示例(变量引用)::root 与 var() 直接引用
保存为 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 类名实现深色模式。
【实战要点】
- 经典应用场景:设计令牌系统(品牌色、间距、字号)、主题切换(明/暗模式)、响应式断点、组件库主题定制
- 常见坑 :变量名拼写错误(
--colorvs--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 注册自定义属性
@property 是 CSS 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 是一个角度值」,浏览器就能在 0deg 和 200deg 之间做逐帧插值。插值计算被 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)。生产环境每个属性只保留一条 width。height 仍由 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>© 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 4 在 calc 体系之上引入了更多数学函数,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 艺术(条纹、循环序列、圆形排列)中。区分 mod 与 rem 的关键是「负数符号归属」,正数时两者相同。生产环境优先用 :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 rightvs90deg);锥形渐变圆心定位易错;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 transition 对 color/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() 取参数中最小/最大值。这三个函数支持混合单位(%、px、vw),在样式解析时计算一次。市面应用 :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 4,clamp() 在 val 为 NaN 或 Infinity 时仍有效(取边界值)。
Q2:clip-path 与 mask 的区别?
A:clip-path 是裁剪区域(超出隐藏),支持 circle()/polygon() 等形状函数,性能较好;mask 是遮罩层(基于透明度),支持图片、渐变,可实现淡入淡出等效果。clip-path 适合硬边裁剪,mask 适合柔和遮罩。两者可组合使用实现复杂效果。
Q3:linear-gradient 与 repeating-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 属性读取字符串,注入 ::after 的 content。这种方式实现纯 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 + 内容区 294px;right: -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.png 用 background-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 简洁;scrollTo 的 behavior: '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 代码更具表达力和工程质量。
高频面试题速查
- CSS 变量 vs Less/Sass 变量 --- 运行时 vs 编译时;可动态修改 vs 不可修改;DOM 作用域 vs 词法作用域
var(--name, fallback)回退值 --- 变量未定义/无效时使用;空值--x: ;不触发回退calc()运算规则 --- 加减两边有单位,乘除只有一边有单位,支持单位混合;+/-两侧必须有空格calc(100% / 3)精度问题 --- IEEE 754 浮点数误差,解决方案:calc(100% / 3 * 3)修正最后一列- HSL vs oklch 渐变 --- HSL 渐变穿越灰色区(非感知均匀);
oklch感知均匀,渐变无"灰色死区";2025 已 Baseline Widely Available clamp()vsmin()/max()---clamp(min, val, max)约束值域,min()/max()取最值;clamp等价于max(min, min(val, max))clip-pathvsmask---clip-path硬边裁剪(性能好),mask柔和遮罩(基于透明度);clip-path动画要求形状类型+顶点数相同- 主题切换实现 --- CSS 变量 + class 切换 +
prefers-color-scheme媒体查询 @property作用 --- 注册类型化自定义属性,启用插值动画;syntax/inherits/initial-value三字段必填(syntax非*时)env()用途 --- 读取safe-area-inset-*适配刘海屏;需搭配viewport-fit=cover;可与max()组合保证最小安全距离attr()用途 --- 在content中读取元素属性(tooltip 常用模式);布局属性中的用法浏览器支持有限- calc 重复属性 --- 同选择器后声明覆盖前声明
- Less
@xvs CSS--x--- 编译时替换 vs 运行时可改 - 固定侧栏 ---
fixed+ 负right+.open+transition round()/mod()/rem()用途 --- CSS Values 4 新函数;round()按步长舍入(Chrome 109+),日常布局仍以calc/clamp为主pow/sqrt/sin用途 --- 几何/动画进阶(CSS Values 4),布局仍以calc/clamp为主- 悬停标签 ---
span改left+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-item 或 span 被裁切 |
检查 overflow 与 z-index |
@property 动画仍离散 |
syntax 类型错误或缺 initial-value |
对照 MDN 补全三个必填字段 |
@property 被忽略 |
嵌套在选择器/媒体查询内 | 移到 CSS 文件顶层作用域 |
env() 无效果 |
未设置 viewport-fit=cover |
meta viewport 补上该属性 |
| oklch 颜色显示异常 | 超出 sRGB 色域 | 改 L/C 值或提供 rgb() 回退 |
学习建议
- 基础练习:先跑通「变量基础示例」「数学运算示例」两个 HTML,再读本文扩展章节
- 实战项目 :
- 实现主题切换(
setProperty+prefers-color-scheme) - 用
calc()+var()做圣杯布局主内容宽度 - 在固定侧边导航栏完整页调试
toggle、scrollTo与悬停标签 - 用
clamp()/min()做流式标题,减少媒体查询 - 在
:root增加--header-stack,用calc(100vh - var(--header-stack))拉齐主区高度
- 实现主题切换(
- 进阶方向 :
- 用
@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 能力的未来方向
- 用
- 参考资源 :
相关资源: