Journal tags: end

391

sparkline

Installing web apps

Safari, Chrome, and Edge all allow you to install websites as though they’re apps.

On mobile Safari, this is done with the “Add to home screen” option that’s buried deep in the “share” menu, making it all but useless.

On the desktop, this is “Add to dock” in Safari, or “Install” in Chrome or Edge.

Firefox doesn’t offer this functionality, which as a shame. Firefox is my browser of choice but they decided a while back to completely abandon progressive web apps (though they might reverse that decision soon).

Anyway, being able to install websites as apps is fantastic! I’ve got a number of these “apps” in my dock: Mastodon, Bluesky, Instagram, The Session, Google Calendar, Google Meet. They all behave just like native apps. I can’t even tell which browser I used to initially install them.

If you’d like to prompt users to install your website as an app, there’s not much you can do other than show them how to do it. But that might be about to change…

I’ve been eagerly watching the proposal for a Web Install API. This would allow authors to put a button on a page that, when clicked, would trigger the installation process (the user would still need to confirm this, of course).

Right now it’s a JavaScript API called navigator.install, but there’s talk of having a declarative version too. Personally, I think this would be an ideal job for an invoker command. Making a whole new install element seems ludicrously over-engineered to me when button invoketarget="share" is right there.

Microsoft recently announced that they’d be testing the JavaScript API in an origin trial. I immediately signed up The Session for the trial. Then I updated the site to output the appropriate HTTP header.

You still need to mess around in the browser configs to test this locally. Go to edge://flags or chrome://flags/ and search for ‘Web App Installation API’, enable it and restart.

I’m now using this API on the homepage of The Session. Unsurprisingly, I’ve wrapped up the functionality into an HTML web component that I call button-install.

Here’s the code. You use it like this:

<button-install>
  <button>Install the app</button>
</button-install>

Use whatever text you like inside the button.

I wasn’t sure whether to keep the button element in the regular DOM or generate it in the Shadow DOM of the custom element. Seeing as the button requires JavaScript to do anything, the Shadow DOM option would make sense. As Tess put it, Shadow DOM is for hiding your shame—the bits of your interface that depend on JavaScript.

In the end I decided to stick with a regular button element within the custom element, but I take steps to remove it when it’s not necessary.

There’s a potential issue in having an element that could self-destruct if the browser doesn’t cut the mustard. There might be a flash of seeing the button before it gets removed. That could even cause a nasty layout shift.

So far I haven’t seen this problem myself but I should probably use something like Scott’s CSS in reverse: fade in the button with a little delay (during which time the button might end up getting removed anyway).

My connectedCallback method starts by finding the button nested in the custom element:

