[控场AI]
· 7 分钟阅读· 3,982 字

别再用JavaScript了:6个被低估的现代CSS特性

别再用JavaScript了:6个被低估的现代CSS特性

Kevin Powell梳理了六项可完全替代JavaScript的成熟CSS原生特性,涵盖滚动、表单验证、焦点管理与文本框控制。

前端讲师Kevin Powell在视频中指出,开发者习惯用JavaScript解决的许多交互问题,其实早已有稳定的CSS原生方案。文章逐一梳理了六项特性:`scroll-behavior` 配合 `scroll-margin` 实现无遮挡的平滑锚点定位;`scroll-snap-type` 与 `scroll-snap-align` 替代横向滚动吸附脚本;`:user-valid`/`:user-invalid` 解决表单验证的「未触碰即报错」问题;`:focus-visible` 智能区分键盘与鼠标的焦点环显示;`lh` 单位精确控制文本框行数高度;`field-sizing: content` 实现输入框随内容自动增高。这些特性均已在主流浏览器中稳定支持,可直接用于生产环境,能减少代码量、提升性能并改善无障碍体验。

前端开发者常常有个习惯:遇到交互问题就本能地伸手去写JavaScript。但很多场景其实早就有了成熟、浏览器广泛支持的CSS原生方案。知名前端讲师Kevin Powell在其最新视频中,梳理了一批「你还在用JS但完全可以用CSS一两行代码搞定」的功能。这些特性都不是实验性前沿语法,而是已经稳定支持多年、可以放心投入生产的能力。

平滑滚动与滚动定位:告别偏移量计算

最基础也最容易被忽略的是 scroll-behavior: smooth。很多人为锚点跳转的平滑滚动去写JS,实际上一行CSS就够了。真正让人转向JavaScript的痛点,往往是跳转后目标元素被固定导航栏遮挡,于是开始手动计算偏移量。

Kevin给出的解法是给目标元素加上 scroll-margin。比如使用 scroll-margin-block(同时控制上下),跳转到某个区块时就会自动预留出边距,标题不再被顶部导航覆盖。ID可以放在section上,也可以直接放在标题上,效果都一样。

使用CSS scroll-margin实现锚点定位

一个重要的无障碍细节:如果启用平滑滚动,最好用 @media (prefers-reduced-motion) 包裹起来。对于前庭功能敏感、容易晕动的用户,关闭动画后页面会直接跳转,但 scroll-margin 的定位效果依然保留。Kevin强调,scroll-behavior 已经在各大浏览器稳定支持超过四年,:target 更是存在已久,可以放心使用。

prefers-reduced-motion 是一个CSS媒体查询,用于检测用户是否在操作系统层面开启了「减少动态效果」的无障碍选项。前庭功能障碍(Vestibular Disorder)患者对屏幕滚动、视差动画等视觉运动高度敏感,可能引发眩晕或恶心。正确的写法是将所有动画/过渡/平滑滚动默认关闭,仅在用户没有特殊偏好时才开启:@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }。这与「默认开启动画再用媒体查询覆盖关闭」的写法相比,对无障碍更友好,因为它假设用户可能处于敏感状态,而非假设用户一定能承受动效。该媒体查询在所有主流浏览器中已全面支持,是现代CSS无障碍实践的重要组成部分。

滚动吸附:Scroll Snap取代大量JS

横向滚动容器(如卡片轮播、缩略图列表)是JavaScript的重灾区,尤其在做AB测试时能看到大量为吸附效果编写的脚本。CSS的 scroll-snap-type 可以彻底替代这些代码。

它需要两个部分配合才能生效:父容器设置 scroll-snap-type,子元素设置 scroll-snap-align。scroll-snap-type 接受两个值——轴向(inline/block 或 x/y)和吸附强度(mandatory 强制 或 proximity 就近)。Kevin建议根据具体场景两者都试试。对齐方式则很直观,center、start、end 等即可。

设置scroll-snap-align控制吸附对齐

他坦言桌面端鼠标滚动时的吸附体验一般,但在移动端手指滑动时手感极佳。对于Web应用类项目,这是非常值得引入的能力,且浏览器支持同样成熟。

表单验证:用:user-valid替代touched类

表单验证是CSS最被误解的领域。原生的 :valid 和 :invalid 伪类有个致命问题——它们在用户还没输入任何内容时就已经生效。一个设置了 required 的空输入框,一进页面就被标记为「无效」,用户什么都没做就被告知出错,体验糟糕。这正是大家转而用JS监听 blur 事件、手动添加 touched 类的原因。

