This page explores the accessibility and impacts of a number of techniques used to hide and minimize content in digital publications.

It is generally advised to avoid including hidden content that is only intended for users of assistive technologies, however, except where the content is not central to understanding the publication. Standard hyperlinks to text alternatives and declarative approaches to minimizing content (e.g., the details element) are more broadly usable than hidden content, as not everyone who can benefit from this content uses an assistive technology.

When content has to be selectively made to appear, ensure that progressive enhancement techniques are followed.

HTML Techniques

The hidden attribute

HTML5 introduced the hidden attribute as a way to declaratively hide content (i.e., to hide content without relying on other technologies like CSS). When the attribute is set on an element, its content will not be rendered in any presentation, so will not be read by assistive technologies.

Example — Effect of the hidden attribute

In the following example, the hidden attribute is used to hide the span containing the words "not the".

Markup:

<p>This is <span hidden="">not the</span> content.</p>

Demo:

This is content.

The value of attribute has to be either an empty string, as in the previous example, or the value "hidden" (hidden="hidden"). Although referred to as a "boolean" attribute, its value cannot be set to "true" or "false". To make content visible again, the hidden attribute has to be removed from the element.

The hidden attribute is most appropriate to author directly on an element when its content will never be made visible. (See the scripting section on dynamically setting the attribute if content will be toggled between visible and hidden states.)

The hidden attribute is most commonly used with the ARIA attributes that do not require visible content (e.g., aria-labelledby and aria-describedby). These attributes make the text available to assistive technologies in specific contexts.

The effect of setting this attribute is the equivalent of setting the CSS display property to none. It is more reliable than CSS options in modern user agents, however, as not all user agents support CSS styling.

For older user agents that do not support the new HTML5 elements and attributes, it will be necessary to also include a CSS fallback for the hidden attribute. A selector like the following will ensure all elements with the attribute are also hidden by CSS:

*[hidden] { display: none; }

The details element

The details element does not strictly meet the requirement of hiding content. What it does provide is the ability to collapse content down to just the label specified in the summary tag. One advantage of the element is that it does not require scripting support, which is often lacking in EPUB reading systems, to expand and collapse the content.

Example — Effect of the details element

The following examples shows a collapsed details element. Clicking on the label expands the content.

Markup:

<details>
<summary>Description</summary>
<p>The first of the three gas giants is …</p>
</details>

Demo

It is not required that the content begin in a collapsed state. By adding the open attribute, the content will initially be expanded (the attribute is also a boolean, like the hidden attribute, so its value is either an empty string or the value open).

Example — Expanded details element

Markup:

<details open="">
<summary>Description</summary>
<p>The first of the three gas giants is …</p>
</details>

Demo

A current limitation, however, is that reading systems do not always repaginate well when the element is expanded or collapsed. Expanding may force content below the element off the bottom of the current page, making it unavailable to sighted readers. The attribute is also not well supported in older browsers, including not at all in Internet Explorer versions, so requires a polyfill to work.

The details element is commonly paired with the aria-details attribute to associate descriptions with elements.

CSS Techniques

Although CSS provides a number of approaches to hiding content visually, the primary problems with using it are that:

  1. CSS is not always supported and can often be disabled by users.
  2. Support for new properties often takes a long time to develop and many never get supported in older user agents.
  3. EPUB reading systems often supply their own styling, so author styles may be ignored or overridden.

As a result, there is no guarantee that styled content will be hidden from any users depending on the user agent they are using. HTML techniques are generally more reliable.

Setting display to none

The display property is a widespread method used to visually hide content, as its origins go back much further than the hidden attribute and it is more direct and easily manipulable than setting the height and width of elements. Setting the display to none causes the element it is carried on to be removed from visual display and the accessibility tree, so assistive technologies will not read the content.

Example — Effect of no display

Markup:

.display-none {
display: none;
}

<p>This is the visible
text<span class="display-none"> and this is 
not</span>.</p>

Demo:

This is the visible text.

