Visibility
Hiding is two questions, not one. From whom β everybody, or only the eye, or only a screen reader? And for how long β until you take it away, until the reader asks for it, or until the box it sits in is a different size? Answer both and there is usually exactly one right tool, and most of the time it is the browser's, not Yeti's.
Hide it fromβ¦
| Tool | Out of sight | Out of the accessibility tree | Keeps its space | What brings it back |
|---|---|---|---|---|
hidden attribute |
yes | yes | no | removing the attribute |
display: none, your own CSS |
yes | yes | no | your rule not matching |
visibility: hidden, your own CSS |
yes | yes | yes | your rule not matching |
aria-hidden="true" |
no | yes | yes | removing the attribute |
inert |
no | yes | yes | removing the attribute |
visually-hidden |
yes | no | no | nothing; it is always out of sight |
| the skip link | yes | no | no | focus |
details, popover, dialog |
while shut | while shut | no | the reader asking |
data-show / data-hide |
yes | yes | no | the container's width |
print / print with data-print="none" |
in the other medium | in the other medium | no | the medium |
a component's own data-threshold |
it changes shape rather than going | β | β | the container's width |
What the platform does
The hidden attribute
The blunt one, and usually the right one. The element is gone: off the screen, out of the accessibility tree, out of the flow. Yeti's reset makes it win over any display a component sets, so it works on a card or a nav item the same as on a div.
<p hidden>Not in the page at all until something removes this.</p>
State, not styling. If a script is going to show and hide something, this is the attribute to toggle β not a class.
display: none and visibility: hidden
The same thing as hidden and a different thing, respectively, and the difference is space. display: none takes the box out of the layout; visibility: hidden leaves the box exactly where it is and paints nothing in it. When a row must not move as its contents come and go β a validation message, a counter, a spinner beside a button β visibility: hidden is what keeps it still. Foundation 6 called that .invisible; it is two words of your own CSS and Yeti does not wrap it.
.form-status[data-state="quiet"] { visibility: hidden; }
Both take the element out of the accessibility tree.
aria-hidden="true"
The opposite direction: still on the screen, gone from the accessibility tree. It is for something a sighted reader needs and a screen reader would only be delayed by β a decorative icon beside a word that already says what the icon says, or text duplicated for layout.
<a href="/downloads"><svg aria-hidden="true" viewBox="0 0 16 16"><path d="M8 2v9m0 0 4-4m-4 4-4-4M2 14h12" fill="none" stroke="currentColor" stroke-width="2"/></svg> Download</a>
Never put it on anything focusable. A button a screen reader cannot see but can still land on is the worst of both.
inert
Seen, but unreachable and unannounced: no focus, no clicks, no find-in-page, and out of the accessibility tree. It is for the page behind something β a custom overlay you built yourself, a form region disabled while a request is in flight.
View Code
<div inert>
<p>Still visible. Nothing in here can be tabbed to or clicked.</p>
<a href="/settings">Settings</a>
</div>
A native dialog opened with showModal() does this to the rest of the page for you, so a dialog needs none of it.
details, popover, dialog
Hidden until the reader asks, with the browser keeping the state and announcing it. A disclosure is details and summary; a panel that closes on Escape and on a click outside is popover; a modal is dialog. None of the three needs a line of script, and each tells a screen reader what happened, which a toggled class never did.
View Code
<details>
<summary>Shipping and returns</summary>
<p>Ships within two days.</p>
</details>
View Code
<button popovertarget="notes">Notes</button>
<div id="notes" popover>
<p>Only in the page while it is open.</p>
</div>
If you are about to write script to show something, this is the section to re-read first.
What Yeti adds
Four things, for the four questions the platform has no single word for.
visually-hidden
Out of sight, still announced. It is for the name a control needs when its face is a picture, or the words that make the third "Read more" on a page mean something different from the first two.
<a href="/trail-map.pdf">Read more<span class="visually-hidden"> about the trail map</span></a>
It is the one two-word class in Yeti, and the second word is there because hidden is already taken by an attribute that does the opposite. Full page: visually-hidden.
The skip link
A special case of the same recipe, and you get it for nothing. The first link in the body, if it points at a fragment, is hidden the way visually-hidden hides β out of sight, in the tree, still in Tab order β until it takes focus, at which point it appears at the corner of the window. There is no class; being the first link in the body is the whole contract, which is why the base rule is written that way and why a body whose first link is something else will find it hidden. It is a base rule like any other, and the base guide lists it among the rest of what a page gets for free.
<body>
<a href="#main">Skip to content</a>
<!-- the furniture -->
<main id="main">β¦</main>
</body>
Foundation 6 called this .show-on-focus.
data-show and data-hide
By the space available, measured on the nearest size container rather than on the window. Both take a width from the same scale as data-threshold and both mean at or above: data-show="md" is shown from md up, data-hide="md" is gone from md up.
View Code
<div class="container">
<p data-show="md">Shown once this column is 32rem or wider.</p>
<p data-hide="md">Gone once this column is 32rem or wider.</p>
</div>
They need a size container above them and do nothing without one. container is what makes a box into one, and lists which layouts already are.
print
By medium. print on its own is for paper and nowhere else; print with data-print="none" is for everywhere but paper.
<p class="print">Printed from https://foundationcss.com/guides/visibility</p>
<button class="button print" data-print="none" type="button">Share this page</button>
Full page: print.
Not hiding, but the same family
A component with a data-threshold does not hide anything β it changes shape. A nav collapses its links behind a toggle, a pagination drops to the compact form, a card puts its figure above the text instead of beside it. That is always the better answer than shipping two versions of a thing and hiding one, because two versions are two things to keep in step forever. The responsive guide is the whole story.
prefers-reduced-motion is the same shape of question β who gets what β applied to movement rather than to presence. Yeti honours it through the motion tokens, so nothing you write has to ask; the animations guide says how.
What Yeti does not ship
There is no hide-for-small, no show-for-large, no viewport visibility class of any kind, and there will not be one.
A viewport rule breaks the moment the element moves. A columns that was tuned against a wide window is suddenly inside a sidebar, or inside a card, or inside a dialog; the window has not changed and the box has, and every medium- and large- prefix in the markup is now lying. That was true in Foundation 6 too β it was just impossible to fix, because the box could not be measured. It can be now, so data-show and data-hide measure it, and nothing in Yeti asks the window how wide a component should be.
There is also no -only band β no "shown at md and not above". A band is two elements with a marker each, or a nested container, and the -only classes were the rarest of the set. If you find yourself wanting one, it is usually a sign the component should be changing shape instead.