Build · Craft
HTML first

HTML first

Jim Nielsen runs two icon gallery sites, and until recently each list of icons shipped a small widget to resize the icons you were looking at. In Out With the JS, In With the HTML (May 2026) he describes the original implementation: a web component like <icon-list size="md"> whose size attribute took an enumeration of sm | md | lg | xl that mapped to pixel dimensions such as 64×64 or 512×512. Clicking the widget changed the attribute and the component’s JavaScript rewrote the child img elements. It worked, but on an otherwise pre-rendered static site it meant templating logic and data duplicated and sent over the wire, and bugs of the form “I updated this one small part of how my icon list renders on the server, but forgot to tweak it on the client.”

The fix was to make the interaction a navigation. Instead of one page at /colors/red/ with JavaScript to re-render the list, he built four pages at /colors/red/{sm|md|lg|xl}, each a different list size. Then, once he added the code to support CSS , he got “a cool effect amongst the icons for free,” and, as he puts it, by removing code. The question he recommends asking is: “Could I remove some client-side JS and get a better overall experience?” If the answer is yes, he bets the development experience and the maintenance burden improve too.

The pattern has a name. In Building Websites With LLMS (March 2025), the acronym stands for “(L)ots of (L)ittle ht(M)l page(S).” With cross-document view transitions gaining support, Jim realised that building in-page, progressively enhanced interactions was more work than building two HTML pages and linking them. A filter he expected to be a few list items shown and hidden by JavaScript turned into data attributes and per-list sorting logic; each filter became its own page instead. A menu is a navigation to a page of options with an x to simulate closing it. He calls this “leveraging the grain of the web,” and the is a phrase worth keeping: on-page interactivity as simple page navigations powered by cross-document CSS transitions, rather than client-side JavaScript.

A year later he wrote a post-mortem, Reminder: You Can Stitch Together Lots of Little HTML Pages With Navigations For Interactions, and still liked it. The principle, in his words: avoid in-page interactions that require JavaScript in favour of multi-page navigations that rely on HTML and are enhanced with CSS view transitions, plus a dash of JS where prudent. The menu does not expand or slide out; it navigates to a page focused on the menu options. A newer browser gets the nicer effect. An older device, an older browser, or JavaScript disabled still works, because “If you can follow a link … it will work.” The one enhancement he kept is that closing the menu, still a plain link back to /, runs history.back() when document.referrer is set, so opening and closing does not add history entries. He is careful to say the solution looked simplistic but was not simple to arrive at; it took thinking about what was essential to navigation and keeping page size small so the interaction stayed fast. “In other words, the approach shaped the design.”

Two of his posts record the gotchas. In Gotchas in Naming CSS View Transitions (January 2025), animating a page title across pages needs a unique view-transition-name, which the docs say must be a <custom-ident>. That means no quotes around it (quoted, it becomes a string), no forward slash, and no leading number; his working value was title-2024i-love-kitkats. Bramus later pointed him to attr(id type(<custom-ident>), none) in Chrome 133 and up, and to auto, Safari-only at the time. In Aspect Ratio Changes With CSS View Transitions (February 2025), an active-tab outline grew proportionally in width but not in height as it moved between pages. “It’s small. Many people might not even notice it. But I do and it’s bugging me.” He had to slow his ::view-transition-old() timing right down to see it, found an AI answer that looked right and was wrong, and finally landed on Jake Archibald’s View transitions: Handling aspect ratio changes, which had a one-line fix and, better, the visuals to explain why the problem existed.

Part of why HTML and CSS suit this way of working is what Jim calls, in A Subtle Nicety of Fault Tolerance in HTML & CSS (January 2024), their . Browsers ignore CSS they do not understand, and he uses that while prototyping: to try a layout without a rule, he adds a z in front of it (zdisplay: inline;) and toggles the single character to compare. A very little thing, he admits, but it also illustrates why progressive enhancement is easy to build in these languages: you can test what a layout does with and without a capability by flipping one character.

The quality bar for all of this comes from As Good as HTML (November 2023), where Jim quotes Jan Miksovsky: “Adopting a quality bar of being as good as HTML is pretty hard.” He is struck that, in Jan’s work, a listbox shares roughly 85% of its code with a carousel, and reads that as HTML’s composability showing through: not bespoke attributes for every element but generic components that compose. He passes on Robin Rendle’s design system habit of asking “what would html do?”, with the select element’s reuse of hr for dividers as the example. The related test from Quality Means The Flexibility to Change (October 2024) is Dave Farley’s, via Ben Nadel: if code is easy to change it is high quality, and if it is hard to change it is not. Since Jim expects to make mistakes, he builds short, inexpensive feedback loops, and warns against npm i-ing yourself into a dependency hole. “Whatever you do, make it easy to change.” Four static pages you can edit are easier to change than a component that re-renders one.

Take the question with you before the technique: for each interaction you are about to build in JavaScript, ask whether it could be a link to another small page, enhanced by a view transition. Keep the enhancement one character away from off so you can see what the page does without it, and when something about the transition looks slightly wrong, slow it down until you can see what.