Like with the hidden attribute, content that is hidden using the display property can be accessed by ARIA attributes that accept hidden content. The same flaw that this approach hides useful information from users who do not use assistive technologies also applies, however.

Clipping

Clipping is a technique that reduces content to a single pixel so that visual users are not aware that that the additional content is present.

The advantage of clipping content instead of hiding it completely is that assistive technologies will read the clipped content, whereas they ignore content set or styled to be hidden.

The clip-path property is the primary property used to achieve this effect, but a number of others are also required (some as fallbacks), as depicted in the following example.

Example — Effect of clipping

The span containing the text "and this is not" will not be visible when the content is rendered, but the text will still be read by an assistive technology.

Markup:

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

<p>This is the visible text<span class="clip"> and
 this is not</span>.</p>

Demo:

This is the visible text and this is not.

Note

The clip property is now deprecated. It is included as a fallback for older browsers.

While this technique works well in web browsers, support in EPUB reading systems is inconsistent. Support for the new clip-path property is not widespread, and neither is support for older clip property as it requires absolute positioning.

Zero height and width

Setting an element's height and width properties to 0 is similar to the clipping technique, except that assistive technologies typically will not read the content of elements without any size dimensions.

Example — Effect of zero height and width

Markup:

.zero-height-width {
height: 0;
width: 0;
}

<p>This is the visible
text<span class="zero-height-width"> and this
is not</span>.</p>

Demo:

This is the visible text and this is not.

Even though setting an element's dimensions to zero does not remove the content from accessibility tree, assistive technologies are often optimized to ignore content styled this way (it is why the clipping technique only reduces the size to one pixel, for example). This behavior is not universal, however, so the content may be read in some cases.

Transparent opacity

Setting the opacity property of an element to 0 makes it completely transparent to users, but assistive technologies will still read the text.

Example — Effect of full opacity

In the following example, the second paragraph has its opacity set to 0 to make it transparent, but there is still space where it is located.

Markup:

.transparent {
opacity: 0;
}

<p>This paragraph appears.</p>
<p class="transparent">While this one is made fully
opaque.</p>
<p>So there is space between.</p>

Demo:

This paragraph appears.

While this one is made fully opaque.

So there is space between.

The primary issues with the use of opacity are support in EPUB reading systems and that it leaves space where the opaque text is.

Note

