---
title: 'Display Types'
source: 'https://academia.sh/en/courses/css-fundamentals/display-types'
course: 'Visual Presentation with CSS'
language: en
updated: '2026-08-17T18:09:15+00:00'
license: 'CC BY-SA 4.0'
---

# Display Types

The behavioral differences between block, inline, and inline-block boxes; the distinction between outer and inner display type, and the three separate ways of hiding an element.

The previous two lessons computed a box's dimensions, but what **kind** of box a box is was
never asked. Why does a paragraph occupy its own line while an emphasis element inside it
stays in the flow of the text? When both are given `width: 200px`, why does only one change?

The difference comes from the `display` property. This lesson compares the three basic types —
block, inline, and inline-block — across four criteria, and shows that hiding is a separate
matter.

## Three Types, Four Criteria

```js
// display-types.mjs — tabulates which properties the display value affects
const TYPES = {
  "block":        { ownLine: true,  widthApplies: true,  verticalMargin: true,  whitespaceSensitive: false },
  "inline":       { ownLine: false, widthApplies: false, verticalMargin: false, whitespaceSensitive: true  },
  "inline-block": { ownLine: false, widthApplies: true,  verticalMargin: true,  whitespaceSensitive: true  },
  "none":         { ownLine: false, widthApplies: false, verticalMargin: false, whitespaceSensitive: false },
};

const headers = ["display", "own line", "width/height", "vertical margin", "whitespace-sensitive"];
console.log(headers.map((h, i) => h.padEnd(i === 0 ? 14 : 16)).join(""));
for (const [name, props] of Object.entries(TYPES)) {
  const yn = (v) => (v ? "yes" : "no").padEnd(16);
  console.log(name.padEnd(14) + yn(props.ownLine) + yn(props.widthApplies) + yn(props.verticalMargin) + yn(props.whitespaceSensitive));
}

// inline boxes laid side by side: the whitespace character in between is also a box
console.log("\n--- inline layout (whitespace character included) ---");
const pieces = [
  { kind: "inline-block", width: 80 }, { kind: "space", width: 4 },
  { kind: "inline-block", width: 80 }, { kind: "space", width: 4 },
  { kind: "inline-block", width: 80 },
];
let x = 0;
for (const p of pieces) { console.log(`${String(x).padStart(4)} .. ${x + p.width}  ${p.kind}`); x += p.width; }
console.log(`total line width: ${x}  (boxes: ${80 * 3}, spaces: ${x - 240})`);
```

```
display       own line        width/height    vertical margin whitespace-sensitive
block         yes             yes             yes             no              
inline        no              no              no              yes             
inline-block  no              yes             yes             yes             
none          no              no              no              no              

--- inline layout (whitespace character included) ---
   0 .. 80  inline-block
  80 .. 84  space
  84 .. 164  inline-block
 164 .. 168  space
 168 .. 248  inline-block
total line width: 248  (boxes: 240, spaces: 8)
```

The table gives the answer to the previous lesson's questions.

**A block box** fills the containing box's inline axis from end to end and pushes whatever
follows it onto a new line. `width` and `height` apply; margin on all four sides applies too.
A paragraph, a heading, a section, and a list are of this type.

**An inline box** stays in the flow of the text and occupies only as much space as its
content. `width` and `height` declarations have **no effect at all**; the box's size comes
from its content. Vertical margin is also ignored. Emphasis, a link, an abbreviation, and a
general-purpose `span` are of this type.

One warning is needed: on an inline box, horizontal padding and border **do apply**, but the
painted area does not grow the line height. When vertical padding is given to a link, the
colored area grows, the distance between lines does not change, and areas can overlap.

**An inline-block box** sits between the two: from outside it behaves like inline — it does
not occupy its own line, it sits side by side with its neighbors — but from inside it is a
block box; `width`, `height`, and margin on all four sides apply.

## The Whitespace Character Counts in Inline Layout

The second part of the output shows a commonly encountered problem. When three 80-unit
inline-block boxes are placed side by side, the total line width came out not 240 but 248. The
8 units in between come from the **whitespace characters between the boxes** in the source
text.

The reason is that inline layout is text layout. Line breaks and spaces in the source text are
collapsed into a single space character, and that character also takes up space. Its width
depends on the font; the 4 units here are an example value.

