从 Java 转向网页开发后,最直接的惊喜是反馈速度。保存 HTML,刷新浏览器,文字和布局马上出现。相比等待编译,这种即时反馈让学习更像在搭建一个可以触摸的东西。

第一张完整页面包含导航、文章列表和一个表单。它能运行,却没有结构:大量 div 混在一起,样式写在标签里,JavaScript 通过层层父子节点寻找元素。新增一个模块,原有选择器就可能失效。

最先坏掉的是表单错误提示。我把脚本写成了“找到表单第二个 div,把它改成红色”。设计调整字段顺序后,脚本仍然运行,只是把帮助文字标红了。修复它时,我第一次给行为建立了独立契约:

<form data-newsletter-form novalidate>
  <label for="email">邮箱</label>
  <input id="email" name="email" type="email" aria-describedby="email-error" />
  <p id="email-error" data-error aria-live="polite"></p>
  <button type="submit">订阅</button>
</form>
const form = document.querySelector("[data-newsletter-form]");
const email = form.elements.namedItem("email");
const error = form.querySelector("[data-error]");
 
form.addEventListener("submit", (event) => {
  event.preventDefault();
  const message = email.validity.valid ? "" : "请输入有效邮箱";
  error.textContent = message;
  email.setAttribute("aria-invalid", String(Boolean(message)));
  if (!message) form.submit();
});

这里的 data-* 不是为了多写属性,而是把脚本依赖和视觉类名分开;aria-live 则让我意识到页面反馈不能只靠颜色。一个很小的表单,已经同时包含结构、行为、可访问性和浏览器约束。

三层不是三个文件

把 HTML、CSS 和 JavaScript 分开并不会自动得到清晰结构。真正的分离是让每一层承担明确责任:HTML 表达内容关系,CSS 管理视觉规则,JavaScript 处理状态与交互。

例如一个错误提示,应当在结构上属于表单,在样式上有独立状态,在行为上由验证结果驱动。如果 JavaScript 直接写颜色和位置,规则便散落在三个地方。

DOM 是一份公共契约

页面结构同时被样式和脚本依赖。随意修改类名,看似只是视觉调整,也可能破坏行为。后来我开始为行为使用独立标记,不让样式选择器承担脚本契约,并尽量减少依赖层级关系的查询。

浏览器开发的门槛很低,但它不会替开发者管理复杂度。一个页面从几十行长到几千行时,早期那些看似无关紧要的边界会突然变得昂贵。

我当时给自己定了三个检查问题,每做完一块页面就走一遍:

  1. 删除 CSS 后,HTML 的阅读顺序是否仍然成立。
  2. 改动视觉类名,JavaScript 是否还会工作。
  3. 只用键盘,能否完成表单和导航。

它们比“在我的浏览器里看起来一样”严格得多,也让我开始把浏览器当运行时,而不是画布。

浏览器差异是真实约束

同一个页面在不同浏览器中出现偏差时,我最初会继续添加覆盖样式。后来才明白应该先确认标准行为、默认样式和兼容范围。渐进增强比追求所有环境像素一致更实际:核心内容和操作先可用,较新的能力再按支持情况加入。

这也让我第一次体会到 Web 的开放性。页面不运行在受控机器上,字体、屏幕、网络和输入方式都可能不同。前端不是为一张截图编码,而是为一组无法完全预测的环境建立有弹性的规则。

第一次完成页面让我确认自己喜欢这种工作:不仅写逻辑,也直接面对使用者看到和感受到的结果。工程与体验在浏览器里几乎没有距离。

一张可交付网页的内容、交互和运行环境三层结构

图:页面能显示只是第一层,资源失败和键盘操作同样属于交付结果。

第一张页面的交付清单

我后来把当时反复遗漏的事情写成六项:禁用 CSS 后内容顺序仍可读;所有图片有尺寸和替代文本;键盘能走完主要操作;网络失败有明确状态;375px 宽度没有整页溢出;控制台没有未处理错误。

这个清单没有设计系统那么完整,却把“我电脑上看起来正常”变成了可重复验收。对初学者而言,先稳定交付一张小页面,比一次引入更多框架更能建立工程直觉。