It is also possible to change the opacity of just the text of an element by setting the alpha channel to be transparent (e.g., using the rgba() or #RRGGBBAA value syntax). Support for alpha channel values is also not widespread in EPUB, however.

Transformations

The transform property provides two options for hiding content: one is to scale the element to zero, and the other is to translate it off screen. In both cases, assistive technologies will still read the text.

Using the scale transform essentially shrinks the referenced element down until it occupies no space. It is similar in effect to setting the height and width to zero, except that the full space the element would occupy does not disappear when scaling.

Example — Effect of scaling

In the following example, the second paragraph is scaled to zero, but the space it occupies remains. Click the button in the demo to toggle the scaling.

Markup:

.scale {
transform: scale(0);
}

<p>This paragraph appears.</p>
<p class="scale">While this one is scaled.</p>
<p>So there is space between.</p>

Demo:

This paragraph appears.

While this one is scaled.

So there is space between.

Using the translate transform is similar in effect to absolute positioning content off screen, except that the full space the element would occupy does not disappear. The value is the x and y coordinates of the translating vector.

Example — Effect of translating

In the following example, the second paragraph is translated off screen using a an x-coordinate of -9999px and y-coordinate of 0. The space the element occupies remains, however. Click the button in the demo to toggle the effect.

Markup:

.translate {
transform: translate(-9999px);
}

<p>This paragraph appears.</p>
<p class="translate">While this one is translated
off screen.</p>
<p>So there is space between.</p>

Demo:

This paragraph appears.

While this one is translated off screen.

So there is space between.

Similar to the opacity, the primary issues with using transform is that such animations are not well supported in EPUB reading systems and they leave space where the transformed text originated.

Setting visibility to hidden

The visibility property is not commonly used to hide content in digital publications, as unlike the display property it leaves a space in the rendered content where the element would appear. The content is not read by assistive technologies, despite the visible space.

Example — Effect of hidden visibility

In the following example, a space the length of the text " and this is not" occurs where the hidden span is. Click the button in the demo to toggle the visibility.

Markup:

.vis-hidden {
visibility: hidden;
}

<p>This is the visible
text<span class="vis-hidden"> and this is 
not</span> but now with space.</p>

Demo:

This is the visible text and this is not but now with space.

The property is more commonly used on the Web to avoid the other content on the page shifting around when an element is hidden or made visible (e.g., to prevent a page footer from being pulled up from the bottom of the page).

Similar to the display property, content hidden this way is hidden to assistive technologies unless it is referenced from an ARIA attribute that allows hidden content.

Absolute position

Absolute positioning content off-screen using the position property is another common Web practice to hide it visually while leaving it for assistive technologies to announce. As it is only the visual position of the content that changes, assistive technologies will still read the text.

Example — Effect of absolute positioning

Markup:

.abs-position {
position: absolute;
left: -9999px;
}

<p>This paragraph appears.</p>
<p class="abs-position">While this one is positioned
off screen.</p>
<p>But there is no space between.</p>

Demo:

This paragraph appears.

While this one is positioned off screen.

But there is no space between.

Using absolute positioning to place content off-screen is very unreliable in EPUB reading systems, however. Absolute positioning of content is often disabled outside of fixed layout publications, as it complicates the rendering and paginating of reflowable content. As a result, the content may appear fixed in an unexpected position on the page, potentially obscuring the other content for visual readers.

Negative text-indent

The text-indent property is sometimes used to push content out of the visible area of the screen by giving it a large negative number. Using a large number allows the text to be rendered on a single line and not reach the visible area of the screen. The content is still read by assistive technologies, even though it is not visually present.

Example — Effect of negative indenting

In the following example, the negative indent on the second paragraph forces it to be rendered off-screen, giving the appearance it is no longer there. Click the button in the demo to toggle the indent.

Markup:

.negative-indent {
text-indent: -9999px;
}

<p>This paragraph appears.</p>
<p class="negative-indent">While this one is pushed
off screen.</p>
<p>But the space the element occupied remains.</p>

Demo:

This paragraph appears.

While this one is pushed off screen.

But the space the element occupied remains.

Even among CSS techniques, negative indents tends to be particularly unreliable. It has been noted that it can cause a large scrollbar to appear in browsers, for example, to allow users to reach the content (although this can be mitigated by setting the directionality). The more common issue with EPUB reading systems is that they ignore negative indents and other attempts to manipulate content outside the viewing area.

It also normally requires other tandem properties, like shrunken font sizes or changes to the element height, to collapse the white space that results from simply moving the first line back. These may not be well-supported in EPUB reading systems, either.

Note

A similar technique employing an indent of 100% to push the code off-screen in the other direction has also been suggested for browsers, but this will also fail in reading systems that prevent content from being positioned off-screen.

Matching color with background

Although it is possible to hide content by making the foreground color match the background, it is arguably the worst option available for EPUB content.

The problems with hiding content this way in EPUB include:

  • Reading systems often apply their own foreground and background colors so that all publications have the same look and feel. As a result, there is no guarantee the text will actually be hidden.
  • Similarly, reading systems often provide users the option to change their color preference for foreground and background text.
  • Reading systems often offer multiple reading modes (e.g., night reading) that reset the foreground and background colors, which will reveal the text even if it is hidden by default.

A more common problem across any user agent is that this method of hiding only obscures the text. Like with changing the visibility, the area the text occupies is still visible.

Assistive technologies will read text hidden this way, though, as changing the color does not actually remove it.

Example — Effect of matching text with background

In the following example, both the color and background-color properties are set to white to obscure the text.

Markup:

.color-match {
color: rgb(255,255,255);
background-color: rgb(255,255,255);
}

<p>This paragraph appears.</p>
<p class="color-match">While this one is colored to
be hidden.</p>
<p>So there is space between.</p>

Demo:

This paragraph appears.

While this one colored to be hidden.

So there is space between.

ARIA Techniques

Although ARIA does not influence the display of content, it contains a number of attributes that can be used both to hide content from, and make hidden content accessible to, assistive technologies.

The aria-describedby attribute

The aria-describedby attribute is commonly used to associate hidden descriptions with an element, although it is not required that the referenced element be hidden. The value of the attribute is the ID of the element that contains the description.

Example — Associating a desciption with an image

Note that the value of the attribute is not a fragment identifier (i.e., it does not include a hash character (#) at the start, as would be expected in a hyperlink).

<img … aria-describedby="img-desc"/>
<p id="img-desc" hidden="hidden">The infographic shows …</p>

The aria-describedby attribute may reference more than one element if the description is broken up across elements.

The problem with using aria-describedby to reference any content, hidden or not, is that it reduces that content to a simple text string (i.e., there is no way to effectively move through the description). Users of assistive technologies consequently have to listen to that entire string of text before they can move on, which can be a frustrating experience.

The use of aria-describedby with hidden content also limits access to the description to users of assistive technologies when there will be many users who could benefit from access.

The aria-details attribute

The aria-details attribute is similar to the aria-describedby attribute in that both identify additional information about the content of an element, but there are a couple of key differences:

  1. It is not intended to reference hidden content.
  2. It does not reduce the referenced content to a simple text string — users are able to navigate the structure of the referenced content.

The value of the aria-details attribute is the ID of the element that contains the description. The attribute can reference only a single element.

The attribute is commonly used to reference the collapsible details element. This use makes it one of the best options for providing descriptions in as minimally obtrusive a manner as possible for all users.

Note

The use of "details" in the element and attribute names is somewhat coincidental. The aria-details element can refer to any element containing additional information.

Example — Adding a description for an image

Note that the value of the attribute is not a fragment identifier (i.e., it does not include a hash character (#) at the start, as would be expected in a hyperlink).

<img src="dollars.jpg" alt="…"
 aria-details="dollar-desc"/>

<details id="dollar-desc">
<summary>Description</summary>
…
</details>

The aria-hidden attribute

Despite its name, the aria-hidden attribute does not control the visual rendering of content. When set, it indicates that the designated content is not to be rendered by an assistive technology (i.e., it is not to be included in the accessibility tree).

Example — Hiding the redundant text of a pull quote

<div role="doc-pullquote" aria-hidden="true">
…
</div>

Unlike the hidden attribute, the value must be "true" or "false". An empty value (aria-hidden="") is the same as not specifying the attribute.

The aria-hidden attribute should rarely be needed in digital publications. It is only of use if there is redundant or extraneous visual content, like pull quotes.

Note that ARIA attributes that can reference hidden content (e.g., aria-describedby and aria-labelledby) ignore this attribute — they will include the hidden text in their values.

The aria-label and aria-labelledby attributes

The aria-label and aria-labelledby attribute both allow an accessible name to be provided for an element.

aria-label allows a hidden name to be specified.

Example — Specifying a hidden name

<section aria-label="Explanation">

The attribute is useful in digital publishing where only whitespace has been used to indicate new sections (e.g., headingless front matter sections, groups of index or bibliography entries). It is important that these sections be given a name, as without an explicit heading a section will not be navigable by assistive technology.

The aria-labelledby attribute serves an identical purpose, but it allows the name to be included in another element (which can be hidden). The value of the aria-labelledby attribute is the ID of the element that contains the name.

Example — Specifying an visible name

Note that the value of the attribute is not a fragment identifier (i.e., it does not include a hash character (#) at the start, as would be expected in a hyperlink).

<div role="note" aria-labelledby="note-hd">
<p id="note-hd" class="hd">Warning!</p>
…
</div>

The aria-labelledby attribute may reference more than one element if the label is split across multiple elements.

It is not strictly necessary to use the aria-labelledby attribute when a section of content has an explicit heading.

Example — Section with explicit heading

<section>
<h2>Definitions</h2>
…
</section>

Assistive technologies will associate the first heading element with the section. It can help with older browsers and assistive technologies to explicitly associate headings, however.

The presentation role

A common misconception is that adding the presentation role to an element is a way to hide content from assistive technologies. It is not!

This misconception arises in part because this role is often applied to images that users do not need to encounter.

Example — Image used for visual spacing

<img src="spacer.href" alt="" role="presentation"/>

In fact, it is the empty alt attribute that signals to assistive technologies that there is no content and the image can be safely ignored.

Setting role="presentation" on any element only removes its semantics. The content of the element is untouched.

Note

The ARIA working group is moving to replace the presentation role with none to better reflect that it is the semantics of the element that are ignored, not the content.

Scripting Techniques

Although JavaScript does not provide any new abilities of its own to hide content, it allows developers to manipulate a document to hide content using all of the techniques mentioned on this page. Developers can dynamically add and remove the hidden attribute, for example, or assign CSS classes to elements. And ARIA, of course, is designed to be modified by script.

Example — Setting attributes and classes

The following example shows how the hidden attribute can be added to an element using the JavaScript setAttribute function and the class hide can be added using classList.add.

   /* set the hidden attribute */
   document.getElementById('hideyho').setAttribute('hidden','');
   /* set a css class */
   document.getElementById('hideyho').classList.add('hide');

The one advantage that JavaScript has over using native techniques directly is that it allows for progressive enhancement when hiding content. There are times when content may need to be toggled on and off depending on user preference.

For example, a book on programming might include examples in multiple languages, allowing the user to selectively enable only the language they are most comfortable with. Using HTML or CSS techniques to hide one language by default could lead to those examples never being available to a user without scripting support (i.e., the scripts to toggle the choice will not work). By instead using JavaScript when the page loads, nothing will be hidden from users if scripting is not available; the scripting fails gracefully without loss of information.

Similarly, if the answers to questions in a textbook are only revealed using script, they will not be accessible to any users.

Example — Progressive enhancement

The following example uses the details element to hide the answer in reading systems that do not support scripting. When scripting is supported, the details element is hidden and a set of radio buttons are enabled instead, with a message about whether the answer is correct or not being dynamically generated.

There are buttons after the demo to reset the question and toggle between the dynamic and static versions.

Markup:

<fieldset>
   <label>Which of the following is a liquid?</label>
   <ul class="q">
      <li>
         <input type="radio" name="q1-ans" value="a"
            onclick="revealResult(true)" hidden="hidden">
         A - Water
      </li>
         
      <li>
         <input type="radio" name="q1-ans" value="b"
            onclick="revealResult(false)" hidden="hidden">
         B - Ice
      </li>
         
      <li>
         <input type="radio" name="q1-ans" value="c"
            onclick="revealResult(false)" hidden="hidden">
         C - Steam
      </li>
   </ul>
   <div id="q1-result" aria-live="assertive" hidden=""></div>
   <details id="q1-static-ans">
      <summary>Answer</summary>
      <p>A - Water</p>
   </details>
</fieldset>

<script>
document.onload = configureTest();

function configureTest() {
  document.getElementById('q1-static-ans').classList.add('hidden');
  document.getElementById('q1-result').removeAttribute('hidden');
  var q1_ans = document.getElementsByName('q1-ans');
  q1_ans.forEach( function(checkbox) {
    checkbox.removeAttribute('hidden');
  });
}

function revealResult(correct) {
  var res_elem = document.getElementById('q1-result');
  var result = correct ? 'Correct!' : 'Sorry, try again!';
  res_elem.textContent = '';
  res_elem.appendChild(document.createTextNode(result));
}
</script>

Demo

Related Links