The result is that when three boxes are given `width: 33.333%`, they do not fit on one line —
once the spaces are added, the total exceeds a hundred percent. This is the fragile side of
building grid-like layouts with inline-block, and it disappears in the layout systems in the
next course; in those models, text nodes between boxes take no part in layout.

## Outer and Inner Display Type

The `display` property does not say one thing, it says two.

**The outer display type** determines how the box behaves *in its container*: `block` or
`inline`.

**The inner display type** determines how the box lays out *its children*: `flow`,
`flow-root`, `flex`, `grid`, `table`.

In two-value notation, the two are given separately:

```css
.nav { display: block flex; }
```

The old single-value notations are shorthand for this pair: the word `block` means
`block flow`, the word `inline-block` means `inline flow-root`, the word `flex` means
`block flex`. This distinction explains why the `inline-block` type is described as
"block from the inside, inline from the outside" — the word really is made of two parts.

The `flow-root` value also deserves mention: it makes the box an independent root that
completes the flow of its children within itself. What this is for is shown in the floating
elements lesson.

## Changing the Type Does Not Change the Meaning

An element's display type comes from the browser's default stylesheet and can be changed with
a declaration. Writing `li { display: inline; }` lines up list items side by side.

Only the layout changes. The document's meaning — that this is a list item — stays in place,
and programs reading the document tree continue to see it as one. This is a direct consequence
of the structure-presentation distinction built in the Web Fundamentals and HTML course: making
a heading inline does not stop it from being a heading.

The reverse is also true, and it carries a warning: making an element visually resemble
something else does not make it that thing. Giving a `div` element the appearance of a button
does not produce a button that can be focused and activated by keyboard. Appearance is style's
job, behavior and meaning are markup's.

## Three Ways to Hide

`display: none` was the fourth row in the table, and it gave "no" on every criterion. The
reason is that this value **produces no box**. The element stays in the document tree but
takes no part in layout at all.

There are three separate ways to hide something, and their results differ:

| Notation | Produces a box | Occupies space | Visible to assistive technology |
|---|---|---|---|
| `display: none` | No | No | No |
| `visibility: hidden` | Yes | Yes | No |
| `opacity: 0` | Yes | Yes | Yes |

The third row calls for attention: an element whose opacity is set to zero is invisible but is
still there — it can be focused, clicked, and read by a screen reader. Writing `opacity: 0` to
hide something from the user does not remove it from the accessibility tree.

There is a fourth case as well: hiding text **visually** while leaving it for assistive
technology. This cannot be done with `display: none`; it is done with a rule set that clips
the element to a one-pixel area, and is usually named with a utility class like
`.visually-hidden`.

## Types on the Station Page

```css
/* station.css — step 10: display types */
.nav li { display: inline-block; margin-inline-end: 12px; }

.measurement-table caption { display: table-caption; text-align: start; }

.status-badge {
  display: inline-block;
  padding-block: 2px;
  padding-inline: 8px;
  border-radius: 4px;
}

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

The `.status-badge` class is defined as inline-block because it wants two things at once:
staying in the flow of the text and being able to take vertical padding. If it were inline,
the padding would be painted but would not grow the line height; if it were block, it would
drop to its own line.

The `.visually-hidden` class carries out the fourth case above: a box is produced, clipped to a
one-pixel area, and it stays in the accessibility tree. It is used in the measurement table to
write a unit visually once in the column header and repeat it for assistive technology in
every cell.

## Summary

- A block box fills its container's inline axis and occupies its own line; `width`, `height`,
  and margin on all four sides apply.
- An inline box stays in the flow of the text; `width`, `height`, and vertical margin do not
  apply, horizontal padding and border are painted but do not grow the line height.
- An inline-block box is inline from the outside, block from the inside; it lines up side by
  side but takes size and spacing declarations.
- In inline layout, whitespace characters in the source text also take up space; this is why
  the total of boxes placed side by side comes out wider than expected.
- The three ways of hiding give different results: `display: none` produces no box,
  `visibility: hidden` occupies space, `opacity: 0` stays in the accessibility tree and open to
  interaction.

## Next Step

This lesson defined the type of boxes but did not go into detail on how they are laid out. Why
do block boxes stack top to bottom, by what rule are inline boxes broken into lines, why is the
margin between two block boxes not the sum of the two? The next lesson defines the rules of
normal flow and computes margin collapsing with numbers.
