CSS色彩视觉

这不仅仅是换个写法,这是色彩空间(Color Space)的物理学升级。

oklch() 与广色域

这不仅仅是换个写法,这是**色彩空间(Color Space)**的物理学升级。

以前的痛点 (RGB/HSL):

  1. 物理不均匀: 在 HSL 中,黄色 (hue: 60) 看起来比 蓝色 (hue: 240) 亮得多,即使它们的“亮度 L”参数设得一样。这对做无障碍设计(A11y)是灾难。
  2. 色域窄: sRGB 只能显示现有屏幕颜色的 70% 左右。现代苹果/安卓设备的 P3 广色域屏幕完全被浪费了。
  3. 渐变发灰: 传统的蓝色到黄色的渐变,中间会出现难看的灰色死区。

现代解法 (oklch): 感知均匀的色彩空间。

css
.modern-color {
  /* L (Lightness): 亮度 (感知上的绝对亮度)
    C (Chroma): 鲜艳度 (类似饱和度,但没有上限)
    H (Hue): 色相
  */
  color: oklch(60% 0.15 240); 
}

image-20260212013154676

相对颜色语法

这是 CSS Color Level 5 的核心,也是Design Token系统的终极形态。

痛点: 你的主题色是 --primary: #3498db。现在你需要一个半透明的主题色做背景。 以前你没办法直接改 HEX 颜色的透明度,你只能把变量定义成 RGB 数字 52, 152, 219,然后用 rgba(var(--primary), 0.5)。非常麻烦。

现代解法: from ... 语法。你可以“解构”一个颜色,修改它的参数,再“重组”它。

css
:root {
  --primary: #3498db; /* 我们可以直接存 HEX 了! */
}

.button-bg {
  /* 翻译:
     1. 从 --primary 变量里拿颜色
     2. 把 r, g, b 保持原样
     3. 加上 / 50% 的透明度
  */
  background-color: rgb(from var(--primary) r g b / 50%);
}

.button-hover {
  /* 甚至可以用 calc 改变亮度! */
  /* 把原来的红色分量 + 20 */
  background-color: rgb(from var(--primary) calc(r + 20) g b);
}

底蕴价值: 它让颜色变成了可计算的对象,而不是死板的字符串。你可以只定义一个基准色,然后自动生成整个配色方案(变亮、变暗、变透明、互补色),且不需要 Sass/Less 预处理。

font-palette

简单来说,font-palette 让你能够直接修改字体内部的配色方案

但这听起来有点抽象,我们需要先理解它的背景——彩色字体 (Color Fonts)

真正的矢量图层控制 彩色字体(尤其是 COLRv1)内部是基于矢量的。font-palette 覆盖的不是一张图,而是字体内部的绘制指令。这意味着无论你放大到多少倍,边缘依然清晰,且颜色过渡极其自然。

性能的降维打击 以前要做出这种 3D 艺术字,你可能需要加载几百 KB 的图片,或者运行复杂的 JavaScript 动画。现在,你只需要加载一个几十 KB 的字体文件,剩下的全部交给 CSS 渲染引擎,性能损耗几乎为零

无障碍与 SEO 友好 这才是最有“底蕴”的一点。虽然它看起来像一张华丽的图片,但它在 HTML 里依然是纯文本。屏幕阅读器可以朗读它,搜索引擎可以索引它,用户可以选中并复制它。

这是使用 font-palette 时最常见的困惑:“我怎么知道 0 号颜色是哪部分?1 号又是哪部分?”

目前有几种方法:

  • 查看字体官网:像 Nabla、Bungee Spice 这些流行的 Google Fonts,官网都会提供索引说明。
  • 使用可视化工具:有些网站(如 Font Drop)可以解析彩色字体,列出它包含的所有调色板(CPAL table)和索引。
  • 暴力调试法:在浏览器的开发者工具中,尝试修改 05 的颜色,观察文字哪部分变色了,这也是前端开发的乐趣所在。

原生色彩混合器

color-mix()这是 CSS 函数式编程能力的体现。

痛点: 以前设计系统里有一套主色(比如蓝色),我们需要生成浅蓝做背景,深蓝做按钮按下态。在 CSS 里做不到,只能用 Sass (lighten($color, 10%)) 或者手动算好一堆 HEX 值写死。

现代解法 (color-mix): 浏览器自己会调色。