class ButtonInstall extends HTMLElement {
  connectedCallback () {
    this.button = this.querySelector('button');
    …
  }
customElements.define('button-install', ButtonInstall);

If the navigator.install method doesn’t exist, remove the button.

if (!navigator.install) {
  this.button.remove();
  return;
}

If the current display-mode is standalone, then the site has already been installed, so remove the button.

if (window.matchMedia('(display-mode: standalone)').matches) {
  this.button.remove();
  return;
}

As an extra measure, I could also use the display-mode media query in CSS to hide the button:

@media (display-mode: standalone) {
  button-install button {
    display: none;
  }
}

If the button has survived these tests, I can wire it up to the navigator.install method:

this.button.addEventListener('click', async (ev) => {
  await navigator.install();
});

That’s all I’m doing for now. I’m not doing any try/catch stuff to handle all the permutations of what might happen next. I just hand it over to the browser from there.

Feel free to use this code if you want. Adjust the code as needed. If your manifest file says display: fullscreen you’ll need to change the test in the JavaScript accordingly.

Oh, and make sure your site already has a manifest file that has an id field in it. That’s required for navigator.install to work.

The schedule for Web Day Out

Here’s the schedule for Web Day Out—what a fantastic collection of talks!

Web Day Out
10:00 – 10:30 I can’t believe it’s not JavaScript Jemima Abu
10:30 – 11:00 A pragmatic guide to browser support Rachel Andrew
11:30 – 12:00 Progressive web apps from the trenches Aleth Gueguen
12:00 – 12:30 Build for the web, build on the web, build with the web Harry Roberts
14:00 – 14:30 Breaking with habits Manuel Matuzovič
14:30 – 15:00 What’s new in web typography? Richard Rutter
15:30 – 16:00 Customisable <select> and the friends we made along the way Jake Archibald
16:00 – 16:30 The browser is the playground Lola Odelola

Seeing all of those talk titles in a row is getting me very, very excited for this day!

I hope that you’re excited too, and I hope you’ve got your ticket already.

If you need to convince your boss to send you (and your team) to Web Day Out I’ve put together some reasons to attend along with an email template that you can use as a starting point.

Also, if your company is sending a group of people anyway, consider sponsoring Web Day Out. You get a bunch of conference tickets as part of the sponsorship deal.

Hope to see you in Brighton on Thursday, 12 March 2026!

Why use React?

This isn’t a rhetorical question. I genuinely want to know why developers choose to build websites using React.

There are many possible reasons. Alas, none of them relate directly to user experience, other than a trickle-down justification: happy productive developers will make better websites. Citation needed.

It’s also worth mentioning that some people don’t choose to use React, but its use is mandated by their workplace (like some other more recent technologies I could mention). By my definition, this makes React enterprise software in this situation. My definition of enterprise software is any software that you use but that you yourself didn’t choose.

Inertia

By far the most common reason for choosing React today is inertia. If it’s what you’re comfortable with, you’d need a really compelling reason not to use it. That’s generally the reason behind usage mandates too. If we “standardise” on React, then it’ll make hiring more straightforward (though the reality isn’t quite so simple, as the React ecosystem has mutated and bifurcated over time).

And you know what? Inertia is a perfectly valid reason to choose a technology. If time is of the essence, and you know it’s going to take you time to learn a new technology, it makes sense to stick with what you know, even if it’s out of date. This isn’t just true of React, it’s true of any tech stack.

This would all be absolutely fine if React weren’t a framework that gets executed in browsers. Any client-side framework is a tax on the end user. They have to download, parse, and execute the framework in order for you to benefit.

But maybe React doesn’t need to run in the browser at all. That’s the promise of server-side rendering.

The front end

There used to be a fairly clear distinction between front-end development and back-end development. The front end consisted of HTML, CSS, and client-side JavaScript. The back end was anything you wanted as long as it could spit out those bits of the front end: PHP, Ruby, Python, or even just a plain web server with static files.

Then it became possible to write JavaScript on the back end. Great! Now you didn’t need to context-switch when you were scripting for the client or the server. But this blessing also turned out to be a bit of a curse.

When you’re writing code for the back end, some things matter more than others. File size, for example, isn’t really a concern. Your code can get really long and it probably won’t slow down the execution. And if it does, you can always buy your way out of the problem by getting a more powerful server.

On the front end, your code should have different priorities. File size matters, especially with JavaScript. The code won’t be executed on your server. It’s executed on all sorts of devices on all sorts of networks running all sorts of browsers. If things get slow, you can’t buy your way out of the problem because you can’t buy every single one of your users a new device and a new network plan.

Now that JavaScript can run on the server as well as the client, it’s tempting to just treat the code the same. It’s the same language after all. But the context really matters. Some JavaScript that’s perfectly fine to run on the server can be a resource hog on the client.

And this is where it gets interesting with React. Because most of the things people like about React still apply on the back end.

React developers

When React first appeared, it was touted as front-end tool. State management and a near-magical virtual DOM were the main selling points.

Over time, that’s changed. The claimed speed benefits of the virtual DOM turned out to be just plain false. That just left state management.

But by that time, the selling points had changed. The component-based architecture turned out to be really popular. Developers liked JSX. A lot. Once you got used to it, it was a neat way to encapsulate little bits of functionality into building blocks that can be combined in all sorts of ways.

For the longest time, I didn’t realise this had happened. I was still thinking of React as being a framework like jQuery. But React is a framework like Rails or Django. As a developer, it’s where you do all your work. Heck, it’s pretty much your identity.

But whereas Rails or Django run on the back end, React runs on the front end …except when it doesn’t.

JavaScript can run on the server, which means React can run on the server. It’s entirely possible to have your React cake and eat it. You can write all of your code in React without serving up a single line of React to your users.

That’s true in theory. The devil is in the tooling.

Priorities

Next.js allows you to write in React and do server-side rendering. But it really, really wants to output React to the client as well.

By default, you get the dreaded hydration pattern—do all the computing on the server in JavaScript (yay!), serve up HTML straight away (yay! yay!) …and then serve up all the same JavaScript that’s on the server anyway (ya—wait, what?).

It’s possible to get Next.js to skip that last step, but it’s not easy. You’ll be battling it every step of the way.

Astro takes a very different approach. It will do everything it can to keep the client-side JavaScript to a minimum. Developers get to keep their beloved JSX authoring environment without penalising users.

Alas, the collective inertia of the “modern” development community is bound up in the React/Next/Vercel ecosystem. That’s a shame, because Astro shows us that it doesn’t have to be this way.

Switching away from using React on the front end doesn’t mean you have to switch away from using React on the back end.

Why use React?

The titular question I asked is too broad and naïve. There are plenty of reasons to use React, just as there are plenty of reasons to use Wordpress, Eleventy, or any other technology that works on the back end. If it’s what you like or what you’re comfortable with, that’s reason enough.

All I really care about is the front end. I’m not going to pass judgment on anyone’s choice of server-side framework, as long as it doesn’t impact what you can do in the client. Like Harry says:

…if you’re going to use one, I shouldn’t be able to smell it.

Here’s the question I should be asking:

Why use React in the browser?

Because if the reason you’re using React is cultural—the whole team works in JSX, it makes hiring easier—then there’s probably no need to make your users download React.

If you’re making a single-page app, then …well, the first thing you should do is ask yourself if it really needs to be a single-page app. They should be the exception, not the default. But if you’re determined to make a single-page app, then I can see why state management becomes very important.

In that situation, try shipping Preact instead of React. As a developer, you’ll almost certainly notice no difference, but your users will appreciate the refreshing lack of bloat.

Mostly though, I’d encourage you to investigate what you can do with vanilla JavaScript in the browser. I totally get why you’d want to hold on to React as an authoring environment, but don’t let your framework limit what you can do on the front end. If you use React on the client, you’re not doing your users any favours.

You can continue to write in React. You can continue to use JSX. You can continue to hire React developers. But keep it on your machine. For your users, make the most of what web browsers can do.

Once you keep React on the server, then a whole world of possibilities opens up on the client. Web browsers have become incredibly powerful in what they offer you. Don’t let React-on-the-client hold you back.

And if you want to know more about what web browsers are capable of today, come to Web Day Out in Brighton on Thursday, 12th March 2026.

Manuel Matuzovič is speaking at Web Day Out

The line-up for Web Day Out is now complete! The final speaker to be added to the line-up is the one and only Manuel Matuzovič.

You may know Manuel from his superb Web Accessibility Cookbook (full disclosure: I had the honour of writing the foreword to that book). Or perhaps you’re familiar with the crimes against markup that he documents at HTMHell. But at Web Day Out, he’s going to be talking about CSS.

The past few years have seen a veritable explosion in CSS capabilities. It’s one thing to hear about all the new stuff in CSS, but how do you actually start using it?

You may need to unlearn what you have previously learned. That’s what Manuel’s talk will be covering:

Manuel built a new project from scratch with modern CSS and questioned every line of code he wrote.

In this talk, he presents what he has learned and encourages you to review your best practices.

You can see why I’m so excited about this—it’s perfect for the agenda of Web Day Out:

Do you feel like you’re missing out on some of the latest advances in HTML, CSS, and JavaScript APIs? Web Day Out is your chance to get up to speed on what matters.

There’ll be eight brilliant speakers for your entertainment:

