KAIROS.WORKSPACE
技术宇宙 / ONLINE
返回文章列表
前端工程intermediate7 分钟

渐进增强不是口号:把"关掉 JS 也能用"落成检查项

以静态优先博客为例,给出每个交互组件的无 JS 基线设计法——原生表单、真实链接、服务端渲染内容,把渐进增强从信念变成可验收的清单。

#渐进增强#无脚本#SSR#可访问性
排版
字号
行宽
目录 · 5 节

“渐进增强”常被当作装饰性口号:说了,但没人验收。它的可操作定义其实很简单——禁用 JavaScript 后,站点的核心任务是否仍可完成? 本文把它拆成一份能逐条勾选的检查清单,以内容站为例。

基线:无 JS 时,什么必须仍然成立

  1. 所有内容可读:正文由服务端渲染进 HTML,不靠前端 fetch 填充(用 fetch 自取数据再注入 DOM 的做法,JS 一关就是白页——这是“SSR 页面 fetch 自己静态文件”踩坑的孪生问题)。
  2. 导航可用:站内跳转是真实的 <a href>,不是 onclick 里写 router.push。增强脚本可以在点击时拦截走 SPA,但href 本身必须是有效目标
  3. 表单可提交:搜索、订阅、评论用原生 <form action method> 提交到服务端端点,JS 只是把体验升级成“行内反馈”。服务端端点要能独立处理并返回结果页。
  4. 状态可见:收藏、进度这类增强若依赖 JS,无 JS 时应退化为“该功能不显示”,而不是“显示一个坏掉的交互”。

把增强做成“加法”而非“替换”

一个正确的订阅表单是这样分层的:

<form method="post" action="/api/subscribe">
  <input name="email" type="email" required />
  <button type="submit">发送确认邮件</button>
</form>
// 增强:拦截提交,改成 fetch + 行内反馈,失败则回退原生提交
form.addEventListener('submit', async (e) => {
  e.preventDefault();
  try {
    const res = await fetch(form.action, { method: 'POST', headers: {...}, body: ... });
    // 渲染成功/错误到 aria-live 区
  } catch {
    form.submit(); // 网络/payload 失败:退回原生整页流程
  }
});

关键在最后那行 form.submit()——增强路径失败时,交回基线路径,而不是把用户困在一个“点了没反应”的按钮上。渐进增强的精髓不是“有 JS 更好”,而是“JS 挂了的瞬间自动降级回可用态”。

内容渲染的“服务端为准”

静态优先框架(如 Astro)默认把内容构建进 HTML,天然满足基线。风险来自“过度客户端化”:为了动效把整页数据塞进 fetch+useState,等于主动放弃无 JS 基线。判断标准——

  • 内容属于信息(文章、列表、导航)→ 服务端渲染,客户端只加动效;
  • 内容属于即时交互态(输入校验反馈、拖拽结果)→ 才交给客户端。

把第一条守住的站点,JS 全关仍能当文档站用;把第二条误当第一条的站点,JS 一挂就白屏。

验收:一份可勾选的清单

每个交互组件上线前,在 DevTools 禁用 JS 逐条验证:

  • 页面主体内容显示完整,无空白占位区
  • 每个导航项是可回车跳转的真实链接
  • 每个表单能用原生提交得到一个正确结果页
  • 报错路径不依赖 JS 才能看到提示(服务端渲染的错误页存在)
  • 关键 SEO 文本(标题/描述/正文)在 view-source 里可见,非 JS 注入

这份清单跑通,“渐进增强”就从信念变成了可回归的工程事实。

小结

真正的健壮不是“什么都能用”,而是“最坏情况下仍能用”。把无 JS 基线设成验收项,你同时赚到的还有:搜索引擎友好、无障碍友好、弱网友好、以及“某个脚本 404 了全站不崩”的韧性。渐进增强从来不是怀旧,是用最便宜的方式买最贵的保险。

Conversation

评论与互动

正在加载评论…

提交后需审核,不会立即公开。

Keep exploring

继续探索