css
:root {
  --brand: #007bff; /* 品牌蓝 */
}
.button {
  background-color: var(--brand);
}
.button:hover {
  /* 想要深一点?混入 10% 的黑色 */
  background-color: color-mix(in srgb, var(--brand), black 10%);
}
.button-light {
  /* 想要浅一点?混入 80% 的白色 (只留 20% 原色) */
  background-color: color-mix(in srgb, var(--brand), white 80%);
}
.transparent-border {
  /* 最强用法:保持颜色不变,但调整透明度 */
  /* 以前只能用 rgba() 重新写一遍 r,g,b,现在直接混入 transparent */
  border-color: color-mix(in srgb, var(--brand), transparent 50%);
}

image-20260212014201489

底蕴价值: 这让 Design Token (设计变量) 的维护变得极其简单。你只需要定义一个主色,其他的交互态颜色、背景色、边框色都可以通过 color-mix 动态计算出来。改一个变量,全站自动换肤。

content-visibility长列表优化

这是一个能让你的网页渲染性能瞬间提升 10 倍的属性,尤其是对于长列表页面(比如新闻流、商品列表)。

痛点: 假设你的页面有 1000 张卡片。即使它们在屏幕外(用户还没滚下去),浏览器默认也会去计算它们的高度、布局和渲染。这会让页面加载变慢,滚动卡顿。

以前的做法: 使用 JavaScript 的“虚拟列表”(Virtual List)技术。非常复杂,要计算滚动位置,动态销毁和创建 DOM。

现代解法: 告诉浏览器:“屏幕外的东西,先别算!”

css
.card-list {
  /* 核心:自动跳过屏幕外元素的渲染工作 */
  content-visibility: auto;
  /* 关键补充:给未渲染的元素占个位 */
  /* 如果不写这个,滚动条会随着加载乱跳(因为浏览器不知道实际高度) */
  contain-intrinsic-size: 1000px; 
}

底蕴价值: 这叫 CSS 级别的懒渲染 (Lazy Rendering)。你不需要写一行 JS,浏览器引擎会自动根据视口可见性来决定是否分配 CPU/GPU 资源。这是构建高性能 Web 应用的基石。

mask-composite (遮罩合成)

以前我们想把两张图叠加,或者在一个形状里挖个洞,通常要找 UI 设计师切好图(PNG/SVG)。但现在,CSS 拥有了类似 Photoshop 的布尔运算能力。

  • 场景: 你想给图片加一个“暗角”,或者把两个形状相减(比如:只有圆环部分显示图片)。
  • 现代解法: 使用 遮罩合成

mask-composite 定义了遮罩层之间如何相互作用。你可以把它想象成 Photoshop 里的“图层混合模式”,但它只管“有”和“无”。

取值 (标准)取值 (-webkit-)逻辑说明 (Boolean Logic)视觉效果
addsource-overA ∪ B (并集)两个遮罩范围加在一起。
subtractsource-outA - B (差集)从第一层里减去第二层的范围。
intersectsource-inA ∩ B (交集)只显示两层重叠的部分。
excludexor(A ∪ B) - (A ∩ B)显示不重叠的部分(重叠处变透明)。
css
.avatar {
  /* 定义两个遮罩层: */
  /* 1. 一个实心的背景图 */
  /* 2. 一个中间的小圆圈 */
  mask-image: 
    url(pattern.png),
    radial-gradient(circle, black 50%, transparent 50%);
  
  /* 核心:定义合成方式 */
  /* subtract = 用第一层 减去 第二层 */
  /* 结果:图片中间被挖空了! */
  mask-composite: subtract; 
  
  /* 兼容性前缀目前还需要写 */
  -webkit-mask-composite: source-out; 
}

image-20260212014713755

mix-blend-mode (混合模式)

以前为了做炫酷的文字特效(比如:文字颜色随背景图片变化,或者文字看起来像镂空的),我们需要切图或者用 SVG。现在 CSS 支持了 Photoshop 里的所有混合模式。

场景: 这是一个非常高级的效果——智能反色文本。 想象一个标题横跨了一张黑白相间的图片。在黑色背景上字要变白,在白色背景上字要变黑。现代解法: difference 模式。

css
.hero-title {
  color: white;
  /* 核心:差值模式 */
  /* 白色 - 黑色背景 = 白色字 */
  /* 白色 - 白色背景 = 黑色字 */
  mix-blend-mode: difference; 
}

