Hiding Content

Not all techniques for hiding web content are created equal. The choice of which to use can have dramatic consequences for accessibility.

Use of this guide can reduce mystery about why this happens and how to do better. The matrix here provides the full range of options on the Web Platform, with the helpful inclusion of testable examples. Thanks to Vincent Valentin for generously providing this as a resource to the web development community.

Access types

What makes this an interesting study is the large number of distinct and overlapping types of hiding. When content is hidden, access to it may be completely removed, but just as likely may only be partially restricted, with an overlapping set of access types still in effect. For example, a very common digital accessibility failure is to hide content visually but neglect to truly remove it from perception by assistive technologies.

A key understanding is that there are not two simple states, such as "visible and hidden." Depending on the technique, there are at least 13 composite states of access to partially hidden web content. Before considering them in combination, let's define each access type.

Definitions

DOM access
The element is in the document.
Visual access
The element is visible in the document.
Layout access
The element fills a space that will affect the rest of the layout.
Semantic access
The element has a meaning (title, list, emphasis…) that can be returned to user agents (screen readers, search engines…).
Content access
The information embedded in the element will be available.
Keyboard access
The element is reachable and usable by navigating on the keyboard (if it allows it natively).
Pointer access
The element is reachable and usable by navigating with a mouse or a tactile device (if it allows it natively).
Styles access
The element is always reachable via CSS and can be modified graphically.
Subtree reverse access
It is possible to reverse the removal on children.

Techniques

Access matrix
Technique DOM Visual Layout Semantic Content Keyboard Pointer Styles Subtree reverse
JS .remove() no no no no no no no no no
HTML <!-- -- > yes no no no no no no no no
CSS display: none yes no no no no no no no no
HTML hidden="hidden" yes no no no no no no no no
HTML type="hidden" yes no no no no no no no no
CSS visibility: hidden yes no yes no no no no yes yes
HTML inert="inert" yes yes yes no no no no yes no
CSS .mask, .sr-only yes no no yes yes yes no yes no
HTML aria-hidden="true" yes yes yes no no yes yes yes no
HTML disabled="disabled" yes yes yes yes yes no no yes no
CSS display: contents yes yes yes yes yes no yes no yes
CSS opacity: 0 yes no yes yes yes yes yes yes no
CSS position: absolute yes yes no yes yes yes yes yes no
HTML tabindex="-1" yes yes yes yes yes no yes yes no
HTML role="presentation" yes yes yes no yes yes yes yes yes
HTML role="none" yes yes yes no yes yes yes yes yes
CSS pointer-events: none yes yes yes yes yes yes no yes yes
Default yes yes yes yes yes yes yes yes yes

Test demos


Default

1 2 3

Remove()

1 2 3

<!-- -->

1 3

display: none

1 2 3

hidden="hidden"

1 3

type="hidden"


visibility: hidden

1 2 3

aria-hidden="true"

1 3

.mask

1 2 3

disabled="disabled"


display: contents

1 2 3

inert="inert"

1 2 3

opacity: 0

1 2 3

position: absolute

1 2 3

role="presentation"

1 2 3

role="none"

1 2 3

tabindex="-1"

1 2 3

pointer-events: none

1 2 3