AniUI Academy

Display and Visibility

The core display values — block, inline, inline-block and none — and the real three-way distinction between display:none, visibility:hidden and opacity:0 for hiding an element.

8 min read

Every element has a display value, and it's arguably the single most consequential property in CSS — it decides whether an element behaves like a paragraph, like a word, like a box you can size precisely, or like it isn't there at all. This lesson covers the four foundational values, then a distinction that trips people up constantly: three different ways to make an element invisible, each with genuinely different consequences.

display: block

A block-level element starts on its own new line and takes the full available width of its container by default (even though its content might be narrower). It fully respects width, height, and margin on all four sides.

div, p, h1, section, article, ul, li {
  /* all block-level by default */
}

This is the default display for most structural and content elements — <div>, <p>, headings, list items, and the semantic sectioning elements you met earlier in this course. Stack a few block elements and they appear one below the other, each claiming a full new line.

display: inline

An inline element flows with the surrounding text, wrapping like a word does, and sitting on the same line as its neighbours.

span, a, strong, em {
  /* all inline by default */
}

The real, verified catch: an inline element ignores width and height entirely, and ignores top and bottom margin too. It only takes up as much horizontal space as its content needs, and vertical margin has nothing to push against, because it isn't creating its own line. Left and right margin, and padding on all sides, do still apply — they just don't affect the vertical rhythm of surrounding lines the way they would on a block element.

span {
  width: 200px;   /* has no effect */
  height: 100px;  /* has no effect */
  margin-top: 20px; /* has no effect */
  margin-left: 10px; /* this one works fine */
}

display: inline-block

This is the practical middle ground: an element flows inline with surrounding content, like inline does, but respects width, height, and margin on every side, like block does.

.badge {
  display: inline-block;
  width: 80px;
  height: 24px;
  margin: 4px;
}

A common real use: a row of tag-like badges or buttons that need to sit next to each other on one line, but each needs a fixed size and full margin control that plain inline can't give you.

display: none

The element is removed entirely — no box, no space reserved, and it's also removed from the accessibility tree, so screen readers behave as if it simply doesn't exist on the page. This is the correct choice whenever "hidden" should really mean "not here."

.tooltip { display: none; }
.tooltip.is-open { display: block; }

The three-way distinction: none vs hidden vs opacity

This is the part worth being precise about, because all three visually "hide" an element, and yet they behave completely differently underneath.

Takes up space?In accessibility tree?Focusable / clickable?
display: noneNoNoNo
visibility: hiddenYesNoNo
opacity: 0YesYesYes (unless separately disabled)

display: none — gone completely. No layout space, invisible to assistive technology, can't receive focus or clicks. Use this for content that genuinely shouldn't exist right now (a closed modal, an inactive tab panel).

visibility: hidden — invisible, but its box is still there holding its place in layout. Surrounding elements don't shift to fill the gap. It's also removed from the accessibility tree and can't be focused or interacted with — functionally, it behaves like it's gone, except the space it would have taken is still reserved. Useful when you want to hide something without causing everything else on the page to reflow.

opacity: 0 — this is the one people get wrong. It is purely a paint effect: the element is fully transparent, but it still occupies its layout space, it's still present in the accessibility tree (a screen reader will still announce it), and it's still clickable and focusable, because as far as hit-testing and focus order are concerned, nothing about the element's interactivity changed — it just isn't visible. If you want an opacity: 0 element to also stop receiving clicks, you have to say so explicitly with pointer-events: none, and you'd need visibility: hidden or display: none (or tabindex="-1", or the inert attribute) if you also want it out of the tab order. This combination — opacity: 0 plus keeping interactivity — is exactly what a lot of custom-styled file inputs and accessible-but-invisible overlays rely on, so it isn't a bug to work around, it's a genuinely different tool from the other two.

A preview of what's next

display also has two more values that are powerful enough to deserve their own lessons entirely: display: flex and display: grid, which turn an element's children into a flexible or grid-based layout instead of normal block/inline flow. Those are exactly where this course goes next.

Try it yourself

Three identical-looking boxes are hidden three different ways. Open your browser's inspector on the rendered result (or just read the layout) to see that display: none leaves no gap, visibility: hidden leaves a gap, and opacity: 0 leaves a gap too — but unlike the other two, its "hidden" box is still clickable, demonstrated by the alert firing on click.

Try it yourself
Loading playground...

What to remember

  • block takes a full new line and respects width/height/margin on all sides; inline flows with text and ignores width, height, and vertical margin.
  • inline-block is the middle ground: flows inline, but respects width, height, and margin everywhere.
  • display: none removes an element from layout and the accessibility tree entirely.
  • visibility: hidden hides it visually but still reserves its layout space, and removes it from the accessibility tree and focus order.
  • opacity: 0 only affects paint — the element still takes space, is still in the accessibility tree, and is still clickable/focusable unless you separately turn that off.
  • display: flex and display: grid are up next — they turn an element's children into a real layout system instead of normal flow.

Check yourself

4 questions · pass 3/4 to unlock Units and Sizing

up to 50
  1. 1.Which of these ignores width, height, and top/bottom margin entirely?

  2. 2.An element is hidden with visibility: hidden. What happens to the space it occupied?

  3. 3.Which hiding method keeps an element visible in the accessibility tree and still clickable, unless you separately disable pointer events?

  4. 4.Which display value flows inline with text but still respects an explicit width and height?

4 left to answer