Tagged “order”
Use z-index only when necessary
There’s a great section on Source order and layers in Every Layout’s Imposter layout. It’s a reminder that when needing to layer one element on top of the other you should:
- favour a modern layout approach such as CSS Grid over absolute positioning; and
- not apply
z-index
unless it’s necessary.
which elements appear over which is, by default, a question of source order. That is: if two elements share the same space, the one that appears above the other will be the one that comes last in the source.
z-index
is only necessary where you want to layer positioned elements irrespective of their source order. It’s another kind of override, and should be avoided wherever possible.
An arms race of escalating z-index values is often cited as one of those irritating but necessary things you have to deal with using CSS. I rarely have z-index problems, because I rarely use positioning, and I’m mindful of source order when I do.
Changing visual order with CSS
When considering using Flexbox or CSS Grid to change the visual order of elements, remember that “with great power comes great responsibility”.
Flexbox and CSS Grid have given us new powers to shuffle the visual order of elements on a web page such that it is different to the element order in the source code.
However many smart developers have rightly pointed out that although this is really convenient and can help in conquering gnarly design and responsive challenges, it’s often not a good idea. Rachel Andrew in particular has regularly offered the following advice:
Don’t fix source problems with Grid or Flexbox.
See Rachel’s talk Grid, content re-ordering and accessibility for more detail.
So, what’s the problem?
Essentially we cause people problems when we create a disconnect between tabbing order and visual order.
Let’s dig into the detail.
People browse web pages in different ways
We know that a web page’s visitors are likely to have a range of different abilities. While some experience the full extent of our visual design, others are visually-impaired or blind. Others still have motor impairments. The web was intended to be accessible and therefore web pages should cater appropriately to this range of user needs.
Relatedly we also know that people will use one or more of the following methods to move around a web page:
- a thumb and fingers;
- a mouse (or trackpad) and keyboard;
- a keyboard alone.
There are probably other methods I’m forgetting, but those are the most common.
In order to cater to people who navigate a web page using a keyboard without a mouse (a.k.a. keyboard users), we must ensure that the page is tab-friendly. We want the page’s interactive elements to be navigable and focusable by pressing the Tab key. Those elements should be focusable one by one in the same order as they are defined in the HTML document.
Often, achieving tab-friendliness requires little or no additional development effort because the browser gives us so much of the necessary behaviour natively. Interactive HTML elements like anchors (links) and form controls are focusable by default. And for any custom interactions where we want to make a normally non-focusable element (such as a div
) focusable (thus giving it a keyboard tab-stop) we can apply the tabindex attribute, setting its tabindex="0"
.
A simple, well-formed web page will natively offer a natural and predictable tabbing order.
With CSS Grid and Flexbox we now have new CSS options such as order
, flex-direction: row-reverse
and grid-auto-flow
which let us reorder elements on the page. This can be really handy for situations where a design spec calls for Element 1 to appear above Element 2 on narrow viewports but to its right on wider viewports. Using these new CSS properties we might let the elements follow the source order on narrow viewports but change their order within a media query for wider viewports.
However this means we are now messing with the natural order of things. And if we move focusable elements around such that their visual order is different from their source order this creates a disconnect between tabbing order and visual order.
The disconnect is unlikely to be apparent to sighted people on a tablet/phone or on a desktop setup and navigating with their mouse, because they are not using tab to navigate. Blind users using a screen reader will be similarly unaffected because they don’t experience the visual order.
We might assume that all keyboard (only) users are also blind, using a screen reader, and not perceiving visual order. However keyboard users also include sighted people who have trouble operating a pointing device such as a mouse or trackball, or whose mouse is currently not working, or who simply prefer to use a keyboard where possible.
For the sighted person who navigates by keyboard our change of order would be confusing. When you use tab and expect that to follow convention and set focus on one element but it actually sets focus on another, you’ll likely assume that something is broken.
Rachel Andrew argues that creating this kind of disconnect is to be avoided. Léonie Watson suggests that in simple examples such a disconnect may only be mildly awkward, however in complex interfaces it could make things horribly unusable.
Is it ever OK to change visual order with CSS?
At work I recently reviewed a PR where the visual order of a Flexbox layout was being updated via order: -1
in a media query for wide viewports. Although it was a really elegant solution on paper, I advised caution in light of the pitfalls mentioned above.
However a colleague rightly pointed out that the elements being reordered were two div
s. In this case and any others where the elements (and their children) are non-focusable and we’re not messing with the likes of navigation links or form elements, I think we are safe.
The Future
We’ve recently been given a few new CSS layout powers only to subsequently be advised not to use them.
How do we move forward?
Rachel Andrew argues that this problem needs addressed at a CSS level; that developers should be able to set the tab and reading order to follow the visual rather than source order under certain circumstances.
Until that becomes a CSS reality we should continue to be judicious in our usage to ensure we don’t break user expectations. We can also use tools like the Source Order Viewer in Chrome DevTools (DevTools > Elements > Accessibility) to check our work.
Using the tabindex attribute | TPG
Léonie Watson explains how the HTML tabindex attribute is used to manage keyboard focus. Of particular interest to me was a clarification of what tabindex="-1"
does (because I always forget).
tabindex="-1"
The element becomes programmatically focusable but isn’t included in the tab order. It can’t be reached by someone using the tab key to navigate through content, but it can be focused on with scripting via the focus()
method.
We might use this because we want to be able to set focus to a particular element via a script. Léonie offers the example of a list of form errors.
Alternatively we might use this because we want to prevent a normally tabbable element from being tabbable. Sara Souidean uses this technique (in combination with aria-hidden=true
) on e-commerce product teaser “media objects” in order to limit the number of duplicate links that keyboard users must tab through.
Tabindex on page targets to assist with keyboard focus
I’ve often seen tabindex="-1"
used as a companion to the id
attribute on elements of a page intended to be directly accessible via links. Examples include a main
element that should be directly accessible from a “Skip to content” link, or the headings in a blog article to support sharing direct links to page sections.
Before HTML5, creating an internal “link target” required creating an anchor element that used the name
attribute. In HTML5 this use of anchor was deprecated with authors instead encouraged to add the id
attribute to any element they wish. The reason why developers added tabindex="-1"
to their main
and h2
(etc) “targets” is because some older browsers, when responding to a link to such a resource, would move visual focus to the target element (i.e. scroll to it) but not programatically set focus to it if the target element was not focusable. Including tabindex="-1"
solved that problem.
Modern browsers move the focus correctly and so using tabindex
for this purpose is no longer necessary.
tabindex="0"
Applying tabindex="0"
to an element inserts it into the tabbing order based on its position in the source. It is not necessary to apply this to an interactive element such as a button or checkbox since they are focusable by default. You should use it sparingly (because it requires care to ensure accessibility) but you might use it on a custom element which needs to be interactive under certain circumstances such as the horizontally scrollable container in a Data Table.
tabindex="1+"
This imposes a tab order on the content that bears no resemblance to the expected tab order. It’s an antipattern. Don’t do it.
See all tags.