Canvas 中的 HTML 简直太酷了,我爱死它了

BBetter Stack
Computing/SoftwareInternet Technology

Transcript

00:00:00我觉得互联网迫切需要更多奇思妙想,尤其是在现在
00:00:03AI 已经能一键生成网站的时候。
00:00:05那么,如果能更容易地让网页变得更有趣会怎样呢?就像这样。别担心,我
00:00:09不是在拖延你们或者别的什么,只是在这个网站上玩得开心点。你现在可以看到
00:00:13底部有很多我的眼睛。顺便提一下,如果我能点到订阅
00:00:17按钮,你也一定能。
00:00:18与其那样,或许你想要一种既实用又美观的网站交互方式,或者
00:00:22你想发明新的“黑暗模式”,比如让用户玩弹珠游戏才能取消订阅。又或者
00:00:27可能在辛苦工作一天后,你想坐在电脑前喝杯啤酒,
00:00:30坐在虚拟电脑前喝杯啤酒,浏览 Twitter 之类的。所有这些
00:00:34都归功于一种叫做 HTML in Canvas 的技术。让我们来聊聊它。
00:00:43我是最近才从 Twitter 上的 Matt Rothenberg 那里了解到的。在我
00:00:46看到那篇帖子后,Twitter 上仿佛开启了一个展示周,到处都是
00:00:50很酷的演示。我看到 Wes Boss 尝试了这个技术,玩得很开心。
00:00:54然后我还看到了 AA 做的那个手指枪的演示。我们两人的演示
00:00:58其实都启发了我在片头展示的那个 YouTube 演示。所以我会把所有
00:01:02演示的来源链接放在下方的说明栏中,如果你想看更多的话。
00:01:05不过现在,什么是 HTML in Canvas 呢?简而言之,它让你能够将真实的交互式
00:01:10DOM 元素直接放入 WebGL 或 2D 画布中。目前这还只是一个提案。
00:01:15它实际上是以实验性质添加到了 Chrome Canary 中,这就是为什么最近这些演示
00:01:19层出不穷,你现在可以通过开启这个标志位在 Chrome Canary 中尝试它。
00:01:24你接下来的问题可能是:为什么要这样做?这是因为 Canvas 可以实现一些很棒的
00:01:28UI 和自定义效果,就像我们刚才看到的那样。这些用 CSS 很难做到,甚至是不可能做到的。
00:01:32但 Canvas 的缺点是无法轻易渲染复杂的文本布局和 HTML 内容。
00:01:38你往往必须在内部从零开始重建它们。这意味着基于 Canvas 的内容
00:01:42在可访问性、国际化、性能和质量方面可能会受损。
00:01:47而这些正是 HTML 很大程度上已经解决的问题。所以 HTML in Canvas 是两者
00:01:51的完美结合。
00:01:52为了向你展示它是如何工作的,让我带你演示一下实际使用它的过程。我
00:01:56这里有一个多年前做的伦敦地铁时刻表网站,当时 AI 还
00:02:00不能一键搞定它。我一直觉得如果能把这些信息
00:02:02放入一个 Three.js 场景中会很酷。是的,从技术上讲你可以用 Three.js 做,显然 Three.js 支持
00:02:08文本,但如果能直接使用 HTML in Canvas,把那个显示时刻表的元素
00:02:12直接放进我的场景里会容易得多。所以,与其用这个托马斯小火车的图片,
00:02:16我只想看到我的 HTML。要做到这一点,第一步
00:02:20就是要获取我们想要在场景中实际渲染的 HTML,并把它
00:02:24放在画布内部。这是构建我们刚才看到的那个板子的 HTML。
00:02:28我们把它作为画布本身的子元素。目前,这个
00:02:32元素实际上是作为画布的后备内容存在的。所以如果画布因为某种原因
00:02:36在用户的浏览器中无法加载,他们实际上会看到这个元素。这不是我们想要的。
00:02:39为了解决这个问题,我们可以在画布元素上提供
00:02:44一个叫做 layout-subtree 的属性。这会告诉浏览器将画布的任何子元素
00:02:48视为真实的布局参与者。这样它们会被放入可访问性树中,它们可以接收
00:02:52焦点,但它们仍然不会被绘制到屏幕上。你可以在我的这个演示中看到
00:02:56依然没有任何东西显示出来。该元素在这里不会显示任何地方,
00:03:00但我们在检查元素时,悬停在它上面。它确实显示出它在技术上
00:03:04正在渲染。它只是不可见的。所以要真正在画布上渲染,我们需要把它
00:03:08转换成纹理,然后我们就可以用它来代替那张托马斯小火车的图片。而且
00:03:12我正是通过这个函数来做到这一点的。大部分工作实际上是 Three.js 完成的,
00:03:15所以你不需要担心它。第一个函数只是获取纹理,
00:03:19即 GL 纹理,也就是目前那张托马斯小火车的图片。但接下来,我们在
00:03:22这一行使用的是一个名为 textElementImage2D 的 HTML in Canvas 函数。
00:03:27看起来很复杂,但我们所做的只是获取我们要应用该元素的 Three.js 纹理。
00:03:30我们提供了一些关于它如何渲染的信息,比如
00:03:34颜色空间和其他针对 GPU 的设置,但我们不需要太担心这些。
00:03:38然后我们只需提供我们要渲染的 HTML 元素。在这种情况下,
00:03:42是那个板子。这直接来自于我们使用 document.getElementById
00:03:45获取我们放入画布中的那个元素的这一行。回到
00:03:49我们的演示,你可以看到我们现在确实用那个时刻表替换了图片,而且它是
00:03:53实时更新的。时钟在更新,我也看到时间也在更新。所以现在使用的是我们的 HTML 元素,
00:03:57但它作为纹理被提供给了这个画布。现在我们检查元素,
00:04:02你可以看到悬停在我们刚才提到的那个板子元素上,它
00:04:06仍然以一种不可见的方式被渲染。这是因为你可以认为这
00:04:09本质上就是查看这个元素会是什么样子,截取它的截图,然后
00:04:14把它放在纹理的位置。所以每当这些元素中任何一个重新渲染时,它都会更新。
00:04:19这实际上是通过 HTML canvas 中的 paint 事件完成的,当它检测到
00:04:22画布的任何子元素被重新渲染时,就会触发更新,但你
00:04:26也可以像使用 requestAnimationFrame 一样,请求进行重绘。
00:04:30如果你现在还有点困惑,我强烈建议查看 GitHub 上的那个提案。
00:04:34它包含大量的信息和演示。老实说,我确实走了一条
00:04:38稍微复杂点的路,选择了 Three.js 和 WebGL。但如果你想看最
00:04:42基础的例子,你只需要在一个画布内,放入一个类似于 form 元素的
00:04:46表单。如果你想把它渲染到画布上,我们可以简单地说 context.draw
00:04:49ElementImage,然后提供一个 form 元素以及我们想要放置它的位置。这就是
00:04:54HTML in Canvas 最简单的形式。我也想非常快速地向你展示
00:04:58这个演示。我觉得它非常有趣。你可以看到它使用了 WebGPU 和 copyElementImage
00:05:02函数来实现 HTML in Canvas,在果冻滑块下绘制一个 div。这真的很有趣。
00:05:07但真正酷的是,它在幕后实际上仍然在使用一个 input 元素。
00:05:11这只是一个非常酷的自定义输入。这就是 HTML in Canvas 所能实现的。
00:05:16不过该提案目前还有一些需要解决的缺陷。其中一个主要的
00:05:19显而易见的问题是性能。目前还有点不稳定。还有一些
00:05:24错误,比如 drawElementImage 相比 DOM 状态会慢一帧。这有一点
00:05:28视觉上的不同步。而且据说如果你尝试在画布
00:05:32子元素中放入滚动条,它会直接崩溃。但这就是它目前处于实验阶段的原因。
00:05:36这正是他们想要收集的反馈。还有一些隐私方面的担忧,即如果
00:05:40这可以渲染 HTML 元素,你肯定不希望它泄露比通常
00:05:44通过 JavaScript 能够获取到的更多的信息。所以他们确实有隐私保护的绘制
00:05:48风险机制,排除了敏感信息,如系统颜色、主题、偏好、拼写和
00:05:52语法标记、已访问链接信息等等。我觉得这里的主要担心是
00:05:56他们不想增加另一个用于指纹追踪的数据收集点。无论如何,
00:06:00我喜欢到目前为止所看到的。所以我很希望这个技术能摆脱实验阶段,
00:06:04但我非常好奇你的想法。在下方的评论区告诉我吧,顺便订阅,
00:06:07一如既往,我们下期见。