Kevin推荐改用 :user-valid 和 :user-invalid。这两个伪类只有在用户实际交互过之后才会触发。用户输入姓名后变为有效,密码不满足 minlength 时显示无效并给出原因,全程零JavaScript。甚至可以通过 pattern 属性配合正则表达式做更复杂的校验,比如要求字母和数字混合。

需要澄清的是,Kevin明确表示这不是让你用CSS做全部验证。他的意思是:把CSS当作第一道防线,替代那些监听blur事件的脚本;而当用户提交时,服务端验证绝不能省略。CSS只负责即时的用户反馈体验。

:user-valid 和 :user-invalid 是CSS Selectors Level 4规范引入的伪类,核心语义是「用户已与该字段发生过交互」。具体而言,当用户在输入框中输入内容后离开(触发 blur 事件的时机),或者表单提交失败后,这两个伪类才会激活对应样式。这与React/Vue项目中常见的「touched状态管理」模式在行为上高度对应——过去需要通过JS监听事件、维护组件状态、动态添加CSS类来实现的逻辑,现在浏览器原生承担了这部分职责。目前 :user-valid / :user-invalid 在Chrome 119+、Firefox 88+、Safari 16.5+ 中均已稳定支持,覆盖了绝大多数生产环境的用户群体。pattern 属性则允许开发者通过HTML属性直接声明正则表达式校验规则,与这两个伪类配合时无需任何脚本即可完成复杂格式的实时反馈。

Focus Visible:只给键盘用户显示焦点环

这是个附加技巧而非替代JS。很多开发者因为鼠标点击按钮后出现焦点环而被上级质疑,于是干脆用 outline: none 移除所有焦点样式——这却害了依赖键盘导航的用户。

正确做法是使用 :focus-visible 而非 :focus。浏览器会智能判断交互方式:键盘Tab切换时显示焦点环,鼠标点击时则不显示。这实际上已经是现代浏览器的用户代理默认行为。

用focus-visible替代focus控制焦点环显示

Kevin提醒具体表现会因交互方式和元素类型而异,浏览器在其中做了不少决策,但整体而言 :focus-visible 的支持度已经很好,可以安心使用。

LH单位与Field Sizing:文本框的两个利器

最后两个技巧都关于 textarea。设计师要求文本框「刚好三行高」时,很多人开始靠魔法数字试出高度。可一旦字号调整,之前的数字全部失效,又得重新试。

解决方案是 lh 单位——它代表行高(line-height)。设置 height: 3lh(或更推荐的逻辑属性 min-block-size)后,无论字号如何变化,文本框永远精确保持三行高度,自动伸缩。Kevin称 lh 是被严重低估的单位,用JS计算这类高度的代码量相当可观,而CSS一行搞定。

用min-height配合lh单位设置文本框高度

之所以推荐用 min-height 而非固定 height,是为了配合另一个新特性 field-sizing。当用户输入内容超过容器时希望输入框自动增高——这在过去是个让人头疼的需求,如今用一行 field-sizing: content 即可实现。对于聊天气泡这类需要动态增长的场景非常实用。

需要注意兼容性差异:lh 单位在所有浏览器引擎中已稳定支持约两年半(自当年11月起进入baseline);而 field-sizing 才刚刚在所有引擎中落地三个月左右。Kevin将后者定位为渐进增强的绝佳案例——即便部分浏览器不支持,也不影响核心功能。

lh 单位属于CSS相对长度单位,其值等于该元素当前计算后的 line-height 值。这意味着它会随字体大小、font-family 乃至 line-height 属性的变化而自动更新,无需任何重新计算。与之类似的还有 rlh(相对于根元素的行高)。field-sizing: content 则是一个更新的CSS属性,它让表单元素(textarea、input 等)的尺寸由其内容动态决定,类似于块级元素的自然流尺寸行为。在没有此属性时,实现自动增高的textarea通常需要监听 input 事件,将元素高度先重置为 auto 再读取 scrollHeight 并重新赋值——这是一段经典但脆弱的JavaScript代码。field-sizing 将这一逻辑完全下沉到浏览器渲染层,性能更优且没有闪烁风险。作为渐进增强方案,不支持的浏览器会回退到由 min-height 决定的固定最小高度,核心可用性不受影响。

写在最后

这批特性的共同点是:它们既不前沿也不复杂,却长期被JavaScript方案覆盖。从平滑滚动、滚动吸附,到表单交互反馈、焦点管理,再到文本框尺寸控制,用原生CSS往往只需一两行代码,还能带来更好的性能与无障碍体验。在动手写脚本之前,不妨先问一句:这个功能CSS是不是已经能做了?

分享:

相关推荐