HTML First

99 阅读6分钟

目标

HTML First 的主要目标是 “大大扩大可以在网络软件代码库上工作的人员规模”。这从个人层面讲好,因为它使更多人能成为网络程序员,构建出色的网络软件,增加收入。从业务角度看也好,因为它降低了软件构建成本,减少了招聘所需的资源数量 —— 这是一个以资源密集而闻名的过程。

HTML First 的第二个目标是使构建网络软件的过程更加流畅和无缝。大多数网络程序员都熟悉从文本编辑器快速过渡到浏览器的激动人心,几乎没有意外的困难或切换上下文。但是要掌握工具和框架,现在需要数年时间。HTML First 的原则应该让人们在编码历程的更早阶段就解锁这种感觉和掌握的水平。

我们实现这些目标的方法是,承认 HTML 很容易理解,因此将 HTML 作为我们产品的基石 —— 不仅用于定义内容和结构,还用于设置样式和行为。

【第2960期】原生 popover 终于要来了!

原则

  • 更倾向于使用原生 HTML/CSS 方法
  • 使用 HTML 属性设置样式和行为
  • 使用利用 HTML 属性的库
  • 避免构建步骤
  • 更倾向于使用纯 HTML
  • 对 “查看源代码” 更友好

优先使用原生 HTML/CSS 方法实现需求,不使用外部框架

浏览器自带支持的功能非常多,而且在持续增加。在添加库或框架到代码库之前,请检查是否可以使用纯 HTML/CSS 实现。

鼓励使用这种方法

 <details>
   <summary>Click to toggle content</summary>
   <p>This is the full content that is revealed when a user clicks on the summary</p>
 </details>

不鼓励

 import React, { useState } from 'react';

 const DetailsComponent = () => {
   const [isContentVisible, setContentVisible] = useState(false);

   const toggleContent = () => {
     setContentVisible(!isContentVisible);
   };

   return (
     <details>
       <summary onClick={toggleContent}>Click to toggle content</summary>
       {isContentVisible && <p>This is the full content that is revealed when a user clicks on the summary</p>}
     </details>
   );
 };

 export default DetailsComponent;

在可能的情况下,默认使用内联 HTML 属性来定义样式和行为

对于样式,可以使用 Tailwind、Tachyons 等样式组件类库来实现这一点。对于行为,可以使用 hyperscript、Alpine 或类似的库。是的,这意味着你的 HTML 会看起来很复杂。但是这也意味着其他开发人员更容易找到和理解行为,浏览它并做出修改。

鼓励

 <button onclick="this.classList.add('bg-green')">
   Click Me
 </button>

不鼓励

 <div id="results-pane">
   Click Me
 </div>
 #results-pane.active {
   background-color: green;
 }
 var resultsPane = document.getElementById("results-pane");
 resultsPane.addEventListener("click", function() {
     this.classList.add("active");
 });

您可能会注意到,这种方法看起来违反了关注点分离 —— 一种最常被吹捧的软件设计原则。我们认为关注点分离的非黑即白方法是有问题的。相反,我们倡导一种平衡行为局部性和两者间权衡关系的方法。

  • HTMX 对行为局部性原则的解释
  • Adam Wathan 对样式关注点分离的理解

如果必须使用库,优先选择利用 html 属性的库,而不是基于 JavaScript 或自定义语法构建的库

鼓励

 <script src="https://unpkg.com/hyperscript@0.0.7/dist/hyperscript.min.js"></script>
 <div>
   <input type="text" _="on input put me into #output">
   <div id="output"></div>
 </div>

不鼓励

 <script src="https://cdn.jsdelivr.net/npm/stimulus@2.0.0/dist/stimulus.umd.js"></script>

 <div data-controller="echo">
   <input type="text" data-echo-target="source" data-action="input->echo#update">
   <div data-echo-target="output"></div>
 </div>

 <script>
   const application = Stimulus.Application.start();

   application.register("echo", class extends Stimulus.Controller {
       static targets = ["source", "output"]

       update() {
           this.outputTarget.textContent = this.sourceTarget.value;
       }
   });
 </script>

