背景:两次失败,数百万罚款风险
作者的一位客户是一家公用事业公司,面临一个大问题:客户要么用网站上老旧的 ASP 表单申请服务,要么走人工流程。人工流程对公司来说成本更高。更糟糕的是,这是一个受监管的垄断行业,如果客户满意度低于 96%,他们可能面临数百万英镑的罚款。
在此之前已有两次失败的(且非常昂贵的)尝试。最近一次是外包团队构建的 React 应用——上线仅 3 天就因客户投诉被紧急撤下。作者看了一眼就说"我们不能接这个东西":加载转圈和全局 JavaScript 状态一塌糊涂、完全不无障碍、图片上传试图用 localStorage(只有 5MB 限制!)。
决策:用 Astro 重构为 HTML-First
作者做了一个大胆的决定:用 Astro 重建,做成 HTML-First 的版本。JavaScript 只在 Web Component 中存在,用于渐进增强——一个没有 JS 也完美运行的网站。
核心理念:
- 这是公共服务
- 应该在每台机器上都能运行
- 应该在网络不佳时也能工作
- 表单数据一旦输入就绝不能丢失
作者受 Terence Eden 的一个故事启发:在伦敦的住房福利办公室,一个年轻人用 PSP 游戏机浏览 GOV.UK 的住房福利页面——那台 PSP 的浏览器极其缓慢,但 GOV.UK 页面是用简单 HTML 写的,即使在垃圾浏览器上也能工作。这就是公共服务网站应有的样子。
技术要求
- 每个表单会话有唯一 ID
- 表单向导每一步都在后端存储已提交数据(包括上传文件)
- 没有 JavaScript 也能完成表单
- 在过时的垃圾浏览器上也能完成
- 满足 WCAG AA 无障碍标准
- JavaScript 和现代 CSS 用于增强体验
表单设计:古老模式的复兴
表单向导的每一步都是独立页面。用户点击"下一步"时表单提交,后端 API 验证后浏览器重定向到下一步。这是古老的 Web 应用模式——因 Remix 而重新流行起来。
表单验证:1KB 的 Web Component
作者用 HTML Web Component 构建了表单验证增强器。它封装在现有 HTML 表单周围,利用 HTML 内置验证并让它看起来更现代。阻止浏览器默认的验证弹窗,改为在 aria-describedby 元素中显示错误。
整个组件不到 1KB。如果 Web Component 失败,回退到浏览器内置验证弹窗;如果那也失败,后端 API 处理验证。
<validation-enhancer>
<form>
<label for="my-email">Email</label>
<input type="email" name="my-email" aria-errormessage="my-email-error" required />
<div id="my-email-error"></div>
<button type="submit">Submit</button>
</form>
</validation-enhancer>
结果:完成表单的人数翻倍
上线后,完成表单的人数翻了一倍。分析团队甚至不知道这些用户从哪来的——因为基于 JavaScript 的分析工具看不到那些因 JS 失败而被挡住的用户。
结语:一个悲伤的尾声
作者离开项目后,接替者被问及这个"总能在无 JS 下工作"的设计时,只说了一句:"但那对我们来说工作量大很多。"
作者的理念:把用户挡在门外——不管是旧浏览器、差网络还是辅助技术用户——是不可接受的。构建一个能在 PSP 上用 3G 网络运行的 Web 应用吧——如果做到了,它将对所有用户有效,30 年后依然有效。