<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Acko.net]]></title>
  <link href="https://acko.net/atom.xml" rel="self"/>
  <link href="https://acko.net/"/>
  <updated>2026-03-05T12:10:39+01:00</updated>
  <id>https://acko.net</id>
  <author>
    <name><![CDATA[Steven Wittens]]></name>
    
  </author>

  
  <entry>
    <title type="html"><![CDATA[HTML is Dead, Long Live HTML]]></title>
    <link href="https://acko.net/blog/html-is-dead-long-live-html/"/>
    <updated>2025-08-06T00:00:00+02:00</updated>
    <id>https://acko.net/blog/html-is-dead-long-live-html</id>
    <content type="html"><![CDATA[<div class="g8 i2 first"><div class="pad">
  <h2 class="sub">Rethinking DOM from first principles</h2>
</div></div>

<div class="c"></div>

<p><img src="https://acko.net/files/dom-cruft-2025/cover.jpg" style="position: absolute; left: -5000px; top: 0;" alt="Cover Image" /></p>

<div class="g8 i2"><div class="pad">

<p>Browsers are in a very weird place. While WebAssembly has succeeded, even on the server, the client still feels largely the same as it did <a href="https://acko.net/blog/shadow-dom/" target="_blank">10 years ago</a>.</p>

<p>Enthusiasts will tell you that accessing native web APIs via WASM is a solved problem, with some <a href="https://queue.acm.org/detail.cfm?id=3746174" target="_blank">minimal JS glue</a>.</p>

<p>But the question not asked is why you would want to access the DOM. It's just the only option. So I'd like to explain why it really is time to send the DOM and its assorted APIs off to a farm somewhere, with some ideas on&nbsp;how.</p>

<p>I won't pretend to know everything about browsers. Nobody knows everything anymore, and that's the problem.</p>

</div></div>

<div class="c"></div>

<div class="wide mt2">
  <img src="https://acko.net/files/dom-cruft-2025/netscape-upside-down.jpg" alt="Netscape or something" />
</div>

<div class="c"></div>

<div class="g8 i2 mt2"><div class="pad">

<h2 class="mt2">The 'Document' Model</h2>

<p>Few know how bad the DOM really is. In Chrome, <code>document.body</code> now has 350+ keys, grouped roughly like this:</p>

</div></div>

<div class="g8 i2"><div class="pad">
  <div class="mt1"><img src="https://acko.net/files/dom-cruft-2025/document-body-chart.png" alt="document.body properties" /></div>
</div></div>

<div class="g8 i2"><div class="pad">

<p>This doesn't include the CSS properties in <code>document.body.style</code> of which there are... <b>660</b>.</p>

<p>The boundary between properties and methods is very vague. Many are just facades with an invisible setter behind them. Some getters may trigger a just-in-time re-layout. There's ancient legacy stuff, like all the <code>onevent</code> properties nobody uses anymore.</p>

<p>The DOM is not lean and continues to get fatter. Whether you notice this largely depends on whether you are making web pages or web applications.</p>

<p class="mt3">Most devs now avoid working with the DOM directly, though occasionally some purist will praise pure DOM as being superior to the various JS component/templating frameworks. What little declarative facilities the DOM has, like <code>innerHTML</code>, do not resemble modern UI patterns at all. The DOM has too many ways to do the same thing, none of them nice.</p>

<div class="c"></div>
<div class="mt2"></div>

<pre><code class="language-tsx wrap">connectedCallback() {
  const
    shadow = this.attachShadow({ mode: 'closed' }),
    template = document.getElementById('hello-world')
      .content.cloneNode(true),
    hwMsg = `Hello ${ this.name }`;

  Array.from(template.querySelectorAll('.hw-text'))
    .forEach(n =&gt; n.textContent = hwMsg);

  shadow.append(template);
}
</code></pre>
<div class="c"></div>

<p>Web Components deserve a mention, being the web-native equivalent of JS component libraries. But they came too late and are unpopular. The API seems clunky, with its Shadow DOM introducing new nesting and scoping layers. Proponents kinda <a href="https://kinsta.com/blog/web-components/" target="_blank">read like apologetics</a>.</p>

<p>The achilles heel is the DOM's SGML/XML heritage, making everything stringly typed. React-likes do not have this problem, their syntax only <i>looks</i> like XML. Devs have learned not to keep state in the document, because it's inadequate for it.</p>

</div></div>

<div class="c"></div>
<div class="mt2"></div>

<div class="g2 i1"><div class="pad">
  <div class="mt1"><img class="flat" src="https://acko.net/files/dom-cruft-2025/w3c-logo.png" alt="W3C logo" /></div>
  <div class="mt1 mb2"><img class="flat" src="https://acko.net/files/dom-cruft-2025/whatwg.png" alt="WHATWG logo" /></div>
</div></div>

<div class="g8"><div class="pad">

<p>For HTML itself, there isn't much to critique because nothing has changed in 10-15 years. Only <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA" target="_blank">ARIA</a> (accessibility) is notable, and only because this was what Semantic HTML was supposed to do and didn't.</p>

<p>Semantic HTML never quite reached its goal. Despite dating from around 2011, there is e.g. no <code>&lt;thread&gt;</code> or <code>&lt;comment&gt;</code> tag, when those were well-established idioms. Instead, an article inside an article <a href="https://www.w3.org/TR/2011/WD-html5-author-20110809/the-article-element.html" target="_blank">is probably</a> a comment. The guidelines are... weird.</p>

<p>There's this feeling that HTML always had paper-envy, and couldn't quite embrace or fully define its hypertext nature, and did not trust its users to follow clear rules.</p>

<p>Stewardship of HTML has since firmly passed to WHATWG, really the browser vendors, who have not been able to define anything more concrete as a vision, and have instead just added epicycles at the margins.</p>

<p>Along the way even CSS has grown expressions, because every templating language wants to become a programming language.</p>

</div></div>

<div class="c"></div>

<div class="g8 i2 mt2">
  <img src="https://acko.net/files/dom-cruft-2025/composer.gif" alt="netscape composer" />
</div>

<div class="c"></div>

<div class="g8 i2"><div class="pad">

<p>Editability of HTML remains a sad footnote. While technically supported via <code>contentEditable</code>, actually wrangling this feature into something usable for applications is a dark art. I'm sure the Google Docs and Notion people have horror&nbsp;stories.</p>

</div></div>

<div class="g8 i2 mt2"><div class="pad">

<p>Nobody really believes in the old gods of progressive enhancement and separating markup from style anymore, not if they make apps.</p>

<p>Most of the applications you see nowadays will kitbash HTML/CSS/SVG into a pretty enough shape. But this comes with immense overhead, and is looking more and more like the opposite of a decent UI toolkit.</p>

</div></div>

<div class="c"></div>

<div class="g10 i1 mt1">
  <img src="https://acko.net/files/dom-cruft-2025/slack-html.png" alt="slack input editor" />
  <p class="tc"><i>The Slack input box</i></p>
</div>

<div class="c"></div>

<div class="g4 mt1">
  <img src="https://acko.net/files/dom-cruft-2025/slack-abs.png" alt="layout hack" />
  <p class="tc"><i>Off-screen clipboard hacks</i></p>
</div>

<div class="g8"><div class="pad">

<p>Lists and tables must be virtualized by hand, taking over for layout, resizing, dragging, and so on. Making a chat window's scrollbar stick to the bottom is somebody's TODO, every single time. And the more you virtualize, the more you have to reinvent find-in-page, right-click menus, etc.</p>

<p>The web blurred the distinction between UI and fluid content, which was novel at the time. But it makes less and less sense, because the UI part is a decade obsolete, and the content has largely homogenized.</p>

</div></div>

<div class="c"></div>
<div class="mt2"></div>

<div class="g8 i2">
  <img src="https://acko.net/files/dom-cruft-2025/css-is-awesome.jpg" alt="'css is awesome' mug, truncated layout" />
</div>

<div class="g8 i2 mt2"><div class="pad">

<h2>CSS is inside-out</h2>

<p>CSS doesn't have a stellar reputation either, but few can put their finger on exactly&nbsp;why.</p>

<p>Where most people go wrong is to start with the wrong mental model, approaching it like a constraint solver. This is easy to show with e.g.:</p>

</div></div>

<div class="g5 i1"><div class="pad">

<pre><code class="language-tsx wrap">&lt;div&gt;
  &lt;div style="height: 50%"&gt;...&lt;/div&gt;
  &lt;div style="height: 50%"&gt;...&lt;/div&gt;
&lt;/div&gt;</code></pre>

</div></div>

<div class="c mobile-appear"></div>
<div class="mt1 mobile-appear"></div>

<div class="g5"><div class="pad">

<pre><code class="language-tsx wrap">&lt;div&gt;
  &lt;div style="height: 100%"&gt;...&lt;/div&gt;
  &lt;div style="height: 100%"&gt;...&lt;/div&gt;
&lt;/div&gt;</code></pre>

</div></div>

<div class="c"></div>

<div class="g8 i2"><div class="pad">

<p>The first might seem reasonable: divide the parent into two halves vertically. But what about the second?</p>

<p>Viewed as a set of constraints, it's contradictory, because the parent div is twice as tall as... itself. What will happen instead in <i>both cases</i> is the <code>height</code> is ignored. The parent height is unknown and CSS doesn't backtrack or iterate here. It just shrink-wraps the contents.</p>

<p>If you set e.g. <code>height: 300px</code> on the parent, then it works, but the latter case will still just spill out.</p>

</div></div>

<div class="g10 i1"><div class="pad">
<p class="tc"><img class="flat" src="https://acko.net/files/dom-cruft-2025/layout-modes.png" alt="Outside-in vs inside-out layout" /></p>
<p class="tc"><i>Outside-in and inside-out layout modes</i></p>
</div></div>

<div class="g8 i2"><div class="pad">

<p>Instead, your mental model of CSS should be applying two passes of constraints, first going outside-in, and then inside-out.</p>

<p>When you make an application frame, this is <i>outside-in</i>: the available space is divided, and the content inside does not affect sizing of panels.</p>

<p>When paragraphs stack on a page, this is <i>inside-out</i>: the text stretches out its containing parent. This is what HTML wants to do naturally.</p>

<p>By being structured this way, CSS layouts are computationally pretty simple. You can propagate the parent constraints down to the children, and then gather up the children's sizes in the other direction. This is attractive and allows webpages to scale well in terms of elements and text content.</p>

<p>CSS is always inside-out by default, reflecting its document-oriented nature. The outside-in is not obvious, because it's up to you to pass all the constraints down, starting with <code>body { height: 100%; }</code>. This is why they always say vertical alignment in CSS is hard.</p>


</div></div>

<div class="g10 i1"><div class="pad">
<p class="tc"><img class="flat" src="https://acko.net/files/dom-cruft-2025/flex.png" alt="Flex grow/shrink" /></p>
<p class="tc"><i>Use flex grow and shrink for spill-free auto-layouts with completely reasonable gaps</i></p>
</div></div>

<div class="g8 i2"><div class="pad">

<p>The scenario above is better handled with a CSS3 flex box (<code>display: flex</code>), which provides explicit control over how space is divided.</p>

<p>Unfortunately flexing muddles the simple CSS model. To auto-flex, the <a href="https://www.w3.org/TR/css-flexbox-1/#algo-main-item" target="_blank">layout algorithm</a> must measure the "natural size" of every child. This means laying it out twice: first speculatively, as if floating in aether, and then again after growing or shrinking to fit:</p>

</div></div>

<div class="g6 i3"><div class="pad">
<p class="tc"><img class="flat square" src="https://acko.net/files/dom-cruft-2025/speculative-layout.png" alt="Flex speculative layout" /></p>
</div></div>

<div class="g8 i2"><div class="pad">

<p>This sounds reasonable but can come with hidden surprises, because it's recursive. Doing speculative layout of a parent often requires <i>full</i> layout of unsized children. e.g. to know how text will wrap. If you nest it right, it could in theory cause an exponential blow up, though I've never heard of it being an issue.</p>

<p>Instead you will only discover this when someone drops some large content in somewhere, and suddenly everything gets stretched out of whack. It's the opposite of the problem on the mug.</p>

<p>To avoid the recursive dependency, you need to isolate the children's contents from the outside, thus making speculative layout trivial. This can be done with <code>contain: size</code>, or by manually setting the <code>flex-basis</code> size.</p>

<p>CSS has gained a few constructs like <code>contain</code> or <code>will-change</code>, which work directly with the layout system, and drop the pretense of <i>one big happy layout</i>. It reveals some of the layer-oriented nature underneath, and is a substitute for e.g. using <code>position: absolute</code> wrappers to do the same.</p>

<p>What these do is strip <i>off</i> some of the semantics, and break the flow of DOM-wide constraints. These are overly broad by default and too document-oriented for the simpler cases. </p>

<p>This is really a metaphor for all DOM APIs.</p>

</div></div>

<div class="c"></div>

<div class="g2 i1">
  <div class="mt2 mobile-appear"><img class="flat square" src="https://acko.net/files/dom-cruft-2025/css-props-mini.png" alt="CSS props" /></div>
  <div class="mt2 mobile-vanish"><img class="flat square" src="https://acko.net/files/dom-cruft-2025/css-props.png" alt="CSS props" /></div>
</div>

<div class="g8"><div class="pad">

<h2 class="mt2">The Good Parts?</h2>

<p>That said, flex box is pretty decent if you understand these caveats. Building layouts out of nested rows and columns with gaps is intuitive, and adapts well to varying sizes. There is a <i>"CSS: The Good Parts"</i> here, which you can make ergonomic with sufficient love. CSS grids also work similarly, they're just very painfully... CSSy in their syntax.</p>

<p>But if you designed CSS layout from scratch, you wouldn't do it this way. You wouldn't have a subtractive API, with additional extra containment barrier hints. You would instead break the behavior down into its component facets, and use them à la carte. Outside-in and inside-out would both be legible as different kinds of containers and placement models.</p>

<p>The <code>inline-block</code> and <code>inline-flex</code> display models illustrate this: it's a <span style="display: inline-block; background: #ccc; padding: 5px; border: 1px solid #bbb;"><code>block</code></span> or <span style="display: inline-flex; background: #ccc; padding: 5px; border: 1px solid #bbb; width: 120px;"><span style="display: block; background: #ddd; padding: 5px; text-align: center; flex-grow: 1;"><code>f</code></span><span style="display: block; background: #ddd; padding: 5px; text-align: center; flex-grow: 1;"><code>l</code></span><span style="display: block; background: #ddd; padding: 5px; text-align: center; flex-grow: 1;"><code>e</code></span><span style="display: block; background: #ddd; padding: 5px; text-align: center; flex-grow: 1;"><code>x</code></span></span> on the inside, but an <code>inline</code> element on the outside. These are two (mostly) orthogonal aspects of a box in a box model.</p>

<p>Text and font styles are in fact the odd ones out, in hypertext. Properties like font size inherit from parent to child, so that formatting tags like <code>&lt;b&gt;</code> can work. But most of those 660 CSS properties do <i>not</i> do that. Setting a border on an element does not apply the same border to all its children recursively, that would be silly.</p>

<p>It shows that CSS is at least two different things mashed together: a system for styling rich text based on inheritance... and a layout system for block and inline elements, nested recursively but without inheritance, only containment. They use the same syntax and APIs, but don't really cascade the same way. Combining this under one style-umbrella was a mistake.</p>

<p>Worth pointing out: early ideas of relative <code>em</code> scaling have largely become irrelevant. We now think of logical vs device pixels instead, which is a far more sane solution, and closer to what users actually expect.</p>

</div></div>

<div class="c"></div>
<div class="mt2"></div>

<div class="g4 r">
  <div class="mt1"><img class="flat" src="https://acko.net/files/dom-cruft-2025/tiger.svg" alt="Tiger SVG" style="width: 100%" /></div>
</div>

<div class="g8"><div class="pad">

<p>SVG is natively integrated as well. Having SVGs in the DOM instead of just as <code>&lt;img&gt;</code> tags is useful to dynamically generate shapes and adjust icon styles.</p>

<p>But while SVG is powerful, it's neither a subset nor superset of CSS. Even when it overlaps, there are subtle differences, like the affine <code>transform</code>. It has its own warts, like serializing all coordinates to strings.</p>

<p>CSS has also gained the ability to round corners, draw gradients, and apply arbitrary clipping masks: it clearly has SVG-envy, but falls very short. SVG can e.g. do polygonal hit-testing for mouse events, which CSS cannot, and SVG has its own set of graphical layer effects.</p>

<p>Whether you use HTML/CSS or SVG to render any particular element is based on specific annoying trade-offs, even if they're all scalable vectors on the back-end.</p>

</div></div>

<div class="c"></div>

<div class="g8 i2"><div class="pad">

<p>In either case, there are also some roadblocks. I'll just mention three:</p>

<ul class="indent">

<li><code>text-ellipsis</code> can only be used to truncate <i>unwrapped</i> text, not entire paragraphs. Detecting truncated text is even harder, as is just measuring text: the APIs are inadequate. Everyone just counts letters instead.</li>

<li><code>position: sticky</code> lets elements stay in place while scrolling with zero jank. While tailor-made for this purpose, it's subtly broken. Having elements remain <i>unconditionally</i> sticky requires an absurd nesting hack, when it should be trivial.</li>

<li>The <code>z-index</code> property determines layering by absolute index. This inevitably leads to a <code>z-index-war.css</code> where everyone is putting in a new number +1 or -1 to make things layer correctly. There is no concept of relative Z positioning.</li>

</ul>

<p>For each of these features, we got stuck with v1 of whatever they could get working, instead of providing the right primitives.</p>

<p>Getting this right isn't easy, it's the hard part of API design. You can only iterate on it, by building real stuff with it before finalizing it, and looking for the holes.</p>


<h2 class="mt2">Oil on Canvas</h2>

<p>So, DOM is bad, CSS is single-digit X% good, and SVG is ugly but necessary... and nobody is in a position to fix it?</p>

<p>Well no. The diagnosis is that the middle layers don't suit anyone particularly well anymore. Just an HTML6 that finally <i>removes</i> things could be a good start.</p>

<p>But most of what needs to happen is to liberate the functionality that is there already. This can be done in good or bad ways. Ideally you design your system so the "escape hatch" for custom use is the <i>same API</i> you built the user-space stuff with. That's what dogfooding is, and also how you get good kernels.</p>

<p>A recent proposal here is <a href="https://github.com/WICG/html-in-canvas/tree/main" target="_blank">HTML in Canvas</a>, to draw HTML content into a <code>&lt;canvas&gt;</code>, with full control over the visual output. It's not very good.</p>

<p>While it might seem useful, the only reason the API has the shape that it does is because it's shoehorned into the DOM: elements must be descendants of <code>&lt;canvas&gt;</code> to fully participate in layout and styling, and to make accessibility work. There are also <i>"technical concerns"</i> with using it off-screen. </p>

<p>One example is this spinny cube:</p>

</div></div>

<div class="g6 i3">
  <img src="https://acko.net/files/dom-cruft-2025/canvas-cube.png" alt="html-in-canvas spinny cube thing" />&lt;/a&gt;
</div>

<div class="g8 i2"><div class="pad">

<p>To make it interactive, you attach hit-testing rectangles and respond to paint events. This is a new kind of hit-testing API. But it only works in 2D... so it seems 3D-use is only cosmetic? I have many questions.</p>

<p class="mt2">Again, if you designed it from scratch, you wouldn't do it this way! In particular, it's absurd that you'd have to take over <i>all</i> interaction responsibilities for an element and its descendants just to be able to customize how it <i>looks</i> i.e. renders. Especially in a browser that has projective CSS 3D transforms.</p>

<p>The use cases not covered by that, e.g. curved re-projection, will also need more complicated hit-testing than rectangles. Did they think this through? What happens when you put a dropdown in there?</p>

<p>To me it seems like they couldn't really figure out how to unify CSS and SVG filters, or how to add shaders to CSS. Passing it thru canvas is the only viable option left. <i>"At least it's programmable."</i> Is it really? Screenshotting DOM content is 1 good use-case, but not what this is sold as at all.</p>

<p>The whole reason to do "complex UIs on canvas" is to do all the things the DOM <i>doesn't do</i>, like virtualizing content, just-in-time layout and styling, visual effects, custom gestures and hit-testing, and so on. It's all nuts and bolts stuff. Having to pre-stage all the DOM content you want to draw sounds... very counterproductive.</p>

<p>From a reactivity point-of-view it's also a bad idea to route this stuff back through the same document tree, because it sets up potential cycles with observers. A canvas that's rendering DOM content isn't really a document element anymore, it's doing something else entirely.</p>

</div></div>

<div class="g10 i1 mt1">
  <a href="https://farseerdev.github.io/sheet-happens/" target="_blank"><img src="https://acko.net/files/dom-cruft-2025/sheet.png" alt="sheet-happens" /></a>
  <p class="tc"><i>Canvas-based spreadsheet that skips the DOM entirely</i></p>
</div>

<div class="g8 i2"><div class="pad">

<p>The actual achilles heel of canvas is that you don't have any real access to system fonts, text layout APIs, or UI utilities. It's quite absurd how basic it is. You have to <a href="https://farseerdev.github.io/sheet-happens/" target="_blank">implement everything</a> from scratch, including Unicode word splitting, just to get wrapped text.</p>

<p>The proposal is <i>"just use the DOM as a black box for content."</i> But we already know that you can't do anything except more CSS/SVG kitbashing this way. <code>text-ellipsis</code> and friends will still be broken, and you will still need to implement UIs circa 1990 from scratch to fix it.</p>

<p>It's all-or-nothing when you actually want something right in the middle. That's why the lower level needs to be opened up.</p>


<h2 class="mt2">Where To Go From Here</h2>

<p>The goals of <i>"HTML in Canvas"</i> do strike a chord, with chunks of HTML used as free-floating fragments, a notion that has always existed under the hood. It's a composite value type you can handle. But it should not drag 20 years of useless baggage along, while not enabling anything truly novel.</p>

<p>The kitbashing of the web has also resulted in enormous stagnation, and a loss of general UI finesse. When UI behaviors have to be mined out of divs, it limits the kinds of solutions you can even consider. Fixing this within DOM/HTML seems unwise, because there's just too much mess inside. Instead, new surfaces should be opened up outside of it.</p>

</div></div>

<div class="c"></div>

<div class="g4 mt1">
  <a href="https://usegpu.live/demo/layout/display" target="_blank"><img src="https://acko.net/files/dom-cruft-2025/use.gpu-layout.png" alt="use-gpu-layout" /></a>
  <a href="https://usegpu.live/demo/layout/align" target="_blank"><img class="mt1" src="https://acko.net/files/dom-cruft-2025/use.gpu-layout-2.png" alt="use-gpu-layout" /></a>
  <p class="tc"><i>WebGPU-based box model</i></p>
</div>

<div class="g8"><div class="pad">

<p>My schtick here has become to point awkwardly at Use.GPU's <a href="https://usegpu.live/demo/layout/display" target="_blank">HTML-like renderer</a>, which does a full X/Y flex model in a fraction of the complexity or code. I don't mean my stuff is super great, no, it's pretty bare-bones and kinda niche... and yet definitely nicer. Vertical centering is easy. Positioning makes sense.</p>

<p>There is no semantic HTML or CSS cascade, just first-class layout. You don't need 61 different accessors for <code>border*</code> either. You can just <a href="https://usegpu.live/demo/rtt/cfd-compute" target="_blank">attach shaders</a> <a href="https://acko.net/files/bluebox/#!/" target="_blank">to divs</a>. Like, that's what people wanted right? Here's <a href="https://usegpu.live/docs/guides-layout-and-ui" target="_blank">a blueprint</a>, it's mostly just <a href="https://iquilezles.org/articles/distfunctions2d/" target="_blank">SDFs</a>.</p>

<p>Font and markup concerns only appear at the leaves of the tree, where the text sits. It's striking how you can do like 90% of what the DOM does here, without the tangle of HTML/CSS/SVG, if you just reinvent that wheel. Done by 1 guy. And yes, I know about the second 90% too.</p>

<p>The classic data model here is of a view tree and a render tree. What should the view tree actually look like? And what can it be lowered into? What is it being lowered into right now, by a giant pile of legacy crud?</p>

</div></div>

<div class="c"></div>

<div class="g3 i1 mt1 r">
  <a href="https://servo.org/" target="_blank"><img src="https://acko.net/files/dom-cruft-2025/servo.png" alt="servo" /></a>
  <a href="https://ladybird.org/" target="_blank"><img class="mt1" src="https://acko.net/files/dom-cruft-2025/ladybird.png" alt="ladybird" /></a>
</div>

<div class="g8"><div class="pad">

<p>Alt-browser projects like Servo or Ladybird are in a position to make good proposals here. They have the freshest implementations, and are targeting the most essential features first. The big browser vendors could also do it, but well, taste matters. Good big systems grow from good small ones, not bad big ones. Maybe if Mozilla hadn't imploded... but alas.</p>

<p>Platform-native UI toolkits are still playing catch up with declarative and reactive UI, so that's that. Native Electron-alternatives like Tauri could be helpful, but they don't treat origin isolation as a design constraint, which makes security teams antsy.</p>

</div> </div>

<div class="g8 i2"><div class="pad">

<p>There's a feasible carrot to dangle for them though, namely in the form of better process isolation. Because of CPU exploits like Spectre, multi-threading via <code>SharedArrayBuffer</code> and Web Workers is kinda dead on arrival anyway, and that affects all WASM. The <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Embedder-Policy" target="_blank">details</a> are <a href="https://github.com/WebKit/standards-positions/issues/45#issuecomment-2077465281" target="_blank">boring</a> but right now it's an impossible sell when websites have to have things like OAuth and Zendesk integrated into them.</p>

<p>Reinventing the DOM to ditch all legacy baggage could coincide with redesigning it for a more multi-threaded, multi-origin, and async web. The browser engines are already multi-process... what did they learn? A lot has happened since Netscape, with advances in structured concurrency, ownership semantics, FP effects... all could come in handy here.</p>

<p class="mt2 mb2 tc" style="opacity: .5">* * *</p>

<p>Step 1 should just be a data model that doesn't have 350+ properties per node tho.</p>

<p>Don't be under the mistaken impression that this isn't entirely fixable.</p>

<div class="c"></div>
<div class="mt4"></div>

</div></div>

<div class="g4 i4">
  <img src="https://acko.net/files/dom-cruft-2025/netscape.png" alt="netscape wheel" />
</div>

<div class="c"></div>

<div class="mt4"></div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[CSS Sub-pixel Background Misalignments]]></title>
    <link href="https://acko.net/blog/css-sub-pixel-background-misalignments/"/>
    <updated>2008-11-18T00:00:00+01:00</updated>
    <id>https://acko.net/blog/css-sub-pixel-background-misalignments</id>
    <content type="html"><![CDATA[<div class="g8 i2 first"><div class="pad"><p><em><strong>Update</strong>: and now, IE8 adds even more odd behavior to the mix!</em>
</p>

<p>
A while ago, <a href="http://ejohn.org/blog/sub-pixel-problems-in-css/">John Resig</a> pointed out some issues with sub-pixel positioning in CSS. The problem he used is one of percentage-sized columns inside a container, where the resulting column widths don't round evenly to whole pixels or don't sum to the correct total. His conclusion is that browsers each have their own way of dealing with the problem.
</p>

<p>
I've recently been bumping into a related issue however, that shows the situation is even worse: rounding is inconsistent even inside a single browser.
</p>

<p>
<img class="natural" src="/files/css-misalign/background-misalign.png" alt="Misalignments of backgrounds in CSS" />
</p>

<p>
Take the following scenario: a fixed width element that is horizontally centered in a viewport using <code>margin-left:&nbsp;auto;&nbsp;margin-right:&nbsp;auto;</code>. The viewport has a horizontally centered background image, having <code>background-position:&nbsp;50%&nbsp;0</code>. This is an extremely common page structure.
</p>

<p>
You'd logically expect the background image and the element to line up, and move as one when the viewport is resized. However, this is not the case. Depending on the viewport width, the background can be offset one pixel to the left or right. This obviously wreaks havoc on many designs. I decided to investigate this more closely and the results are not pretty.
</p>

<p>
<!--break-->
</p>

<p>
My <a href="/files/css-misalign/index.html">test case</a> consists of the basic structure described above, repeated in a bunch of mini-viewports. Each background image contains a black box of a certain size, and is overlaid with a grey element that covers this box exactly. If the two pieces align, there should be no black peeking through on the sides, and each box should be fully gray.
</p>

<p>
For full coverage, I vary the following parameters:
<ul>
<li>The width of the viewport</li>
<li>The odd/even size of the box/element</li>
<li>Background image is bigger/smaller than the viewport</li>
<li>Background image is padded evenly/unevenly around the box (1px difference). (*)</li>
</ul>
</p>

<p>
I tested this in IE6, IE7, Safari 3.1.2, Firefox 3.0.4 and Opera 9.6.2.
</p>

<p>
The result is quite baffling: not a single browser out there rounds background image positions the same as element positions, resulting in misalignments. The tell-tale black lines show up in every browser:
</p>

<p>
<strong>IE6 and IE7:</strong>
<img class="natural" src="/files/css-misalign/IE6-7.png" alt="Misalignments of backgrounds in CSS" />
</p>

<p>
<strong>Safari 3.1 and Opera 9.6:</strong>
<img class="natural" src="/files/css-misalign/Safari3.1-Opera9.6.png" alt="Misalignments of backgrounds in CSS" />
</p>

<p>
<strong>Firefox 3.0:</strong>
<img class="natural" src="/files/css-misalign/Firefox3.0.png" alt="Misalignments of backgrounds in CSS" />
</p>

<p>
What's worse is there isn't a single case (across viewport sizes) that is handled consistently between all the browsers. So this CSS technique should in fact be considered broken.
</p>

<p>
Of course this brings up the question: is it really a browser bug or just an implementation quirk? I would argue that at least in the case where the image's width parity matches the element's, you'd expect perfectly matching rounding (i.e. for the first four rows of test cases). The other test cases are more ambiguous, and all you could hope for is consistent behaviour in each browser individually.
</p>

<p>
I wonder why this hasn't been brought up more though. A quick sampling of designers around me shows that they have all encountered this bug, but don't really know a fix and just tweak the design or layout structure to mask the effect.
</p>

<p>
If you really do need to align a background image properly, there is an ugly work-around: place your background image on an additional fixed-width element layered behind the center column. Center the background's element using margins rather than the background image itself, and clip it off at the sides using <code>overflow:&nbsp;hidden</code> on an additional wrapper. This causes the background's position to be rounded the same way as the column on top.
</p>

<p>
<small>(*) Note that there is a choice whether to pad more on the left or on the right. I chose the left. This means that the last 4 rows of test cases are inherently ambiguous: a browser that misaligns all of these in the same fashion is in fact being consistent, just in the opposite direction.</small>
</p>

<p>
</p></div></div>
]]></content>
  </entry>
  
</feed>
