Lorem ipsum dolor sit amet consectetur adipisicing elit. Deleniti laborum error tempore nulla consequuntur π» π β οΈ π½ πΎ π€ blanditiis labore natus ratione eius, placeat omnis quas adipisci architecto harum accusamus reprehenderit, repellendus ullam. Culpa! ππ₯Ίππππππππ³ππ£π’ππ°π₯°
Why would one want to render HTML using WebGL? Besides flashy effects and per-pixel manipulations possible by writing shaders, this method is useful where performance and responsiveness are UI critical.
If we are to build UI that required a stack of layered cards (as in Tinder), which can be fluidly moved by touch and faded out, layouting, compositing and capturing dragging events at the same time can be pretty costly.
Compositing large elements with a lot of children which may have have their own opacities / shadowes, all while capturing touch events can get real bad real soon
What if we could create a WebGL context, and render each card as a simple quad with a texture of it's corresponding UI, instead of trying to render complex tree structure such as the DOM? Our rendering will be offloaded to the GPU, resulting in a massive performance boost and per-pixel control over its graphics using shaders.
This technique works nicely with React and more specifically ReactDOMServer.renderToString()
. It can be offloaded to web-workers for string concatenation and offscreen canvas for rendering.
We will insert our specially formated HTML into SVG <foreignObject>
special tag. It uses the built-in browser rendering pipeline to display HTML as part of a SVG graphic. We will then draw the SVG as a regular image onto a canvas2d element, which in turn we will use as a source to webgl texture.
There are some restrictions to what kind of HTML is allowed though:
<foreignObject>
.
<div style="
position: relative;
font-family: Arial, Helvetica, sans-serif;
max-width: 400px;
padding: 20px 30px 20px 20px;
display: flex;
justify-content: space-between;
">
...
</div>
getComputedStyle()
and append the result to an inline tag. This can be a huge performance bottleneck and will result in giant strings too (you have to apply every possible style that affect this element to make sure it renders correctly)Besides these deal-breakers, it seems browser vendors did not write a custom rendering path for the <foreignObject> and everything else appears to be fair game. Flexbox, various elements, fancy CSS transforms and even other SVGs can all be embeded and render just fine.
Safari has problems with inlined SVG whitespace and is not rendering the images