Highlight
Safari 今年在 CSS 领域新增了 Masonry 布局预览、margin-trim、OKLCH/LCH/OKLAB/LAB 颜色函数、color-mix()、relative color 语法、:user-valid/:user-invalid 伪类、font-size-adjust、lh/rlh 单位和 @counter-style,让布局更简洁、颜色更丰富、表单更友好、排版更精准。
核心内容
布局:Masonry 和 margin-trim
瀑布流(Masonry)布局在网页中很常见,尤其适合展示不同高度的内容卡片。以前实现这种布局要么用 CSS Multicolumn(内容按列纵向流动),要么用 JavaScript 库。但 Multicolumn 的内容顺序是纵向的,不符合大多数设计需求;JavaScript 方案则比 CSS 慢且脆弱。
Safari Technology Preview 中预览了 Masonry Layout,作为 CSS Grid 的扩展。只需一行 grid-template-rows: masonry,就能让 Grid 在保持列定义的同时,将物品按行方向紧密排列。
(01:15)
与 JavaScript 库不同,Masonry 与 Grid 的结合让你可以在一维上做 Masonry,在另一维上自由使用 Grid 的全部能力:fr 单位、minmax()、固定宽度列等。
margin-trim 是另一个解决常见痛点的新属性。容器内的子元素通常有上下 margin,这些 margin 会与容器的 padding 叠加,导致顶部和底部的空白比预期大。以前的做法是手动移除第一个子元素的 top margin 和最后一个子元素的 bottom margin,但这很脆弱——内容变化时容易出问题。
margin-trim: block 让容器自动修剪与容器边缘接触的 margin。Safari 16.4 已支持,也可以用 margin-trim: inline 处理水平方向。
(03:58)
颜色:突破 sRGB 限制
sRGB 色域只能表示人类可见颜色的一部分。Display P3 能多显示 50% 的颜色,Apple 从 2015 年的 iMac 开始就在硬件和软件上支持 P3。
CSS 新增了四个颜色函数突破 sRGB 限制:
- LCH 和 OKLCH:基于亮度(Lightness)、色度(Chroma)、色相(Hue)
- LAB 和 OKLAB:基于亮度、绿-红轴(A)、蓝-黄轴(B)
这些模型是感知均匀的,可以表示任何色域的颜色,包括 Display P3 和未来可能出现的新色域。Safari 15.0/15.4 已支持,Chrome、Edge、Firefox 今年也在 Interop 2023 项目中加入支持。
(06:51)
Relative Color Syntax 允许基于现有颜色派生新颜色:
/* 基于蓝色创建 70% 不透明度的版本 */
rgb(from blue r g b / 0.7)
/* 基于 LAB 颜色,亮度减半 */
lab(from var(--brand-color) calc(l / 2) a b)
/* 基于 OKLCH 颜色,色度降低三分之一 */
oklch(from var(--accent) l calc(c / 3) h)
color-mix() 函数可以在指定颜色空间中混合两个颜色,默认 50/50 比例,也可以自定义:
color-mix(in oklab, white, blue)
color-mix(in oklch, white 30%, blue 30%) /* 结果有 60% 不透明度 */
渐变和颜色动画也可以指定颜色空间了。同样的白到蓝渐变,在 sRGB 中过渡偏紫,在 OKLAB 中更偏蓝,在 OKLCH 中经过黄绿青色的过渡。选择哪种取决于设计效果。
(10:23)
伪类:更智能的表单验证
:valid 和 :invalid 伪类有个长期困扰:页面加载时空字段就被标记为 invalid,用户还没开始输入就看到错误提示。
:user-valid 和 :user-invalid 用更复杂的算法判断何时显示验证状态。用户离开字段后才显示错误提示,不会在输入过程中打扰用户。Safari 16.5 已支持。
(16:55)
:has() 今年也增强了,支持更多伪类组合::has(:lang()) 可以根据页面中是否存在特定语言来应用样式;:has() 也支持媒体伪类,可以根据音视频播放状态做条件样式。
:dir() 伪类填补了语言方向支持的空白。配合逻辑属性(如 margin-inline-start),可以轻松写出同时支持 LTR 和 RTL 的 CSS。
(18:14)
排版:精准控制字体
lh 和 rlh 单位:1lh 等于当前元素的行高,1rlh 等于根元素的行高。这让布局中的间距可以与文字行高保持整数倍关系,建立垂直节奏(vertical rhythm)。
(20:18)
font-size-adjust:不同字体在相同字号下视觉大小可能差异很大。font-size-adjust 让浏览器根据字体的 x-height 比例自动调整视觉大小,使字体栈中的备选字体看起来一致。
Safari 16.4 支持基础用法(font-size-adjust: 0.47),Safari 17 增加了 from-font 值(让浏览器自动计算)和双值语法(可以选择用 cap-height、ch-width、ic-width 或 ic-height 作为调整基准)。
(22:25)
text-box-trim(预览):修剪文本框中字体预留的额外空间,解决垂直居中对齐不准的问题。这个属性还在演进中,属性名已经从 leading-trim 改为 text-box-trim,细节可能继续变化。
(26:42)
@counter-style:自定义计数器样式。可以定义任何计数系统,比如塞尔维亚-克罗地亚字母、二进制计数、循环 emoji 等。W3C 提供了数百种预制计数样式可以直接复制使用。
(28:53)
详细内容
Masonry Layout 与 Grid 结合
/* 基础瀑布流:自动填充列 */
main {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
grid-template-rows: masonry;
gap: 1rem;
}
/* 不同宽度的列 */
main {
display: grid;
grid-template-columns: 1fr 2fr 3fr;
grid-template-rows: masonry;
gap: 1rem;
}
/* 固定 + 弹性 + minmax 组合 */
main {
display: grid;
grid-template-columns: 10rem 1fr minmax(100px, 300px);
grid-template-rows: masonry;
gap: 1rem;
}
关键点:
grid-template-rows: masonry开启瀑布流模式(行方向排列)grid-template-columns定义列,可以使用 Grid 的所有功能- 物品按行方向排列,每个物品放在能使整体高度最小的列中
- 目前仅在 Safari Technology Preview 中可用
- 属于 CSS Grid 规范的一部分,不是独立的布局机制
margin-trim 解决容器边缘 margin 叠加
/* 以前的做法:手动移除边缘 margin */
.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }
/* 现在的做法:一行代码自动修剪 */
.card {
background-color: #fcf5e7;
padding: 2rlh;
margin-trim: block;
}
.card h2, .card p {
margin: 1rlh 0;
}
关键点:
margin-trim: block修剪垂直方向(block 轴)上与容器边缘接触的 marginmargin-trim: inline修剪水平方向(inline 轴)- 不需要知道第一个/最后一个子元素是什么类型
- 内容动态变化时自动适应
- Safari 16.4 已支持
宽色域颜色定义
/* sRGB 颜色(传统方式) */
.brand-red {
color: #ff0000;
color: rgb(255, 0, 0);
color: hsl(0, 100%, 50%);
}
/* Display P3 颜色 */
.brand-red-p3 {
color: color(display-p3 1 0 0);
}
/* OKLCH:感知均匀的颜色模型 */
.brand-red-oklch {
color: oklch(62.8% 0.257 29.2);
}
/* 条件应用 P3 颜色 */
@media (color-gamut: p3) {
.brand-red {
color: color(display-p3 1 0 0);
}
}
关键点:
color(display-p3 1 0 0)定义纯红色,在 P3 显示器上比 sRGB 的红色更鲜艳oklch(62.8% 0.257 29.2)用感知均匀的模型定义颜色@media (color-gamut: p3)检测设备是否支持 P3 色域- 渐进增强策略:sRGB 设备看到常规颜色,P3 设备看到更丰富的颜色
Relative Color Syntax
:root {
--brand-blue: oklch(50% 0.2 250);
}
/* 基于品牌色创建变体 */
.brand-blue-light {
color: oklch(from var(--brand-blue) calc(l + 20%) c h);
}
.brand-blue-dark {
color: oklch(from var(--brand-blue) calc(l - 15%) c h);
}
.brand-blue-transparent {
color: oklch(from var(--brand-blue) l c h / 0.5);
}
/* 混合当前文字颜色 */
a:hover {
color: color-mix(in oklab, currentColor 60%, white);
}
关键点:
from var(--brand-blue)指定基准颜色calc(l + 20%)调整亮度通道,创建更亮的变体c和h保持不变表示继承原色的色度和色相/ 0.5设置透明度color-mix(in oklab, currentColor 60%, white)将当前文字色与白色混合
渐变颜色空间对比
/* sRGB 渐变:过渡偏紫 */
.gradient-srgb {
background: linear-gradient(in srgb, white, blue);
}
/* OKLAB 渐变:更自然的蓝色过渡 */
.gradient-oklab {
background: linear-gradient(in oklab, white, blue);
}
/* OKLCH 渐变:经过黄绿青色 */
.gradient-oklch {
background: linear-gradient(in oklch, white, blue);
}
/* LCH 渐变:类似 OKLCH 但略有不同 */
.gradient-lch {
background: linear-gradient(in lch, white, blue);
}
关键点:
in srgb显式指定在 sRGB 颜色空间中计算渐变in oklab在 OKLAB 空间中计算,过渡更自然- 不同颜色空间产生不同的中间色,没有绝对的对错
- 选择取决于设计需求和预期的视觉效果
表单验证伪类
/* 以前的做法::invalid 在页面加载时就显示错误 */
.form-group:has(input:invalid) label::before {
content: "✗ ";
color: red;
}
/* 现在的做法::user-invalid 只在用户交互后显示 */
.form-group:has(input:user-invalid) label::before {
content: "✗ ";
color: red;
}
.form-group:has(input:user-valid) label::before {
content: "✓ ";
color: green;
}
/* 配合 :has() 的完整表单样式 */
input:user-invalid {
border-color: #dc2626;
background-color: #fef2f2;
}
input:user-valid {
border-color: #16a34a;
background-color: #f0fdf4;
}
关键点:
:user-invalid在用户离开字段且内容无效时触发:user-valid在用户正确填写后触发- 不会在页面加载时或用户输入过程中显示错误
- 与
:has()结合可以样式化包含无效输入的父元素 - Safari 16.5 已支持
font-size-adjust 统一视觉大小
/* 基础用法:指定 x-height 比例 */
article {
font-family: "Iowan Old Style", Georgia, serif;
font-size-adjust: 0.47;
}
article code {
font-family: "SF Mono", Courier, monospace;
/* 浏览器自动调整,使 x-height 匹配 0.47 */
}
/* Safari 17:from-font 自动计算 */
article {
font-size-adjust: from-font;
}
/* Safari 17:双值语法,使用 cap-height */
article {
font-size-adjust: cap-height from-font;
}
关键点:
font-size-adjust: 0.47让所有字体的 x-height 等于指定 font-size 的 47%from-font让浏览器自动计算主字体的比例- 双值语法可以选择
ex-height(默认)、cap-height、ch-width、ic-width、ic-height - 解决字体栈中备选字体视觉大小不一致的问题
- Safari 16.4 支持基础用法,Safari 17 支持高级用法
@counter-style 自定义计数器
/* 定义塞尔维亚-克罗地亚字母计数 */
@counter-style serbo-croatian {
system: alphabetic;
symbols: "A" "B" "V" "G" "D" "Đ" "E" "Ž" "Z" "I" "J" "K" "L" "Lj" "M" "N" "Nj" "O" "P" "R" "S" "T" "Ć" "U" "F" "H" "C" "Č" "Dž" "Š";
}
ol.serbian {
list-style: serbo-croatian;
}
/* 二进制计数 */
@counter-style binary {
system: numeric;
symbols: "0" "1";
pad: 4 "0";
}
ol.binary {
list-style: binary;
}
/* 循环 emoji */
@counter-style emoji-cycle {
system: cyclic;
symbols: "🐶" "🐱" "🐰";
}
ol.pets {
list-style: emoji-cycle;
}
/* 用于标题编号 */
@counter-style section-number {
system: numeric;
symbols: "〇" "一" "二" "三" "四" "五" "六" "七" "八" "九" "十";
}
h2 {
counter-increment: section;
}
h2::before {
content: counter(section, section-number) ". ";
}
关键点:
@counter-style定义自定义计数器样式system指定计数系统类型:alphabetic、numeric、cyclic等symbols列出计数使用的符号pad设置最小位数和填充字符- 可以用在
list-style和counter()函数中 - W3C 提供了数百种预制计数样式
核心启发
1. 用 margin-trim 替代手动边缘 margin 清理
- 做什么:在卡片、文章容器等组件中使用
margin-trim: block自动修剪边缘 margin - 为什么值得做:消除手动
:first-child/:last-child规则的维护负担,内容变化时自动适应 - 怎么开始:找到项目中所有手动清理边缘 margin 的 CSS,替换为
margin-trim: block或margin-trim: inline
2. 用 OKLCH 构建设计系统的调色板
- 做什么:将设计系统的颜色从 HEX/HSL 迁移到 OKLCH,用 Relative Color Syntax 生成变体
- 为什么值得做:OKLCH 是感知均匀的,亮度调整(
calc(l + 20%))在不同色相上产生一致的视觉变化,暗色模式适配更自然 - 怎么开始:定义一组基础 OKLCH 颜色,用
oklch(from ...)语法生成亮/暗/透明变体,用@media (color-gamut: p3)为支持设备提供更鲜艳的颜色
3. 用 :user-invalid 改进表单体验
- 做什么:将表单验证样式从
:invalid迁移到:user-invalid - 为什么值得做:用户不会在开始输入时就看到错误提示,只在离开字段且内容有误时显示
- 怎么开始:全局搜索
:invalid伪类,在表单相关场景中替换为:user-invalid,配合:has(input:user-invalid)样式化父元素
4. 用 font-size-adjust 统一代码块的视觉大小
- 做什么:为包含等宽字体的区域添加
font-size-adjust,使代码与正文视觉大小一致 - 为什么值得做:等宽字体通常比正文字体小,导致代码看起来”缩进去”了
- 怎么开始:在
code、pre选择器或包含代码的父元素上添加font-size-adjust: from-font(Safari 17)或手动计算合适的比例值
5. 用 @counter-style 实现本地化列表编号
- 做什么:为不同语言的内容定义对应的计数器样式
- 为什么值得做:默认的 western Arabic 数字不适合所有语言场景,自定义计数器让列表编号符合当地习惯
- 怎么开始:从 W3C 的 Ready-made Counter Styles 文档中复制需要的样式定义,用
@counter-style引入项目,在对应语言的列表中应用
关联 Session
- What’s new in Web Inspector — Safari Web Inspector 的新调试功能
- Rediscover Safari developer features — Safari 开发者功能的全面更新
- What’s new in web apps — Web App 在 macOS 和 iOS 上的新能力
- What’s new in Safari extensions — Safari 扩展的新 API 和功能
- Explore media formats for the web — Safari 和 WebKit 的新图像格式和视频技术
评论
GitHub Issues · utterances