Display & Visibility

CSS · Lesson 19 of 55 7 min read Updated

Why does a <div> start on a new line but a <span> sits inside the sentence? Why does width work on one and not the other? The answer is the display property. It decides what kind of box an element makes and how its children are laid out, so it is the switch behind every layout technique in CSS.

In this lesson you will learn block, inline and inline-block boxes, how display turns on Flexbox and Grid, and the different ways to hide an element, including one that keeps content available to screen readers.

Block and inline

Every element has a default display value from the browser's style sheet. Most elements are either block or inline. (The HTML side of this is in Block & Inline Elements.)

Block boxes, such as <div>, <p>, <h1>, <section> and <ul>:

  • start on a new line and stretch to fill the width of their parent;
  • respect width, height, and all margins and padding.

Inline boxes, such as <span>, <a>, <strong> and <em>:

  • sit inside a line of text and are only as wide as their content;
  • ignore width and height;
  • take horizontal margins and padding, but vertical margins do nothing, and vertical padding overlaps the lines above and below instead of pushing them away.

Inline-block is a mix: the box flows in the line like inline, but respects width, height and vertical spacing like block. It suits things like small buttons or badges inside a sentence.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>block, inline, inline-block</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 1rem; line-height: 1.6; }
    span { background: #ffe8cc; border: 1px solid #e0a100; padding: 0.5rem; width: 8rem; margin: 1rem; }
    .inline       { display: inline; }
    .inline-block { display: inline-block; }
    .block        { display: block; }
  </style>
</head>
<body>
  <p>Inline: the bus to <span class="inline">Rohtak</span> leaves at nine. Notice the padding overlapping the lines and the width being ignored.</p>
  <p>Inline-block: the bus to <span class="inline-block">Rohtak</span> leaves at nine. The width, margin and padding all work, and the line makes room.</p>
  <p>Block: the bus to <span class="block">Rohtak</span> leaves at nine. The span now sits on its own line.</p>
</body>
</html>

Same element, same styles, three different display values, three different results.

display turns on layout modes

display actually controls two things: how the box behaves outside (block or inline) and how it lays out its children inside. The most important inside values are:

ValueOutsideChildren are laid out with
blockblocknormal flow (text and stacked blocks)
flexblockFlexbox
gridblockGrid
inline-flexinlineFlexbox
inline-gridinlineGrid
flow-rootblocknormal flow, in a self-contained box

Modern CSS also lets you write the two parts separately, which makes the meaning clearer. display: inline flex is the same as inline-flex, and display: block flex is the same as flex. The two-value syntax is supported in current versions of all major browsers, but the one-word forms are still the most common in real code.

CSS
.toolbar { display: flex; }          /* a block-level flex container */
.chip    { display: inline-flex; }   /* flows in text, lays out its icon and label with flex */
.gallery { display: grid; }

flow-root

display: flow-root creates a block that keeps everything inside it contained. Its children's margins can no longer escape through its top or bottom (see margin collapsing in The Box Model), and it fully wraps any floated children. You may see older "clearfix" hacks used for this in old code; flow-root replaces them.

Hiding elements

There are several ways to hide something, and they behave very differently:

MethodTakes up space?Can be clicked or focused?Read by screen readers?
display: noneNoNoNo
visibility: hiddenYes, an empty gap staysNoNo
opacity: 0YesYesYes
visually hidden classNoYes, if focusableYes
HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Hiding elements</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 1rem; }
    .row { display: flex; gap: 0.5rem; margin-block: 0.75rem; }
    .row div { padding: 1rem; background: #d8e6f8; border-radius: 6px; }
    .none    { display: none; }
    .hidden  { visibility: hidden; }
    .clear   { opacity: 0; }
  </style>
</head>
<body>
  <div class="row"><div>Aarav</div><div class="none">Priya</div><div>Kabir</div></div>
  <div class="row"><div>Aarav</div><div class="hidden">Priya</div><div>Kabir</div></div>
  <div class="row"><div>Aarav</div><div class="clear">Priya</div><div>Kabir</div></div>
</body>
</html>

In the first row, Priya's box is gone and Kabir moves up next to Aarav. In the second and third rows a gap remains where she was. The difference between the last two is invisible here, but important: an element with opacity: 0 is still there for clicks, keyboard focus and screen readers. Use opacity for fade effects in transitions, not to hide content.

The HTML hidden attribute works like display: none, because the browser's default style sheet hides it. Watch out: if your CSS gives that element any display value, for example .menu { display: flex; }, your rule wins and the "hidden" element appears. Many projects add [hidden] { display: none !important; } to protect it.

Hiding visually but keeping it for screen readers

Sometimes text should be available to screen reader users but not shown, such as a label "Search" on an icon-only button. display: none would hide it from everyone. This well-known pattern hides it only visually:

CSS
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

The text is shrunk to a single clipped pixel and taken out of the flow, but it stays in the page for assistive technology. See HTML Accessibility for when to use it.

Common mistakes

  • Setting width on an inline element. It is ignored. Use inline-block, or make the parent a flex container.
  • Vertical margin on links. Inline elements ignore top and bottom margins. Change display if you need them.
  • Hiding with opacity: 0. The element can still be clicked and focused. Use display: none or the hidden attribute.
  • Overriding hidden by accident. A display rule on an element beats the browser's [hidden] style.
  • display: none on content meant for screen readers. Use the visually hidden class instead.

Key points

  • Block boxes start on a new line and fill the width; inline boxes flow in text and ignore width and height.
  • inline-block flows in text but respects width, height and vertical spacing.
  • display: flex and display: grid turn an element into a layout container for its children.
  • display: flow-root contains its children's margins and floats.
  • display: none removes an element completely; visibility: hidden keeps its space; opacity: 0 keeps it interactive.
  • A visually hidden class hides content from the screen while keeping it for screen readers.

Exercise

Make a short sentence about a Jaipur bookshop containing three links styled as small "tag" buttons that sit inside the sentence, have a fixed width of 7rem, padding and rounded corners. Then add an icon-only "Search" button (use the character ⌕) with the word "Search" in a visually hidden span, so screen reader users still hear it.

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Bookshop tags</title>
  <style>
    body { font-family: system-ui, sans-serif; padding: 1rem; line-height: 2; }
    .tag {
      display: inline-block;
      width: 7rem;
      text-align: center;
      padding: 0.2rem 0.5rem;
      border-radius: 999px;
      background: #e8eef7;
      text-decoration: none;
    }
    .visually-hidden {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
      border: 0;
    }
  </style>
</head>
<body>
  <p>Browse <a class="tag" href="#">Fiction</a>, <a class="tag" href="#">Exam guides</a> or <a class="tag" href="#">Hindi poetry</a> at Pink City Books.</p>
  <button type="button">⌕ <span class="visually-hidden">Search</span></button>
</body>
</html>

inline-block lets the links keep their place in the sentence while accepting a width, and the hidden span gives the icon button an accessible name.

Quick Quiz

1. Which display value lets an element sit inside a line of text but still accept a width and height?

2. What is the difference between display: none and visibility: hidden?

3. Why is opacity: 0 a poor way to hide a menu?

4. What does display: inline-flex create?

Learn CSS with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call