避免使用构建步骤

需要将文件从一种格式转换为另一种格式的库会带来大量的维护开销,移除或严重削弱 “查看源代码” 的能力,并通常要求开发人员学习新工具才能使用它们。当这些做法被引入时,现代浏览器没有过去那些性能限制。而且,如果我们使用 HTML First 的库 (如静态 Tailwind 或 HTMX), 通常只需要很少的额外 CSS 和 JS。

鼓励

 <link rel="stylesheet" href="/styles.css">

不鼓励

 <link href="/dist/output.css" rel="stylesheet">
 npx css-compile -i ./src/input.css -o ./dist/output.css --watch

附注:构建步骤的做法已经深深扎根,以至于一年前这种意见还被认为是极端的。但在过去的一年中,它开始获得重要关注。一些最近的例子:

  • @dhh - “我们的 CSS 在 37signals 上已经实现了 #NoBuild”
  • Chris Ferdinandi - 构建工具是一种反模式吗
  • 构建工具如何破坏向后兼容性
  • Blake Watson - “现在是抛弃构建步骤的最佳时机”

更倾向于使用 “裸” HTML 而不是编译为 HTML 的混淆层

这一原则最适用的场景是后端实现。这里的基本思想同样是可读性。即使开发人员只熟悉 HTML 而不熟悉你的后端框架,在查看视图文件时也应能理解 90% 以上的内容。如上所述,这意味着牺牲简洁性以换取可理解性。

鼓励

 <form action="<%= new_signup_path %>" method="post">
   <div class="field">
     <label for="first_name">First Name</label>
     <input id="first_name" type="text" value="<%= @signup&.first_name %>" />
   </div>
   <div class="field">
     <label for="last_name">Last Name</label>
     <input id="last_name" type="text" value="<%= @signup&.last_name %>" />
   </div>
   <div class="field">
     <label for="email">Last Name</label>
     <input id="email" type="text" value="<%= @signup&.email %>" />
   </div>
 </form>

不鼓励

 <%= form_with url: "#", local: true do |form| %>
   <div class="field">
     <%= form.label :first_name %>
     <%= form.text_field :first_name %>
   </div>

   <div class="field">
     <%= form.label :last_name %>
     <%= form.text_field :last_name %>
   </div>

   <div class="field">
     <%= form.label :email %>
     <%= form.email_field :email %>
   </div>

   <div class="actions">
     <%= form.submit %>
   </div>
 <% end %>

在可能的情况下,保持 “右键查看源代码” 的能力

早期网络之美在于,你总能 “偷窥幕后”, 查看负责任何网页任何部分的代码。对于抱负的开发者来说,这是件大礼,因为它让我们能够在理论 (关于代码运作的学习) 和实践之间建立桥梁 —— 同时查看代码和界面。对许多网站,我们可以复制粘贴 HTML 或 CSS, 在本地运行来获得近似相同的副本。“重组” 现有代码不仅是一种学习方式,而且通常构成我们新创作的基础。

自那以后,该行业采纳了几项 “改进”, 使这种做法更加罕见。例如,如果我们使用 React (最流行的前端框架), 点击 “查看源代码”、复制代码并重组是不行的,因为 1. React 有构建步骤,我们在开发者工具中看到的代码与开发者编写的不同;2. React 代码必须打包在 React 应用中才能工作。

对于遵循 HTML First 原则的网站,我们重新获得了 “查看源代码” 的能力。事实上,HTML First 的网站通常会更进一步。如果您使用 HTML 属性定义用户界面交互,那么在将内容复制粘贴到新代码库时,可以保留这些交互 (前提是目标文件包含相同的 JS 库)。在将来的某个时候,我们打算利用这一点来建立 HTML First 代码段库。

  • HTMX.org 关于 ViewSource 能力的文章

总结

本网站所描述的实践和原则,在整个行业还是被视为小众的,使用它们的人群也很小。我创建这个网站的一个期待是能够汇聚志同道合的人,与他们讨论和完善这些理念。如果这些建议对你有启发,我很乐意听到你的想法。