Fit-to-Width:纯 CSS 让文本撑满宽度
本页建立在 View Timeline 的 animation-timeline: view() 之上。不用 JS 测量、不硬编码任何 font-size,让一行文本自动缩放到正好填满容器宽度。手法出自
Roman Komarov · Fit-to-Width Text:把本为滚动联动设计的 Scroll-Driven Animations 反用成「在样式层读取尺寸比例」的工具——view(inline) 时间线在 entry-crossing 区间的进度,恰好等于容器宽度 ÷ 文本固有宽度,拿它驱动 scale() 即可。整页零脚本:下面的宽度调节用 resize、文本编辑用 contenteditable,缩放全靠 CSS。
本页效果依赖 animation-timeline: view(inline)(Scroll-Driven Animations,需 Chromium 115+)。不支持的浏览器会自动回退为普通 text-overflow: ellipsis,请用 Chrome / Edge 打开以查看真实效果。
1 · 拖右下角改宽度、直接改文字
只缩小、不放大:文本天生比容器宽时被缩放贴合;若文本本就窄于容器,则维持原始字号(scale 封顶 1)。所以容器拉得越窄,字越小,且右边缘始终贴着容器。
2 · 不同长度的多行、同一宽度
每行都是一个独立的 view(inline) subject,各算各的比例,因此字数越少的行字号越大,但所有行的实际渲染宽度一致——这是该手法最直观的展示。
3 · 原理
三个零件合起来,把「尺寸比」算进了样式:
- 其一
overflow: hidden让容器成为 scroll container(有 scrollport,只是不显示滚动条)。 - 其二 文本
inline-size: max-content取固有宽度,通常比容器更宽,于是溢出。 - 其三
scroll-snap-type: both mandatory配scroll-snap-align: start,把滚动偏移钉死在起点。
在这个被钉住的滚动位置上,view(inline) 时间线于 entry-crossing 区间的进度值 = 容器宽度 ÷ 文本固有宽度。
@keyframes 里只写了 from(进度 0 时 scale(0)),to 隐式为元素原状态 scale(1)。于是被钉住位置的进度 p 就把字号缩放成 scale(p),正好等于那个比例。margin-block-end: -1lh
抵消缩放后行盒残留的高度,让垂直节奏不塌;transform-origin: 0 0 保证从左上角缩放、左边缘不漂移。
4 · 核心 CSS
.fit-box { /* 容器 = 隐式 scroll container,滚动钉在起点 */
overflow: hidden;
scroll-snap-type: both mandatory;
font-size: 7rem; /* 够大 → 必定溢出 → 必定缩放 */
}
.fit-box > .line {
inline-size: max-content; /* 文本固有宽度 */
transform-origin: 0 0;
animation: fit-ratio linear;
animation-timeline: view(inline);
animation-range: entry-crossing; /* 进度 = 容器/文本 比例 */
scroll-snap-align: start;
contain: layout;
}
@keyframes fit-ratio {
from { transform: scale(0); margin-block-end: -1lh; }
}
底层机制见本系列 View Timeline。