mix-blend-mode 的取值很多,但只要掌握了以下三类,你就掌握了 90% 的场景:

模式类别核心代表逻辑说明视觉效果
变暗类multiply (正片叠底)颜色 A × 颜色 B滤掉白色。文字像盖章一样印在背景上。
变亮类screen (滤色)1 - (1-A)×(1-B)滤掉黑色。文字像投影光束一样打在背景上。
对比类overlay / soft-light根据背景深浅自动切换增强对比。文字颜色会根据背景明暗进行“柔光”处理。
反转类difference (差值)**A - B

为什么我设置了混合模式,文字却和背景不发生反应?

原因:混合模式默认只能影响其同级或下方的元素。如果你的背景在一个容器里,而文字在另一个带背景色的容器里,它们可能被隔绝在不同的“层叠上下文”中。

解法:确保参与混合的元素都在同一个渲染层。有时候需要配合 isolation: isolate; 属性来明确定义混合的范围,防止文字不小心把整个页面的颜色都搞乱了。

好炫酷!!!image-20260212015025380

底蕴价值: 这不仅仅是特效,这是动态视觉适配。以前需要极复杂的 Canvas 计算才能做到的像素级颜色处理,现在只要一行 CSS。

介绍

mix-blend-mode属性定义了元素的内容如何与其背景融合。例如,文本<h1>可以以有趣的方式与其背景融合。

image-20260214231816553

value:

价值观

  • initial:该属性的默认设置,不设置混合模式。
  • inherit元素将继承其父元素的混合模式。
  • unset:移除元素当前的混合模式。
  • <blend-mode>这是下方某个混合模式的属性:
  • normal此属性不应用任何混合效果。
  • multiply该元素的颜色会乘以背景色,并替换背景色。最终得到的颜色始终与背景色一样深。
  • screen:将背景和内容相乘,然后对结果进行补充。这将导致内容比背景更亮background-color
  • 叠加:根据背景颜色对内容进行叠加或滤色处理。这与强光混合模式相反。
  • 变暗:当内容颜色较深时,背景将替换为内容颜色;否则,保持原样。
  • lighten背景被替换为内容,内容颜色较浅。
  • color-dodge此属性可提亮背景颜色,使其与内容颜色相呼应。
  • color-burn:这将使背景变暗,以反映内容的自然颜色。
  • hard-light根据内容的颜色,此属性将对其进行筛选或倍增。
  • soft-light根据内容的颜色,这将使其颜色变深或变浅。
  • difference:这是从最浅的颜色中减去两种颜色中较深的那种颜色。
  • exclusion类似difference但对比度较低。
  • hue:根据内容的色调与背景的饱和度和亮度相结合,创建颜色。
  • saturation:根据内容的饱和度以及背景的色调和亮度来创建颜色。
  • color:根据内容的色调和饱和度以及背景的亮度创建颜色。
  • luminosity:根据内容的亮度以及背景的色调和饱和度创建颜色。这是该color属性的逆操作。

在 CSS 中,当你给一个元素设置 mix-blend-mode: multiply(或除 normal 之外的任何值)时,浏览器会自动为该元素创建一个新的堆叠上下文

backdrop-filter (毛玻璃/磨砂)

这是 iOS 和 Windows 11 设计语言的核心(Glassmorphism)。

痛点: 以前想做一个“背景模糊”的半透明导航栏。

  • filter: blur(10px)?不行,那会把导航栏里的文字也模糊掉
  • 以前的做法: 必须用两层背景图,一层清晰,一层模糊,然后绝对定位重叠。非常麻烦且性能差。

现代解法: 滤镜只作用于“背景后面的东西”。

css
.navbar {
  background-color: rgba(255, 255, 255, 0.7); /* 半透明白色 */
  /* 核心:模糊我背后的所有元素 */
  backdrop-filter: blur(10px) saturate(180%);
  /* 必须配合 webkit 前缀,Safari 需要 */
  -webkit-backdrop-filter: blur(10px) saturate(180%);
}

image-20260212015433070

底蕴价值: 这意味着 CSS 开始通过 GPU (图形处理器) 直接介入渲染管线的后处理阶段。它能创造出极具层次感的 UI。

图片裁剪的黑科技:object-view-box

这是一个非常新且神奇的属性,它可以让你缩放/裁剪 <img><video> 的内容,而不改变其容器大小