  1. Jemima Abu
  2. Rachel Andrew
  3. Jake Archibald
  4. Aleth Gueguen
  5. Manuel Matuzovič
  6. Lola Odelola
  7. Harry Roberts
  8. Richard Rutter

You won’t want to miss this, so get your ticket now for the ludicrously reasonable price of just £225+VAT!

See you in Brighton on 12 March 2026!

Providers

If you’re building software, it’s generally a good idea to avoid the Not-Invented-Here syndrome. This is when you insist on writing absolutely everything from scratch even if it would make more sense to use a third-party provider.

Need your app to take payments? Don’t try to become your own payment provider—use an existing provider instead.

Need your app to send email? Don’t try to code all that up yourself—just use an existing service.

This same thinking seems to apply to JavaScript libraries too. If you don’t use a library or framework, you’ll just end up writing your own library or framework instead, right?

Except that’s not the way that JavaScript frameworks work. At least not any more.

There was a time when JavaScript libraries really did abstract away browser differences that you probably didn’t want to deal with yourself. In the early days of jQuery—before querySelector existed—trying to work with the DOM could be a real pain. Libraries like jQuery helped avoid that pain.

Maybe it was even true in the early days of Angular and React. If you were trying to handle navigations yourself, it probably made sense to use a framework.

But that’s not the case any more, and hasn’t been for quite a while.

These days, client-side JavaScript frameworks don’t abstract away the underlying platform, they instead try to be an alternative. In fact, if you attempt to use web platform features, your JavaScript framework will often get in the way. You have to wait until your framework of choice supports a feature like view transitions before you get to use it.

This is nuts. Developers are choosing to use tools that actively get in the way of the web platform.

I think that most developers have the mental model of JavaScript frameworks completely backwards. They believe that the framework saves them time and effort (just like a payment provider or an email service). Instead these frameworks are simply limiting the possibility space of what you can do in web browsers today.

When you use a JavaScript framework, that isn’t the end of your work, it’s just the beginning. You still have to write your own code that makes use of that framework. Except now your code is restricted to only what the framework can do.

And yet most developers still believe that using a JavaScript framework somehow enables them to do more.

Jim Nielsen has a great framing on this. JavaScript libraries aren’t like payment providers or email services. Rather, it’s the features built into web browsers today that are like these third-party providers. When you use these features, you’re benefiting from all the work that the browser makers have put into making them as efficient as possible:

Browser makers have teams of people who, day-in and day-out, are spending lots of time developing and optimizing new their offerings.

So if you leverage what they offer you, that gives you an advantage because you don’t have to build it yourself.

Want to do nifty page transitions? Don’t use a library. Use view transitions.

Want to animate parts of the page as the user scrolls? Don’t use a library. Use scroll-driven animations.

Want to make something happen when the user clicks? Don’t use a library. For the love of all that is holy, just use a button.

If you agree that using a button makes more sense than using a div, then I encourage you to apply the same thinking to everything else your app needs to do.

Take advantage of all the wonderful things you can do in web browsers today. If instead you decide to use a JavaScript framework, you’re basically inventing from scratch.

Except now all of your users pay the price because they’re the ones who have to download the JavaScript framework when they use your app.

Aleth Gueguen is speaking at Web Day Out

Almost two months ago, I put out the call for speaker suggestions for Web Day Out. I got some good responses—thank you to everyone who took the time to get in touch.

The response that really piqued my interest was from Aleth Gueguen. She proposed a talk on progressive web apps, backed up with plenty of experience. The more I thought about it, the more I realised how perfect it would be for Web Day Out.

So I’m very pleased to announce that Aleth will be speaking at Web Day Out about progressive web apps from the trenches:

Find out about the most important capabilities in progressive web apps and how to put them to work.

I’m really excited about this line-up! This is going to be a day out that you won’t want to miss. Get your ticket for a mere £225+VAT if you haven’t already!

See you in Brighton on 12 March, 2026!

Jake Archibald is speaking at Web Day Out

I’m very happy to announce that the one and only Jake Jaffa-The-Cake Archibald will be speaking at Web Day Out!

Given the agenda for this event, I think you’ll agree that Jake is a perfect fit. He’s been at the forefront of championing user-centred web standards, writing specs and shipping features in browsers.

Along the way he’s also created two valuable performance tools that I use all the time: SVGOMG and Squoosh, which has a permanent place in my dock—if you need to compress images, I highly recommend adding this progressive web app to your desktop.

He’s the man behind service workers and view transitions—two of the most important features for making websites first-class citizens on any device.

So what will he talk about at Web Day Out? Image formats? Offline functionality? Smooth animations? Something else entirely?

All will be revealed soon. In the meantime, grab yourself a ticket to Web Day Out—it’s just £225+VAT—and I’ll see you in Brighton on Thursday, 12 March 2026!

Reasoning

Tim recently gave a talk at Smashing Conference in New York called One Step Ahead. Based on the slides, it looks like it was an excellent talk.

Towards the end, there’s a slide that could be the tagline for Web Day Out:

Betting on the browser is our best chance at long-term success.

Most of the talk focuses on two technologies that you can add to any website with just a couple of lines of code: view transitions and speculation rules.

I’m using both of them on The Session and I can testify to their superpowers—super-snappy navigations with smooth animations.

Honestly, that takes care of 95% of the reasons for building a single-page app (the other 5% would be around managing state, which most sites—e-commerce, publishing, whatever—don’t need to bother with). Instead build a good ol’-fashioned website with pages of HTML linked together, then apply view transitions and speculation rules.

I mean, why wouldn’t you do that?

That’s not a rhetorical question. I’m genuinely interested in the reasons why people would reject a simple declarative solution in favour of the complexity of doing everything with a big JavaScript framework.

One reason might be browser support. After all, both view transitions and speculation rules are designed to be used as progressive enhancements, regardless of how many browsers happen to support them right now. If you want to attempt to have complete control, I understand why you might reach for the single-page app model, even if it means bloating the initial payload.

But think about that mindset for a second. Rather than reward the browsers that support modern features, you would instead be punishing them. You’d be treating every browser the same. Instead of taking advantage of the amazing features that some browsers have, you’d rather act as though they’re no different to legacy browsers.

I kind of understand the thinking behind that. You assume a level playing field by treating every browser as though they’re Internet Explorer. But what a waste! You ship tons of uneccesary code to perfectly capable browsers.

That could be the tagline for React.

Simplify

I was messing about with some images on a website recently and while I was happy enough with the arrangement on large screens, I thought it would be better to have the images in a kind of carousel on smaller screens—a swipable gallery.

My old brain immediately thought this would be fairly complicated to do, but actually it’s ludicrously straightforward. Just stick this bit of CSS on the containing element inside a media query (or better yet, a container query):

display: flex;
overflow-x: auto;

That’s it.

Oh, and you can swap out overflow-x for overflow-inline if, like me, you’re a fan of logical properties. But support for that only just landed in Safari so I’d probably wait a little while before removing the old syntax.

Here’s an example using pictures of some of the lovely people who will be speaking at Web Day Out:

Jemima Abu Rachel Andrew Lola Odelola Richard Rutter Harry Roberts

While you’re at it, add this:

overscroll-behavior-inline: contain;

Thats prevents the user accidentally triggering a backwards/forwards navigation when they’re swiping.

You could add some more little niceties like this, but you don’t have to:

scroll-snap-type: inline mandatory;
scroll-behavior: smooth;

And maybe this on the individual items:

scroll-snap-align: center;

You could progressively enhance even more with the new pseudo-elements like ::scroll-button() and ::scroll-marker for Chromium browsers.

Apart from that last bit, none of this is particularly new or groundbreaking. But it was a pleasant reminder for me that interactions that used to be complicated to implement are now very straightforward indeed.

Here’s another example that Ana Tudor brought up yesterday:

You have a section with a p on the left & an img on the right. How do you make the img height always be determined by the p with the tiniest bit of CSS? 😼

No changing the HTML structure in any way, no pseudos, no background declarations, no JS. Just a tiny bit of #CSS.

Old me would’ve said it can’t be done. But with a little bit of investigating, I found a nice straightforward solution:

section >  img {
  contain: size;
  place-self: stretch;
  object-fit: cover;
}

That’ll work whether the section has its display set to flex or grid.

There’s something very, very satisfying in finding a simple solution to something you thought would be complicated.

Honestly, I feel like web developers are constantly being gaslit into thinking that complex over-engineered solutions are the only option. When the discourse is being dominated by people invested in frameworks and libraries, all our default thinking will involve frameworks and libraries. That’s not good for users, and I don’t think it’s good for us either.

Of course, the trick is knowing that the simpler solution exists. The information probably isn’t going to fall in your lap—especially when the discourse is dominated by overly-complex JavaScript.

So get yourself a ticket for Web Day Out. It’s on Thursday, March 12th, 2026 right here in Brighton.

I guarantee you’ll hear about some magnificent techniques that will allow you to rip out plenty of complex code in favour of letting the browser do the work.

Harry Roberts is speaking at Web Day Out

I was going to save this announcement for later, but I’m just too excited: Harry Roberts will be speaking at Web Day Out!

Goddamn, that’s one fine line-up, and it isn’t even complete yet! Get your ticket if you haven’t already.

There’s a bit of a story behind the talk that Harry is going to give…

Earlier this year, Harry posted a most excellent screed in which he said:

The web as a platform is a safe bet. It’s un-versioned by design. That’s the commitment the web makes to you—take advantage of it.

