Snippets

Accessible Text Labels For All

When you navigate this page using VoiceOver, and use the Form Controls menu, you’ll get a list of all form controls on the page, including the Add to Cart buttons.

Quickly scanning these buttons you can tell that they provide very little value, as there is no way to tell which product each button corresponds to. How does a user know which button they want to go to and press if they don’t know which product it corresponds to?

[…]

A popular example of Voice recognition software used to browse the Web is Dragon Naturally Speaking.

[…]

Seeing it in action is the best way to get an idea of how it’s used. So, to quickly demonstrate how it is used on the Web, Level Access created a video demoing Dragon Naturally Speaking to fill out a form on a page. The following video is a short clip from their video which you can find and watch in full on [YouTube].

 

When the dragon user (in the video) wants to select a form control, he speaks out the visual text label of that control. This is one of many reasons why visual labels are important in user interfaces.

So when we have a series of Add to Cart buttons, a dragon user will speak the label of the button in order to interact with it. This is why adding text in the middle of the string makes it inaccessible. The content in the middle of the string would break the visible label. The user would be telling dragon to interact with a button whose label is not what it visually appears to be.

[…]

So whenever you need to add additional text to a visible label, it best come after what’s visually shown.

Similarly, always ensure the accessible name (announced by screen readers) matches the visual label as much as possible. This means that you’ll also want to avoid adding a label using aria-label that does not match the text label that is shown on a control.

Idle Until Urgent

A few weeks ago I was looking at some of the performance metrics for my site. Specifically, I wanted to see how I was doing on our newest metric, first input delay (FID). My site is just a blog (and doesn’t run much JavaScript), so I expected to see pretty good results.

Input delay that’s less than 100 milliseconds is typically perceived as instant by users, so the performance goal we recommend (and the numbers I was hoping to see in my analytics) is FID < 100ms for 99% of page loads.

To my surprise, my site’s FID was 254ms at the 99th percentile. And while that’s not terrible, the perfectionist in me just couldn’t let that slide. I had to fix it!

[…]

[W]hile I was trying to solve my issue I stumbled upon a pretty interesting performance strategy that I want to share (it’s the primary reason I’m writing this article).

I’m calling the strategy: idle until urgent.

My performance problem

First input delay (FID) is a metric that measures the time between when a user first interacts with your site (for a blog like mine, that’s most likely them clicking a link) and the time when the browser is able to respond to that interaction (make a request to load the next page).

The reason there might be a delay is if the browser’s main thread is busy doing something else (usually executing JavaScript code). So to diagnose a higher-than-expected FID, you should start by creating a performance trace of your site as it’s loading (with CPU and network throttling enabled) and look for individual tasks on the main thread that take a long time to execute. Then once you’ve identified those long tasks, you can try to break them up into smaller tasks.

Here’s what I found when doing a performance trace of my site:

So what’s taking so long to run?

Well, if you look at the tails of this flame chart, you won’t see any single functions that are clearly taking up the bulk of the time. Most individual functions are run in less than 1ms, but when you add them all up, it’s taking more than 100ms to run them in a single, synchronous call stack.

This is the JavaScript equivalent of death by a thousand cuts.

Since the problem is all these functions are being run as part of a single task, the browser has to wait until this task finishes to respond to user interaction. So clearly the solution is to break up this code into multiple tasks[.]

[…]

A perfect example of a component that really needs to have its initialization code broken up can be illustrated by zooming closer down into this performance trace. Mid-way through the main() function, you’ll see one of my components uses the Intl.DateTimeFormat API[.]

[…]

Creating this object took 13.47 milliseconds!

The thing is, the Intl.DateTimeFormat instance is created in the component’s constructor, but it’s not actually used until it’s needed by other components that reference it to format dates. However, this component doesn’t know when it’s going to be referenced, so it’s playing it safe and instantiating the Int.DateTimeFormat object right away.

[…]

Idle Until Urgent

After spending a lot of time thinking about this problem, I realized that the evaluation strategy I really wanted was one where my code would initially be deferred to idle periods but then run immediately as soon as it’s needed. In other words: idle-until-urgent.

Idle-until-urgent sidesteps most of the downsides I described in the previous section. In the worst case, it has the exact same performance characteristics as lazy evaluation, and in the best case it doesn’t block interactivity at all because execution happens during idle periods.

What forces layout/reflow: a comprehensive list by Paul Irish

All of the below properties or methods, when requested/called in JavaScript, will trigger the browser to synchronously calculate the style and layout*. This is also called reflow or layout thrashing, and is common performance bottleneck.

Generally, all APIs that synchronously provide layout metrics will trigger forced reflow / layout. Read on for additional cases and details.

Screen reader order of precendence for interpreting content

Whether you build a widget as a web component using standards, Vue, React, or any other framework, or with a combination of HTML and JavaScript, screen readers that encounter your widget will look for clues in the rendered markup to discern what it is and tell users that they’ve encountered a search box, menu, or carousel.

Screen readers generally follow this order of precedence:

  1. Look for explicitly set ARIA attributes (roles, states, properties), and in the absence of those:
  2. Interpret any implicit roles from markup semantics (form elements, paragraphs, lists, etc).
  3. Read any text available in the markup.

If no discernable semantics exist (think ARIA-less <div> or <span> tags), it skips to #3. So when you omit ARIA, you’re rolling the dice on whether users will understand that your <ul> is a menu and not simply a list. When you omit ARIA and semantic tags, you’re leaving it up to your users to figure things out (and potentially abandon your product because it doesn’t work).