场景: 用户上传了一张包含全身的人像,但在头像列表里,你只想显示他的“脸部特写”。

以前的做法:

  1. background-imagebackground-position(这不利于 SEO,因为没有 <img> 标签)。
  2. 在外层套一个 divoverflow: hidden,然后把里面的 img 放大并定位(这就多了层 DOM)。

现代解法: 直接操作“视图盒子”。

css
img.avatar {
  width: 100px;
  height: 100px;
  object-fit: cover;
  
  /* 核心:
     只显示原图中:
     上 10%,右 20%,下 10%,左 20% 的区域
     (类似于 viewBox)
  */
  object-view-box: inset(10% 20% 10% 20%); 
  /* 甚至可以做 transition 动画!实现鼠标悬停时镜头拉近的效果 */
  transition: object-view-box 0.5s;
}

img.avatar:hover {
  /* 悬停时,视口变小,相当于镜头放大 */
  object-view-box: inset(25% 35% 25% 35%);
}

底蕴价值: 这赋予了前端工程师**“导演”**的能力。你不再被动接受美术给的图,而是可以在代码里动态决定“镜头的焦距和位置”。

像素艺术的救星:image-rendering: pixelated

在这个高清屏时代,有时候我们需要故意不清晰

场景: 你在做一个复古游戏风格的网页,或者需要放一张二维码图片。

  • 痛点: 当把一张 32x32 的小图放大到 300px 时,浏览器默认会使用“双线性插值”算法,把图片变得模糊、平滑。这对于像素画或二维码来说是灾难(二维码模糊了扫不出来)。

现代解法: 关闭抗锯齿,保留硬边缘。

css
.pixel-art, .qr-code {
  width: 300px;
  /* 核心:告诉浏览器,放大时不要模糊,要保留像素格 */
  image-rendering: pixelated; 
  /* 如果是高清照片想保留锐利度,可以用 crisp-edges (兼容性还在路上) */
}

image-20260212020121647

底蕴价值: 这体现了你对 图形渲染算法 的控制力。你知道什么时候该平滑(照片),什么时候该锐利(图标、二维码、像素画)。

响应式背景图:image-set()

你给 <img> 标签用过 srcset 来做 Retina 屏幕适配,但背景图怎么办?

background-image: url(icon.png);在高分屏(手机、Mac)上,这图糊了。

以前的做法:@media (-webkit-min-device-pixel-ratio: 2),非常啰嗦。

现代解法: CSS 里的 srcset

css
.hero {
  /* 核心:浏览器自动选一张最合适的 */
  background-image: image-set(
    "icon.png" 1x,       /* 普通屏用这张 */
    "icon-2x.png" 2x,    /* 2K 屏用这张 */
    "icon-print.png" 600dpi /* 打印时用这张高清图 */
  );
  
  /* 甚至支持格式协商(比如优先用 avif) */
  background-image: image-set(
    url("bg.avif") type("image/avif"),
    url("bg.jpg") type("image/jpeg")
  );
}

底蕴价值: 这是性能优化视觉体验的平衡。你不需要为了高清屏强迫所有用户下载大图,浏览器会根据网速和设备自己做决定。

overflow-clip-margin

你做了一个卡片(Card),里面有圆角图片。为了圆角生效,你不得不写 overflow: hidden

痛点: 一旦写了 overflow: hidden,卡片外部原本漂亮的 Box Shadow (阴影) 瞬间被切掉了一半(因为阴影算在 overflow 区域外)。

以前的做法: 套两层 div。外层负责阴影,内层负责 overflow: hidden。结构变得很臃肿。

现代解法: 告诉浏览器:“你可以裁剪内容,但请往外多留一点余地”。

css
.card {
  overflow: hidden; /* 必须有这个 */
  border-radius: 10px;
  box-shadow: 0 10px 20px rgba(0,0,0,0.5); /* 很大的阴影 */
  /* 核心:
     裁剪边界向外扩展 20px。
     这样,内部的内容(如图片)会被裁剪,
     但外部的阴影(只要不超过 20px)就能显示出来!
  */
  overflow-clip-margin: 20px;
}

底蕴价值: 这是对 盒模型渲染边界 的精细控制。它解决了“圆角”与“阴影”这对 CSS 里的“世纪冤家”之间的矛盾。

评论

评论加载中……