  • Opt into web platform features incrementally;
  • Embrace progressive enhancement to build fast, reliable applications that adapt to your customers’ context;
  • Write code that leans into the browser, not away from it.

Yes! Exactly!

Thing is, Harry posted this on LinkedIn. My indieweb sensibilities were affronted. So I harangued him:

You should blog this, Harry

My pestering paid off with an excellent blog post on Harry’s own site called Build for the Web, Build on the Web, Build with the Web:

The beauty of opting into web platform features as they become available is that your site becomes contextual. The same codebase adapts into its environment, playing to its strengths, rather than trying to build and ship your own environment from the ground up. Meet your users where they are.

That’s a pretty neat summation of the agenda for Web Day Out. So I thought, “Hmm …if I was able to pester Harry to turn a LinkedIn post into a really good blog post, I wonder if I could pester him to turn that blog post into a talk?”

I threw down the gauntlet. Harry accepted the challenge.

I’m sure you’re already familiar with Harry’s excellent work, but if you’re not, he’s basically Mr. Web Performance. That’s why I’m so excited to have him speak at Web Day Out—I want to hear the business case for leaning into what web browsers can do today, and he is most certainly the best person to bring receipts.

You won’t want to miss this, so be sure to get your ticket now; it’s only £225+VAT.

If you’re not ready to commit just yet, but you want to hear about more speaker announcements like this, you can sign up to the mailing list.

Speaking at Web Day Out

Half of the line-up of speakers for Web Day Out is already on the site. One more is already confirmed.

I’m ridiculously excited about the way the line-up is taking shape, and judging by the zippiness of ticket sales, so are lots of my peers. Seriously, don’t wait to get your ticket or you might end up missing out completely.

I’ve already got a shortlist of other people I could imagine on the line-up, but I’m open to more suggestions. If you’d like to speak at Web Day Out—or you know someone you think would be great—send an email to jeremy@clearleft.com

I won’t be checking my work email while I’m away on holiday next week but it would be lovely to come back to an inbox of exciting suggestions.

A couple of pointers…

I’d rather not have too many people like me on the line-up. White dudes are already over-represented in this industry, especially at conferences.

If you’ve never given a talk before, don’t worry. I’d love to help you put your talk together and coach you in presenting it. I have some experience in this area.

No product pitches. That includes JavaScript frameworks and CSS libraries.

If I get even a whiff of “AI”, your proposal doesn’t stand a chance. There are many, many, many other events that are only too happy to have wall-to-wall talks about …that sort of thing.

If you end up speaking at Web Day Out you will, of course, be paid. We will, of course, cover travel and accommodation too. We can’t afford the travel costs of bringing anyone in from outside Europe though (and we’d like to keep the carbon footprint of the event as small as possible).

Web Day Out has an opinionated agenda all about showing what’s possible in web browsers today. Some potential topics include:

The emphasis should be on using stuff in production rather than theoretical demos.

If you’ve got a case study about using the web platform—perhaps migrating away from a framework-driven approach—that would fit the bill perfectly.

How’s all that sounding? Know someone who could deliver the goods? Let me know!

Announcing Web Day Out

I’m going to cut right to the chase: Clearleft is putting on a brand new conference in 2026. It’s called Web Day Out. It’ll be on Thursday, March 12th right here in Brighton. Tickets are just £225+VAT. You should be there!

If you’ve ever been to Responsive Day Out or Patterns Day, the format will be familiar to you. There’s going to be eight 30 minute talks. Bam! Bam! Bam!

Like those other one-day conferences, this one has a laser-sharp focus.

Web Day Out is all about what you can do in web browsers today. You can expect talks that showcase hands-on practical uses for the latest advances in HTML, CSS, and JavaScript APIs. There will be no talks about libraries, frameworks or build tools, and I can guarantee there will be absolutely no so-called “AI”.

As you might have gathered, this is an opinionated conference.

If you care about performance, accessibility, and progressive enhancement, Web Day Out is the event for you.

Or if you’ve been living in React-land but starting to feel that maybe you’re missing out on what’s been shipping in web browsers, Web Day Out is the event for you too. And I’m not talking about cute demos here. This is very much about shipping to production.

I’ve got half of the line-up assembled already:

Jemima’s talk gives you a flavour of what to expect at Web Day Out:

In this talk, we’ll take a look at how to use HTML and CSS to build simpler alternatives to popular JavaScript components such as accordions, modals, scroll transitions, carousels etc We’ll also take a look at the performance and accessibility benefits and real-life applications and use-cases of these components.

Web Day Out will be in The Studio Theatre of the Brighton Dome, which is a fantastic intimate venue. That means that places are limited, so get your ticket now!

The Invisibles

When I was talking about monitoring web performance yesterday, I linked to the CrUX data for The Session.

CrUX is a contraction of Chrome User Experience Report. CrUX just sounds better than CEAR.

It’s data gathered from actual Chrome users worldwide. It can be handy as part of a balanced performance-monitoring diet, but it’s always worth remembering that it only shows a subset of your users; those on Chrome.

The actual CrUX data is imprisoned in some hellish Google interface so some kindly people have put more humane interfaces on it. I like Calibre’s CrUX tool as well as Treo’s.

What’s nice is that you can look at the numbers for any reasonably popular website, not just your own. Lest I get too smug about the performance metrics for The Session, I can compare them to the numbers for WikiPedia or the BBC. Both of those sites are made by people who prioritise speed, and it shows.

If you scroll down to the numbers on navigation types, you’ll see something interesting. Across the board, whether it’s The Session, Wikipedia, or the BBC, the BFcache—back/forward cache—is used around 16% to 17% of the time. This is when users use the back button (or forward button).

Unless you do something to stop them, browsers will make sure that those navigations are super speedy. You might inadvertently be sabotaging the BFcache if you’re sending a Cache-Control: no-store header or if you’re using an unload event handler in JavaScript.

I guess it’s unsurprising the BFcache numbers are relatively consistent across three different websites. People are people, whatever website they’re browsing.

Where it gets interesting is in the differences. Take a look at pre-rendering. It’s 4% for the BBC and just 0.4% for Wikipedia. But on The Session it’s a whopping 35%!

That’s because I’m using speculation rules. They’re quite straightforward to implement and they pair beautifully with full-page view transitions for a slick, speedy user experience.

It doesn’t look like WikiPedia or the BBC are using speculation rules at all, which kind of surprises me.

Then again, because they’re a hidden technology I can understand why they’d slip through the cracks.

On any web project, I think it’s worth having a checklist of The Invisibles—things that aren’t displayed directly in the browser, but that can make a big difference to the user experience.

Some examples:

If you’ve got a checklist like that in place, you can at least ask “Whose job is this?” All too often, these things are missing because there’s no clarity on whose responsible for them. They’re sorta back-end and sorta front-end.

Newsletters

Ethan tagged me in a post. I didn’t feel a thing.

“I’d love to invite a few other folks to share their favorite newsletters”, he wrote.

My immediate thought was that I don’t actually subscribe to many newsletters. But then I remembered that most newsletters are available as RSS feeds, and I very much do subscribe to those.

Reading RSS and reading email feel very different to me. A new item in my email client feels like a task. A new item in my feed reader feels like a gift.

Anyway, I poked around in my subscriptions and found some newsletters in there that I can heartily recommend.

First and foremost, there’s The History Of The Web by Jay Hoffman. Each newsletter is a building block for the timeline of the web that he’s putting together. It’s very much up my alley.

On the topic of the World Wide Web, Matthias has a newsletter called Own Your Web:

Whether you want to get started with your own personal website or level up as a designer, developer, or independent creator working with the ever-changing material of the Web, this little email is for you. ❤✊

On the inescapable topic of “AI”, I can recommend Mystery AI Hype Theater 3000: The Newsletter by Professor Emily M. Bender and Doctor Alex Hanna.

Journalist Clive Thompson has a fun newsletter called The Linkfest:

The opposite of doomscrolling: Every two weeks (roughly) I send you a collection of the best Internet reading I’ve found — links to culture, technology, art and science that fascinated me.

If you like that, you’ll love The Whippet by McKinley Valentine:

A newsletter for the terminally curious

Okay, now there are three more newsletters that I like, but I’m hesitant to recommend for the simple reason that they’re on Substack alongside a pile of racist trash. If you decide you like any of these, please don’t subscribe by email; use the RSS feed. For the love of Jeebus, don’t give Substack your email address.

Age of Invention by Anton Howes is a deep, deep dive into the history of technology and industry:

I’m interested in everything from the exploits of sixteenth-century alchemists to the schemes of Victorian engineers.

Finally, there are two newsletters written by people whose music I listened to in my formative years in Ireland…

When We Were Young by Paul Page recounts his time in the band Whipping Boy in the ’90s:

This will be the story of Whipping Boy told from my perspective.

Toasted Heretic were making very different music around the same time as Whipping Boy. Their singer Julian Gough has gone on to write books, poems, and now a newsletter about cosmology called The Egg And The Rock:

The Egg and the Rock makes a big, specific argument (backed up by a lot of recent data, across many fields), that our universe appears to be the result of an evolutionary process at the level of universes.

There you go—quite a grab bag of newsletter options for you.

Underlines and line height

I was thinking about something I wrote yesterday when I was talking about styling underlines on links:

For a start, you can adjust the distance of the underline from the text using text-underline-offset. If you’re using a generous line-height, use a generous distance here too.

For some reason, I completely forgot that we’ve got a line-height unit in CSS now: lh. So if you want to make the distance of your underline proportional to the line height of the text that the link is part of, it’s easy-peasy:

text-underline-offset: 0.15lh;

The greater the line height, the greater the distance between the link text and its underline.

I think this one is going into my collection of CSS snippets I use on almost every project.

Style your underlines

We shouldn’t rely on colour alone to indicate that something is interactive.

Take links, for example. Sure, you can give them a different colour to the surrounding text, but you shouldn’t stop there. Make sure there’s something else that distinguishes them. You could make them bold. Or you could stick with the well-understood convention of underlying links.

This is where some designers bristle. If there are a lot of links on a page, it could look awfully cluttered with underlines. That’s why some designers would rather remove the underline completely.

As Manu observed:

I’ve done a lot of audits in the first half of this year and at this point a believe that designing links without underlines is a kink. The idea that users don’t understand that links are clickable arouses some designers. I can’t explain it any other way.

But underlining links isn’t the binary decision it once was. You can use CSS to style those underlines just as you’d style any other part of your design language.

Here’s a regular underlined link.

For a start, you can adjust the distance of the underline from the text using text-underline-offset. If you’re using a generous line-height, use a generous distance here too.

Here’s a link with an offset underline.

If you’d rather have a thinner or thicker underline, use text-decoration-thickness.

Here’s a link with a thin underline.

The colour of the underline and the colour of the link don’t need to be the same. Use text-decoration-color to make them completely different colours or make the underline a lighter shade of the link colour.

Here’s a link with a translucent underline.

That’s quite a difference with just a few CSS declarations:

text-underline-offset: 0.2em;
text-decoration-thickness: 1px;
text-decoration-color: oklch(from currentColor l c h / 50%);

If that still isn’t subtle enough for you, you could even use text-decoration-style to make the underline dotted or dashed, but that might be a step too far.

Here’s a link with a dotted underline.

Whatever you decide, I hope you’ll see that underlines aren’t the enemy of good design. They’re an opportunity.

You should use underlines to keep your links accessible. But you should also use CSS to make those underlines beautiful.

Streamlining HTML web components

If you’re a front-end developer and you don’t read Chris Ferdinandi’s blog, you should change that right now. Add that RSS feed to your feed reader of choice!

Lately he’s been posting about some of the thinking behind his Kelp UI library. That includes some great nuggets of wisdom around HTML web components.

First of all, he pointed out that web components don’t need a constructor(). This was news to me. I thought custom elements had to include this incantation at the start:

constructor () {
  super();
}

But it turns that if all you’re doing is calling super(), you can omit the whole thing and it’ll be done for you.

I immediately refactored all the web components I’m using on The Session. While I was at it, I implemented Chris’s bulletproof web component loading.

Now technically, I don’t need to do this. I’m linking to my JavaScript at the bottom of every page so I know it’s going to load after the HTML. But I don’t like having that assumption baked into my code.

For any of my custom elements that reference other elements in the DOM—using, say, document.querySelector()—I updated the connectedCallback() method to use Chris’s technique.

It turned out that there weren’t that many of my custom elements that were doing that. Because HTML web components are wrapped around existing markup, the contents of the custom element are usually what matters (rather than other elements on the same page).

I guess that’s another unexpected benefit to HTML web components. Because they’ve already got their own bit of DOM inside them, you don’t need to worry about when you load your markup and when you load your JavaScript.

And no faffing about with the dark arts of the Shadow DOM either.

Awareness

Today is Global Accessibility Awareness Day:

The purpose of GAAD is to get everyone talking, thinking and learning about digital access and inclusion, and the more than One Billion people with disabilities/impairments.

Awareness is good. It’s necessary. But it’s not sufficient.

Accessibility, like sustainability and equality, is the kind of thing that most businesses will put at the end of sentences that begin “We are committed to…”

It’s what happens next that matters. How does that declared commitment—that awareness—turn into action?

In the worst-case scenario, an organisation might reach for an accessibility overlay. Who can blame them? They care about accessibility. They want to do something. This is something.

Good intentions alone can result in an inaccessible website. That’s why I think there’s another level of awareness that’s equally important. Designers and developers need to be aware of what they can actually do in service of accessibility.

Fortunately that’s not an onerous expectation. It doesn’t take long to grasp the importance of having good colour contrast or using the right HTML elements.

An awareness of HTML is like a superpower when it comes to accessibility. Like I wrote in the foreword to the Web Accessibility Cookbook by O’Reilly:

It’s supposed to be an accessibility cookbook but it’s also one of the best HTML tutorials you’ll ever find. Come for the accessibility recipe; stay for the deep understanding of markup.

The challenge is that HTML is hidden. Like Cassie said in the accessibility episode of The Clearleft Podcast:

You get JavaScript errors if you do that wrong and you can see if your CSS is broken, but you don’t really have that with accessibility. It’s not as obvious when you’ve got something wrong.

We are biased towards what we can see—hierarchy, layout, imagery, widgets. Those are the outputs. When it comes to accessibility, what matters is how those outputs are generated. Is that button actually a button element or is it a div? Is that heading actually an h1 or is it another div?

This isn’t about the semantics of HTML. This is about the UX of HTML:

Instead of explaining the meaning of a certain element, I show them what it does.

That’s the kind of awareness I’m talking about.

One way of gaining this awareness is to get a feel for using a screen reader.

The name is a bit of a misnomer. Reading the text on screen is the least important thing that the software does. The really important thing that a screen reader does is convey the structure of what’s on screen.

Friend of Clearleft, Jamie Knight very generously spent an hour of his time this week showing everyone the basics of using VoiceOver on a Mac (there’s a great short video by Ethan that also covers this).

Using the rotor, everyone was able to explore what’s under the hood of a web page; all the headings, the text of all the links, the different regions of the page.

That’s not going to turn anyone into an accessibility expert overnight, but it gave everyone an awareness of how much the HTML matters.

Mind you, accessibility is a much bigger field than just screen readers.

Fred recently hosted a terrific panel called Is neurodiversity the next frontier of accessibility in UX design?—well worth a watch!

One of those panelists—Craig Abbott—is speaking on day two of UX London next month. His talk has the magnificent title, Accessibility is a design problem:

I spend a bit of time covering some misconceptions about accessibility, who is responsible for it, and why it’s important that we design for it up front. It also includes real-world examples where design has impacted accessibility, before moving onto lots of practical guidance on what to be aware of and how to design for many different accessibility issues.

Get yourself a ticket and get ready for some practical accessibility awareness.

CSS snippets

I’ve been thinking about the kind of CSS I write by default when I start a new project.

Some of it is habitual. I now use logical properties automatically. It took me a while to rewire my brain, but now seeing left or top in a style sheet looks wrong to me.

When I mentioned this recently, I had some pushback from people wondering why you’d bother using logical properites if you never planned to translate the website into a language with a different writing system. I pointed out that even if you don’t plan to translate a web page, a user may still choose to. Using logical properties helps them. From that perspective, it’s kind of like using user preference queries.

That’s something else I use by default now. If I’ve got any animations or transitions in my CSS, I wrap them in prefers-reduced-motion: no-preference query.

For instance, I’m a huge fan of view transitions and I enable them by default on every new project, but I do it like this:

@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
}

