display vs visibility vs opacity
display: none removes an element from the layout, visibility: hidden hides it but keeps its space, and opacity: 0 makes it transparent, yet still clickable.
Side-by-side comparison
#Takes up space in the layout
- display: none
- No, the space is freed up
- visibility: hidden
- Yes, empty space remains
- opacity: 0
- Yes, empty space remains
Can be clicked or focused with Tab
- opacity: 0
- Yes, it still reacts to clicks and focus
Visible to screen readers
- opacity: 0
- Yes, still read out
A child can reverse it
- display: none
- No, the whole subtree disappears
- visibility: hidden
- Yes, with
visibility: visible - opacity: 0
- Not applicable, the background is only visually transparent
Smooth animation
- display: none
- Not without
transition-behavior: allow-discrete - visibility: hidden
- Changes in a single step
- opacity: 0
- Yes, smoothly
Typical use
- display: none
- Removing an element from the page completely
- visibility: hidden
- Reserving space for something that will appear later
- opacity: 0
- Smooth fade-out and fade-in animations
Example
#.item-none { display: none; }<div class="stage" style="display: flex; gap: 8px;">
<div class="box">1</div>
<div class="box item-none">display: none</div>
<div class="box">3</div>
</div>Definition and usage
#The three ways to "hide" an element differ in how much of its presence remains on the page. display: none removes the element from the layout completely, along with the space it occupied, as if it had never been there. visibility: hidden only hides it; the space in the layout stays empty. opacity: 0 also keeps the space, but structurally the element is still fully present, just visually transparent.
This difference in presence carries over to interaction. An element with display: none or visibility: hidden can’t be clicked or focused with Tab, and screen readers skip it. An element with opacity: 0 behaves as if it were visible: it reacts to clicks, takes its place in the Tab order and is read out by screen readers, which is easy to forget.
This also matters for animation. opacity changes smoothly, so it’s well suited to animated fade-ins and fade-outs. visibility changes in a single step, but you can pair it with transition so the element drops out of interaction exactly when the animation ends. display doesn’t take part in transitions at all by default, though the newer transition-behavior: allow-discrete changes that.
Syntax
#display: none;
visibility: hidden;
opacity: 0;More examples
#.item-hidden { visibility: hidden; }<div class="stage" style="display: flex; gap: 8px;">
<div class="box">1</div>
<div class="box item-hidden" style="visibility: hidden;">2</div>
<div class="box">3</div>
</div>The space left by item 2 stays empty, unlike with display: none.
.ghost { opacity: 0; }<button class="ghost" type="button" onclick="this.textContent = 'Clicked despite opacity: 0'" style="padding: 8px 16px; border: 0; border-radius: 8px; background: #7c3aed; color: #fff;">Invisible button</button>Despite being invisible, the button can still be clicked and focused with Tab, because opacity doesn’t turn off interaction.
Good practices
#- For an animated fade-in, use
opacity, possibly paired withvisibilityandtransition-behavior: allow-discrete. - If the element should disappear completely and free up its space, choose
display: none. - A transparent but still clickable element is a common mistake. Add
pointer-events: noneif it shouldn’t react.
Related entries
#Spotted a mistake or missing an example? Write to us.