Key Takeaway

HTML in Canvas 技术通过将交互式 DOM 元素转化为 Canvas 纹理,结合了 Web UI 的排版优势与 Canvas 的图形渲染能力,解决了以往在画布中重建复杂文本和交互的难题。

Highlights

HTML in Canvas 技术允许将交互式 DOM 元素直接嵌入 WebGL 或 2D 画布中,从而弥补了 Canvas 在复杂文本布局和国际化支持上的缺陷。

该功能目前处于实验阶段,在 Chrome Canary 中通过开启特定标志位即可启用。

Canvas 元素上的 layout-subtree 属性使子元素能够进入可访问性树并接收焦点,同时保持在画布内的视觉渲染状态。

HTML in Canvas 的渲染机制通过 Paint 事件或 requestAnimationFrame 触发,当子元素状态更新时,画布对应的纹理会自动重绘。

该技术目前存在性能不稳定、视觉渲染慢一帧以及包含滚动条时可能导致崩溃等技术局限。

Timeline

HTML in Canvas 的技术价值

  • HTML in Canvas 技术使得真实的交互式 DOM 元素能够在 WebGL 或 2D 画布中直接运行。
  • Canvas 本身在处理复杂文本布局、国际化和性能方面存在短板,而这些正是 HTML 擅长的领域。
  • 此技术目前以实验性质提供在 Chrome Canary 中,旨在突破传统 CSS 对自定义 UI 效果的限制。