I’ll usually have a prefers-color-scheme query for dark mode too. This is often quite straightforward if I’m using custom properties for colours, something else I’m doing habitually. And now I’m starting to use OKLCH for those colours, even if they start as hexadecimal values.

Custom properties are something else I reach for a lot, though I try to avoid premature optimisation. Generally I wait until I spot a value I’m using more than two or three times in a stylesheet; then I convert it to a custom property.

I make full use of clamp() for text sizing. Sometimes I’ll just set a fluid width on the html element and then size everything else with ems or rems. More often, I’ll use Utopia to flow between different type scales.

Okay, those are all features of CSS—logical properties, preference queries, view transitions, custom properties, fluid type—but what about actual snippets of CSS that I re-use from project to project?

I’m not talking about a CSS reset, which usually involves zeroing out the initial values provided by the browser. I’m talking about tiny little enhancements just one level up from those user-agent styles.

Here’s one I picked up from Eric that I apply to the figcaption element:

figcaption {
  max-inline-size: max-content;
  margin-inline: auto;
}

That will centre-align the text until it wraps onto more than one line, at which point it’s no longer centred. Neat!

Here’s another one I start with on every project:

a:focus-visible {
  outline-offset: 0.25em;
  outline-width: 0.25em;
  outline-color: currentColor;
}

