What is visual hiding?
When creating accessible interfaces, we sometimes provide text alternatives.
These are similar to the alt attribute on the <img> tag. These text
alternatives usually describe a form control or an icon whose purpose is
visually obvious but not obvious to users with reduced visual ability.
Why not display: none or visbility: hidden?
Let's get the obvious out of the way. There is no out-of-the-box way to hide
an element for just the visually able users but keep it available to the
accessibility technologies. Neither the HTML attributes nor CSS properties
provide such a mechanism. Both display: none and visibility: hidden will
cause screen readers to suppress the text as if it does not exist.
The right way™
Whether it's the right way aside, a way to visually hide text in a way that is still accessible to screen readers is this:
.text-alt {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
}
Let's break down the code:
position: absolutetakes the element out of the document flow so that it takes up no space in the layout.width: 1pxandheight: 1pxmakes the element take up a square pixel on the screen. The reason we are not using 0 here is that some user agents may still treat an element with 0 dimensions as "effectively invisible".overflow: hiddenprevents the contents of the element from showing outside the 1x1px square.clip-path: inset(50%)causes the element to become completely invisible.
Technically we could use just the first and last line to achieve the same
effect in all browsers that support clip-path, but not all of
them do.
A few examples
When a button only contains an icon, we may provide a text alternative in a hidden span:
<button>
<svg class="icon" aria-hidden="true"><use href="icons.svg#folder"></svg>
<span class="text-alt">Open</span>
</button>
When a fieldset has a legend that visually able people do not need, we might hide it visually:
<fieldset>
<legend class="text-alt">Pick a day</legend>
<label>
<input type="radio" name="day" value="1">
<span>Monday</span>
</label>
<label>
<input type="radio" name="day" value="2">
<span>Tuesday</span>
</label>
<label>
<input type="radio" name="day" value="3">
<span>Wednesday</span>
</label>
<!-- .... -->
</fieldset>
When a section heading should remain visually hidden but still exist to allow navigation:
<section aria-labelledby="sidebar">
<h3 id="sidebar" class="text-alt">Sidebar</h3>
<menu><!-- .... --></menu>
</section>
Do not abuse
Visual hiding should really be the last resort. Ideally you (or your product team) should plan your layout so that the text can be included. Visual hiding should only be used in cases where the visual presentation is self-evident but the UI is unusable for those that receive no visual cues.