日历、表格、导航的那条分隔线,你还在给每个子元素挂 border 吗——Chrome 和 Edge 149 把 gap 装饰做进了 CSS
Chrome 和 Edge 从 149 版开始支持一组新的 CSS 属性,专门用来画布局之间的分隔线。它把用了很多年的 column-rule 从多列布局里放出来,同时补了一个 row-rule 管另一个轴。也就是说,以前你要靠 border 和伪元素硬凑的那些线,现在浏览器自己会画。
先说清楚这个功能解决的具体痛点。做日历、数据表格、卡片列表、多列导航的时候,你几乎一定写过这两种代码之一:给每个子元素挂 border-right,然后祈祷最后一个子元素别多出那条线;或者用 ::before 在留白里画一条绝对定位的线,再默默计算容器宽度变了之后它会不会错位。
这两套写法的问题不在丑,而在于——它们把「视觉装饰」和「结构」绑死了。多一个 border 会让盒模型多两像素、多一个伪元素会多一份层叠上下文,屏幕阅读器也可能被多余节点干扰。而且容器一换列数、一换行数,你补的那条线就得跟着重算。
核心:column-rule 和 row-rule
旧写法里唯一能用的官方属性是 column-rule,可它只认多列布局(columns),你把它写进 grid 或 flex 里完全不生效。gap decorations 做的事,就是让同一个属性在所有布局类型里都生效:
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
column-rule: 1px solid #ddd; /* 竖线,画在列间距里 */
row-rule: 1px solid #eee; /* 横线,画在行间距里 */
}
关键特性有三个:
第一,装饰是纯视觉的,不影响布局。它不占空间、不改变 gap 宽度、不触发 reflow 的连锁反应,所以往现有项目里加基本是零风险的。
第二,支持 repeat() 语法。你可以像写 grid 轨道一样,让不同的间距用不同的线,多余的值自动循环。比如日历里每小时用实线、每半小时用虚线:
.calendar {
row-rule-width: 2px, 1px;
row-rule-style: solid, dashed;
row-rule-color: #e8e4df, #f0ece7;
}
第三,有一个 rule 简写,两个轴一起设:
.nav ul {
display: flex;
flex-wrap: wrap;
gap: 2rem;
rule: 2px dashed #666;
}
细粒度控制:交点、端点、层叠顺序
这是这个特性真正有意思的地方,也是它在试验期改过名字的部分。
rule-break 控制装饰在行线和列线交叉处怎么表现:none 表示穿过交点连成一片,intersection 表示在交点处断开。默认值 normal 的行为取决于容器类型。
rule-inset 控制线在间距内两端各缩进多少。它下面还有一组 longhand,让你分开控制不同的端点:
rule-inset-cap:只作用于端点(线碰到容器外边缘的那一头)rule-inset-junction:只作用于交点(横线和竖线交叉的地方)rule-inset-start/rule-inset-end:分别钉住起点和终点
举个例子,页脚链接矩阵想要竖线贯穿、横线两端留白收进去:
.links ul {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1.5rem 2.5rem;
row-rule: 1px solid #c9a96a;
column-rule: 3px solid #6a707a;
rule-overlap: column-over-row; /* 交点处竖线压横线 */
column-rule-inset-cap: 1.75rem; /* 只把竖线的两头收进去 */
}
这里 rule-overlap 也是改过名的,旧名是 gap-rule-paint-order,现在它决定横竖线交叠时谁在上层。还有个 rule-inset: overlap-join 关键字,能让线在拐角处自动接上。
空单元格旁边那条悬空的线
最后一个实用属性是 rule-visibility-items。网格的最后一排如果没填满,默认可能会在空位旁画出一条莫名其妙的线。把它设成 around,浏览器只在至少一侧有内容时才画这条装饰:
.posts {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 3rem;
rule: 2px solid #999;
rule-visibility-items: around;
}
一个必须记住的改名坑
如果你在早期试验版(Chrome 139)就试过这个功能,留神:row-rule-outset 和 column-rule-outset 已经被改名成 row-rule-inset / column-rule-inset,而且语义反转了——以前是往外扩,现在是往内缩。照抄旧文章里的代码,线的位置会正好差一倍。
兼容性与今天能做的
支持情况是 Chrome / Edge 149+,以及同步 149 版本的其他 Chromium 浏览器。Firefox 和 Safari 尚未实现,不过都在标准讨论中,MDN 上也有对应的 polyfill 在开发。
所以上线策略很清楚:把分隔线当渐进增强用。线只在支持的浏览器里出现,不支持就什么都不画,页面布局不会崩——这本来就是这个特性设计的友好之处。如果你必须保证每个浏览器都有线,那就用 polyfill 或保留旧的 border 方案兜底。
三件今天就值得做的事:
- 在项目里搜
border-right/border-bottom专门用来画分隔线的写法,列个清单——这些是 gap decorations 的直接替换目标。 - 挑一个隔离的组件(比如页脚链接网格、日历)先试点,用
@supports (row-rule: 1px solid red)包一层,验证渲染效果。 - 如果清单里有跨行跨列的复杂网格,重点测
rule-break和rule-overlap两个值——交点行为是多列时代从没处理过的场景,也是这个特性最容易出意外的地方。
一条线的写法,从「给元素挂 border 再擦屁股」,变成了「告诉浏览器间距该怎么装饰」。布局和装饰,终于分开了。
评论区
登录后可评论。