That puts a nice chunky focus ring on links when they’re tabbed to. Personally, I like having the focus ring relative to the font size of the link but I know other people prefer to use a pixel size. You do you. Using the currentColor of the focused is usually a good starting point, thought I might end up over-riding this with a different hightlight colour.

Then there’s typography. Rich has a veritable cornucopia of starting styles you can use to improve typography in CSS.

Something I’m reaching for now is the text-wrap property with its new values of pretty and balance:

ul,ol,dl,dt,dd,p,figure,blockquote {
  hanging-punctuation: first last;
  text-wrap: pretty;
}

And maybe this for headings, if they’re being centred:

h1,h2,h3,h4,h5,h6 {
  text-align: center;
  text-wrap: balance;
}

All of these little snippets should be easily over-writable so I tend to wrap them in a :where() selector to reduce their specificity:

:where(figcaption) {
  max-inline-size: max-content;
  margin-inline: auto;
}
:where(a:focus-visible) {
  outline-offset: 0.25em;
  outline-width: 0.25em;
  outline-color: currentColor;
}
:where(ul,ol,dl,dt,dd,p,figure,blockquote) {
  hanging-punctuation: first last;
  text-wrap: pretty;
}

But if I really want them to be easily over-writable, then the galaxy-brain move would be to put them in their own cascade layer. That’s what Manu does with his CSS boilerplate:

