Lesson 15 of 32
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.
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: none | No | No | No |
visibility: hidden | Yes | No | No |
opacity: 0 | Yes | Yes | Yes (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.
What to remember
blocktakes a full new line and respects width/height/margin on all sides;inlineflows with text and ignores width, height, and vertical margin.inline-blockis the middle ground: flows inline, but respects width, height, and margin everywhere.display: noneremoves an element from layout and the accessibility tree entirely.visibility: hiddenhides it visually but still reserves its layout space, and removes it from the accessibility tree and focus order.opacity: 0only 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: flexanddisplay: gridare 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
1.Which of these ignores width, height, and top/bottom margin entirely?
2.An element is hidden with
visibility: hidden. What happens to the space it occupied?3.Which hiding method keeps an element visible in the accessibility tree and still clickable, unless you separately disable pointer events?
4.Which display value flows inline with text but still respects an explicit width and height?
4 left to answer