Snippets

The anatomy of visually-hidden

Visually-hidden styles are used to hide content from most users, while keeping it accessible to assistive technology users.

It works because the content is technically visible and displayed — it appears in the accessibility tree and the render tree, both of which are used by assistive technologies — it’s just that the rendered size is zero.

Our industry has largely settled on a standard CSS pattern for this, refined over years of testing and iteration, by many people. This pattern:

Code language: CSS

.visually-hidden {
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

[…]

This article is not about when or why you would use visually-hidden content. There’s a number of excellent articles that discuss these questions in detail, notably Scott O’Hara’s Inclusively Hidden. But most of them don’t go into much detail about the specific CSS involved — why do we use this particular pattern, with these specific properties? So today I’m going to dissect it, looking at each of the properties in turn, why it’s there, and why it isn’t something else.

Don't fall into the well again

Now that we’ve had a little more time since the initial shock and awe of the Elon Musk purchase of Twitter, social networks have had a chance to build up interest as potential next networks to replace Twitter.

We have been given a rare chance, as a culture of social media addicts, to break a cycle we keep repeating and move to something that isn’t just owned by somebody who stands to make billions of dollars from your decision.

Unfortunately, we’re in real risk of falling into the same well as before, convinced that the open choice is somehow too complicated. That has meant that two separate social networks, Post and Hive, have driven interest from Twitter’s failings, away from open networks like Mastodon or the broader Fediverse[.]

Don’t fall into the well again.

Browserslist: target usage, not versions

July 2024 update: I no longer feel this is a good approach; instead, don’t specify anything to use the Browserslist defaults keyword, or augment the defaults keyword with additional queries instead of relying on just a minimum percentage or last few versions.


The ">0.25%" value tells [Browserslist] to only [target] browsers that make up more than 0.25% of global usage. This ensures your bundle does not contain unnecessary transpiled code for browsers that are used by a very small percentage of users.

In most cases, this is a better approach than using […] the "last 2 versions" value[, which targets] the last two versions of every browser, which means support is provided for discontinued browsers such as Internet Explorer. This can unnecessarily increase the size of your bundle if you do not expect these browsers to be used to access your application.

Ultimately, you should select the appropriate combination of queries to only target browsers that fit your needs.

StreamSaver.js

First I want to thank Eli Grey for a fantastic work implementing the FileSaver.js to save files & blobs so easily! But there is one obstacle - The RAM it can hold and the max blob size limitation

StreamSaver.js takes a different approach. Instead of saving data in client-side storage or in memory you could now actually create a writable stream directly to the file system (I’m not talking about [Chrome’s] sandboxed file system or any other web storage). This is accomplish by emulating how a server would instruct the browser to save a file using some response header + service worker

StreamSaver.js is the solution to saving streams on the client-side. It is perfect for webapps that need to save really large amounts of data created on the client-side, where the RAM is really limited, like on mobile devices.