@layer core, third-party, components, utility;

Then I could put those snippets in the core layer, making sure they could be overwritten by the CSS in any of the other layers:

@layer core {
  figcaption {
    max-inline-size: max-content;
    margin-inline: auto;
  }
  a:focus-visible {
    outline-offset: 0.25em;
    outline-width: 0.25em;
    outline-color: currentColor;
  }
  ul,ol,dl,dt,dd,p,figure,blockquote {
    hanging-punctuation: first last;
    text-wrap: pretty;
  }
}

For now I’m just using :where() but I think I should start using cascade layers.

I also want to start training myself to use the lh value (line-height) for block spacing.

And although I’m using the :has() selector, I don’t think I’ve yet trained my brain to reach for it by default.

CSS has sooooo much to offer today—I want to make sure I’m taking full advantage of it.

OKLCH()

I was at the State Of The Browser event recently, which was great as always.

Manu gave a great talk about colour in CSS. A lot of it focused on OKLCH. I was already convinced of the benefits of this colour space after seeing a terrific talk by Anton Lovchikov a while back.

After Manu’s talk, someone mentioned that even though OKLCH is well supported in browsers now, it’s a shame that it isn’t (yet) in design tools like Figma. So designers are still handing over mock-ups with hex values.

I get the frustration, but in my experience it’s not that big a deal in practice. Here’s why: oklch() isn’t just a way of defining colours with lightness, chroma, and hue in CSS. It’s also a function. You can use the magical from keyword in this function to convert hex colours to l, c, and h:

--page-colour: oklch(from #49498D l c h);

So even if you’re being handed hex colour values, you can still use OKLCH in your CSS. Once you’re doing that, you can use all of the good stuff that comes with having those three values separated out—something that was theoretically possible with hsl, but problematic in practice.

Let’s say you want to encode something into your CSS like this: “if the user has specified that they prefer higher contrast, the background colour should be four times darker.”

@media (prefers-contrast: more) {
  --page-colour: oklch(from #49498D calc(l / 4) c h);
}

It’s really handy that you can use calc() within oklch()—functions within functions. And I haven’t even touched on the color-mix() function.

Hmmm …y’know, this is starting to sound an awful lot like functional programming:

Functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that map values to other values.