互联网内容呈现方式正向更具互动性与实验性的方向发展,HTML in Canvas 提供了将复杂的 DOM 结构直接植入图形场景的可能性。这一结合解决了在 Canvas 内部从零重构 HTML 功能时产生的性能、可访问性及文字排版难题。

实现与渲染机制

  • layout-subtree 属性使画布子元素成为布局参与者,确保它们出现在可访问性树中并能获得焦点。
  • 通过 textElementImage2D 函数,DOM 元素被转化为纹理并应用于 Three.js 场景中。
  • 渲染更新由 Paint 事件驱动,当子元素发生重绘时,画布内容会实时同步。

实现过程包括在画布元素中定义子元素,并利用 layout-subtree 属性使其在视觉上虽不直接显示,但在底层逻辑中保持活跃。通过将 DOM 元素转换为 WebGL 纹理,开发者可以在复杂的 3D 场景中嵌入实时更新的 HTML 时刻表等组件。这种方式简化了图形与文本交互的整合难度。

技术局限与安全考量

  • 当前技术阶段存在视觉渲染延迟一帧及包含滚动条时导致浏览器崩溃的问题。
  • 为防止增加指纹追踪风险,系统会限制渲染敏感信息,如系统颜色、已访问链接及拼写标记。
  • 此技术仍处于实验性反馈收集阶段,旨在通过开发者测试解决性能与兼容性缺陷。

由于仍处于实验阶段,该技术在稳定性和性能方面尚不成熟。开发团队特别关注隐私保护,通过排除部分系统级敏感数据来防止该特性被滥用为新的追踪工具,平衡了交互创新与用户隐私安全。

Community Posts

No posts yet. Be the first to write about this video!

Write about this video