Show HN:htmz – 一个用于 HTML 的低功耗工具
一个名为 htmz 的 181 字节 HTML“微框架”,利用 iframe 和 `target` 属性在不使用传统 AJAX 或前端框架的情况下交换页面片段,令许多开发者印象深刻,认为它是构建交互式页面的一种巧妙、极简的方式。评论者将它与 htmx 以及 pjax 等更早的技术进行比较,在欣赏其优雅和低复杂度的同时,也权衡其实际缺点,例如返回按钮行为异常、在没有 JavaScript 时缺乏优雅降级、与 CSP 的兼容性问题,以及高度交互式 UI 的延迟。总体情绪是:htmz 最适合作为一个锋利的概念验证,用来凸显浏览器与原生声明式、超媒体驱动应用之间的距离已经很近,而不是直接可投入生产的解决方案。
总体反应与意图
- 许多人认为 htmz 的体积小得惊人、很优雅,而且是对平台深度理解的巧妙展示。
- 它经常被描述为一个“有趣的 hack”、“实验”,甚至是对更重型框架的戏仿,不过也有人仍会把它考虑用于小型真实项目。
- 另一些人则认为它在技术上很巧妙,但调试起来令人困惑或脆弱,不是他们愿意在生产代码中继承的东西。
与 htmx 及其他工具的关系
- htmz 被广泛描述为 htmx 核心行为的一个子集 / 单行重实现(把服务器渲染的片段交换进 DOM)。
- htmx 被认为更重,因为它增加了历史支持、事件/回调系统、DOM morphing、SSE、输入收集以及优雅降级;这既被看作优点,也被看作成本。
- 人们还把它与 pjax、Vue(常因“向下扩展”而受到赞赏)、Alpine、hyperscript,以及其他“HTML-first”或微框架进行比较。
机制与 HTML 语义
- 核心技巧:使用
<base target>和一个隐藏的<iframe>作为代理;链接/表单将目标指向该 iframe,其加载到的片段会根据 URL hash 移动到主 DOM 中。 - 有些人认为对片段标识符(
#id)的复用以及对<slot>的原始使用是一种语义滥用;另一些人则认为这与 iframe 的行为一致,属于可以接受的 hack。 - 还有建议使用像
<div>或<output>这样的无语义元素,并使用替代的查询选择器模式来进一步缩小代码片段。
历史记录 / 返回按钮行为
- 多位评论者指出,每次点击都会增加一条浏览器历史记录,破坏预期的后退行为并污染历史。
- 提议包括:用按钮替代链接、使用
replaceState,或用一个“扩展”来管理历史;有些人认为历史方面的怪癖对于演示可以接受,但对真实应用来说是糟糕的 UX。
对 JavaScript 的依赖与优雅降级
- htmz 在没有 JS 时会完全失效;当用户在新标签页打开链接或复制链接目标时,它的表现也不佳。
- 关于非 JS 支持是否仍然重要,存在大量争论:
- 一派坚持渐进增强和“HTML-first、JS 作为升级”很重要,因为这关乎可访问性、隐私以及低功耗/旧设备。
- 另一派则认为,禁用 JS 等同于禁用了浏览器的一部分,因此出现故障是可以接受的。
- 人们提出了各种策略:动态插入 base 标签、特殊查询参数、cookie,以及新的
Sec-Fetch-Dest: iframe头,用来区分完整页面与片段。
性能与 UX 权衡
- 有些人担心每次交互都要一次往返延迟(例如切换标签页),并认为这类交互应该完全在客户端完成。
- 另一些人则反驳说,通过网络传输的小 HTML 片段可能比庞大的 JS bundle 表现更好,而且在许多地区和使用场景下,适度延迟是可以接受的。
- 于是出现了混合思路:大多数流程使用服务器渲染 HTML,而对本地、零延迟交互使用小型客户端脚本(或 hyperscript/Alpine 之类的工具)。
安全性、CSP 与跨源问题
- 内联
onload和 iframe 可能与严格的 Content-Security-Policy 冲突;文中提到了一些变通方法,如 nonce 或 hash。 - 还建议使用
postMessage的跨源变体,但如果使用targetOrigin: '*',则会被标记为危险,因为这可能泄露 iframe 内容。
更广泛的平台讨论
- 几位评论者认为 htmz 证明了“HTML 原生 AJAX”或片段加载应该被标准化。
- 讨论中提到了已有提案(例如
html-include元素)以及一种新的片段 MIME 类型的想法。 - 还有人怀念 SPA 出现之前那些 iframe/XHR hack,并认为现代 UI 技术栈把本来由基础超媒体就能很好完成的事情过度复杂化了。