还在手撸JS解决样式问题?这波CSS新特性,真的用对了吗?

2,991字
13–19 分钟
in

CSS 世界最近可是热闹得很,新特性像下饺子一样往外冒,光看浏览器更新日志都能把人看花眼。但话说回来,新东西学了一堆,真到写页面的时候,是不是还在用老一套的 JavaScript 去硬刚那些本来 CSS 就能搞定的样式难题?这期咱们就扒一扒最近那些值得关注的 CSS 和 HTML 硬核更新,顺便聊聊怎么换个思路,用更优雅的写法来解决问题。

目录

搞定老顽固样式

让文本断字更聪明

有些词断得是真尴尬,比如英文单词“lighter”,要是断成了“light-er”,不仅看着别扭,还容易让人理解跑偏。现在 CSS 里有个属性叫 hyphenate-limit-chars,虽然 Safari 还在磨蹭没支持,但在其他浏览器里已经能派上用场了。这个属性可以设置连字符两边至少保留多少个字符,比如想让“lighter”变成“light-er”,而不是“ligh-ter”,就可以设置 hyphenate-limit-chars: 4 2 1,意思就是整个单词至少4个字符才断,断点前至少2个字符,断点后至少1个字符。这样一来,那些看着难受的断字情况就能大大减少。

用CSS解决弹窗按钮交互

以前要实现点击按钮弹出对话框,第一反应是不是写一堆 addEventListener 去控制 dialog 元素的 showModal?现在根本不用这么麻烦。新出的 commandcommandfor 属性直接让按钮和弹窗“锁死”,写个 command="show-modal"commandfor="myDialog",再把 commandfor 的值指向弹窗的 id,一个纯 HTML 的交互弹窗就成了。这俩属性现在已经是所有浏览器都支持的状态,算是今年最实用的 HTML 功能之一了。

实际操刀改代码

举个栗子,想象一下现在要搞一个点击就弹出的提示框。以前的方式是:

<dialog id="tipDialog">
  <p>这是新消息提示</p>
  <button onclick="this.closest('dialog').close()">关掉</button>
</dialog>
<button onclick="document.getElementById('tipDialog').showModal()">点我</button>

现在完全可以换成:

<dialog id="tipDialog">
  <p>这是新消息提示</p>
  <button commandfor="tipDialog" command="close">关掉</button>
</dialog>
<button commandfor="tipDialog" command="show-modal">点我</button>

看着是不是清爽多了?不用在 JS 里折腾那些 DOM 操作,HTML 自己就把活干了。

浏览器悄悄上的新硬菜

Chrome 143的新动作

Chrome 143 这次把锚点容器查询(Anchored container queries)给整上了。这玩意儿干啥用的?简单说就是让一个元素可以根据另一个元素的位置和大小来动态调整自己的布局。以前要实现一个悬浮菜单,还得用 JS 去实时计算位置,现在直接 CSS 搞定。

实现随动菜单

比如说页面上有个按钮,想让一个提示框始终贴着它右边出现,如果右边空间不够,就自动贴左边。传统做法得监听窗口大小变化,用 getBoundingClientRect 算来算去。现在可以这么玩:

.anchor-button {
  anchor-name: --myBtn;
}

.tooltip {
  position: fixed;
  position-area: right;
  position-try-fallbacks: left;
}

把按钮通过 anchor-name 标记为一个锚点,提示框用 position-area 直接定位到它右边,再用 position-try-fallbacks 给个备选方案左边。一旦右边空间不够,CSS 会自动切换到左边,全程不需要 JS 介入。

Firefox 146的新鲜事

Firefox 这次更新里,有几个东西特别值得拿出来说说。一个是 @scope 规则,这货让 CSS 的作用域控制不再是痛点。以前写样式,最怕的就是类名冲突和样式污染,现在用 @scope 可以把一组样式圈定在某个 DOM 范围内,出了这个圈子样式就不生效,维护起来省心多了。

还有一个是 contrast-color() 函数,虽然它目前还是半成品状态,但未来能根据背景色自动选择黑或白的文字颜色,做主题切换的时候再也不用自己写一堆判断逻辑。

搞定组件样式隔离

假设写一个卡片组件,怕内部的 .title 样式影响到外面其他同名的类。以前要么加很长的类名前缀,要么用 CSS Modules 这种构建工具。现在直接:

@scope (.card-component) {
  .title {
    font-size: 1.5rem;
    color: #333;
  }
}

.card-component 里面的 .title 只会作用于这个组件内部,外界的 .title 纹丝不动。这样一来,组件库的样式维护直接降低好几个难度等级。

Safari 26.2的独家技能

Safari 这次带来的 random() 函数有点意思,能在 CSS 里直接生成随机数。虽然目前只有 Safari 支持,但用来做那些无伤大雅的装饰效果,比如随机位置的飘浮动画,完全可以先用着,其他浏览器降级处理就好。

另外 sibling-index()sibling-count() 这俩函数,可以在 CSS 里拿到元素在同级中的位置和总数量。做那种根据元素数量变化布局的组件,比如导航菜单,如果超过五个就换行显示,现在用 CSS 就能拿到数量,不用再让 JS 去数。

给元素加点随机个性

做个加载占位图,想让每个条纹的宽度随机一点,显得不那么呆板。可以这样:

.loading-stripe {
  width: calc(20px + (random() * 30px));
}

每个 .loading-stripe 元素的宽度都会是 20px 到 50px 之间的一个随机值,视觉上立马就灵动起来了。这要是搁以前,得用 JS 循环生成一堆内联样式,现在一行 CSS 搞定。

颜色格式该选哪个

现代格式的优势

现在 CSS 里颜色格式多得让人眼花缭乱,什么 rgbhexhsllaboklch 一大堆。之前一直在用 hsl,但后来发现 oklch 更符合人眼的感知,调整亮度和色度的时候颜色不会偏得离谱。而且像 Figma 这种设计工具对 oklch 的支持也越来越好。所以现在写颜色的时候,可以优先考虑用 oklch,它的语法是 oklch(亮度 色度 色相),比如 oklch(70% 0.15 250) 就是一个很柔和的蓝色。用这个格式做主题切换,调整亮度值就能让所有颜色整体变亮或变暗,比在 hsl 里调饱和度来得直观多了。

搞定暗色模式颜色

想给一套颜色适配暗色模式,不需要重新定义一堆新变量,直接改亮度就行。比如定义一套主题色:

:root {
  --primary: oklch(65% 0.18 260);
  --secondary: oklch(70% 0.12 180);
}

@media (prefers-color-scheme: dark) {
  :root {
    --primary: oklch(75% 0.18 260);
    --secondary: oklch(80% 0.12 180);
  }
}

在暗色模式下,只需要把亮度值提高一些,就能保证颜色在深色背景上依然有足够的对比度,而且不会出现色相偏移的问题。