Display & Visibility
Master block, inline, inline-block behaviors, and learn the critical difference between display: none and visibility: hidden.
🎯 What You Will Master in This Lesson
📊 The Master Display Comparison Matrix
The `display` property is the master switchboard of CSS. It dictates whether an element acts like a wall of bricks or words flowing in a sentence:
| Display Mode | Starts New Line? | Default Width | Respects width/height? | Vertical Padding/Margin | Common Tags |
|---|---|---|---|---|---|
| display: block; | Yes (forces line break) | 100% of parent width | Yes | Full support | <div>, <p>, <h1-h6>, <section> |
| display: inline; | No (flows in text) | Shrinks to content width | Ignored! | Padding bleeds; Margin ignored | <span>, <a>, <strong>, <em> |
| display: inline-block; | No (flows side-by-side) | Shrinks to content width | Yes | Full support | <button>, <input>, <img> |
| display: contents; | Depends on children | Container has no box! | Ignored on container | Ignored on container | Wrapper divs in Grid/Flex |
| display: none; | N/A (removed) | 0px (no layout box) | N/A | N/A | Hidden modals, collapsed menus |
👻 The 4 Ways to Hide Elements in CSS (Crucial Interview Topic)
Junior developers frequently confuse `display: none` and `visibility: hidden`. How you hide an element has massive implications for screen readers, keyboard accessibility, and browser performance:
- Takes 0 physical space (box collapsed).
- Completely removed from the accessibility tree.
- Cannot receive focus or clicks.
- Cannot be animated with CSS transitions.
- Reserves physical blank space on page.
- Hidden from screen readers.
- Cannot receive focus or clicks.
- Can be transitioned with delays!
- Reserves physical space on page.
- ⚠️ Still fully clickable & keyboard focusable!
- Still read aloud by screen readers.
- Smooth 120fps GPU transitions.
- Clipped to 1px × 1px via `clip-path`.
- Takes 0 visual space on the page.
- ✅ Read loud and clear by screen readers!
- Used for accessible icon buttons.
💻 Live CSS Display Playground
🔍 The Mystery 4px Gap of `inline-block` (And How History Solved It)
In the early days of web development, before Flexbox existed, developers placed navigation tabs or photo grids side-by-side using `display: inline-block;`. But an infuriating phantom gap of approximately 4px appeared between every single element, causing three 33.33% columns to wrap onto a second line!
In HTML, line breaks and spaces between words are collapsed into a single space character. Because `inline-block` elements participate in the typography flow, the newline in your editor between `</div>` and `<div>` is rendered as an actual text space:
<div class="card">Card 1</div> <div class="card">Card 2</div> <!-- The newline above = 4px text space! -->
1. The Modern Solution (Flexbox): Replace `inline-block` with display: flex; gap: 16px;. Flex containers ignore HTML whitespaces entirely and give you precise pixel control.
2. The Historic Hack: Setting font-size: 0; on the parent container, and restoring font-size: 14px; on the children.
🧬 Modern CSS: Inner vs Outer Display Syntax
In the CSS Display Module Level 3 specification, `display` actually sets two distinct behaviors at once:
Dictates how the element behaves relative to its siblings and parent in the document flow:
- block: Starts on a new line, expands to 100% width.
- inline: Sits side-by-side in the text flow.
Dictates how the element lays out its own direct child elements:
- flow: Normal document flow (standard block/inline children).
- flex: Lays children along a 1D flex axis.
- grid: Lays children in a 2D track grid.
display: inline flex; = Outer inline + Inner flex (same as `inline-flex`)display: block flex; = Outer block + Inner flex (same as standard `flex`)display: inline grid; = Outer inline + Inner grid (same as `inline-grid`)display: block flow-root; = Block container that establishes a clean BFCLine-by-Line Code Breakdown
.block-box { display: block; width: 100%; }Forces the element to occupy its own dedicated horizontal row. Successive block elements stack neatly below one another.
.inline-tag { display: inline; padding: 4px 8px; }Flows smoothly inside paragraph sentences. Horizontal padding (left/right) pushes neighboring words away, while vertical padding draws over the lines above and below.
.inline-block-card { display: inline-block; width: 140px; height: 90px; }The hybrid best of both worlds: sits side-by-side with siblings like an inline element, but strictly respects declared `width`, `height`, and vertical margins.
vertical-align: top;Crucial for `inline-block` grids! Prevents elements from aligning to the typographical baseline (which causes jagged cards whenever card content varies in height).
Q1Why does adding `width: 250px; height: 100px;` to a standard `<span>` tag have zero visual effect in the browser?
Q2What is the crucial performance and layout difference between `display: none;` and `visibility: hidden;`?
Q3What causes the mysterious ~4px whitespace gap between two adjacent `display: inline-block;` elements in HTML?
Q4What does the modern `display: contents;` property do to an element?
Practice Challenge: Unhide and Format the Secret Ghost Box
In the live code editor on the right:
- Step 1: Look at
.ghost-boxinside the<style>block. It is currently hidden withdisplay: none;. - Step 2: In the HTML body, add a new element:
<div class="ghost-box">👻 I was invisible!</div>right under Block Box 2. - Step 3: Change
.ghost-box { display: none; }todisplay: block; border-radius: 8px; font-weight: bold;. Notice how the page smoothly reflows to welcome the unhidden element! - Step 4: Temporarily switch it to
visibility: hidden;and notice how an empty gap remains in its place!
💡 Click to view the solution styles
Common Pitfalls & Senior Developer Interview Questions
❌ Pitfall: Inadvertent Hidden Link Click Traps
When developers hide a modal or dropdown using only opacity: 0, the invisible buttons and links are still present in the hit testing layer! Users trying to click text behind the hidden modal will accidentally click the invisible modal buttons. Always pair opacity: 0 with pointer-events: none; visibility: hidden;.
✅ Pro Tip: Use `display: flow-root` for Modern BFC
Forget the ancient `.clearfix` micro-hacks with `::after`! If you have floated children or want to prevent child margin collapse, simply apply display: flow-root; on the parent container. It establishes an independent Block Formatting Context cleanly and without clipping overflow menus.
💬 Interview Q: What is `display: contents` and why is it beloved in CSS Grid and Flexbox?
Often in frameworks like React or Vue, components must be wrapped in a container tag (e.g. <div class="card-wrapper">) for state or props, which inadvertently becomes a grid item and ruins the CSS Grid layout.
Applying display: contents; makes the browser pretend the wrapper div does not exist in the layout tree! The wrapper produces no visual box, zero margin/padding, and its children directly become items in the parent Grid or Flex container.
💬 Interview Q: How do browsers optimize rendering for `display: none` vs `visibility: hidden`?
`display: none` triggers a full Reflow (Layout recalculation): The browser removes the node from the Render Tree, recalculates geometric coordinates for all remaining elements on the page, and repaints.
`visibility: hidden` triggers only a Repaint: Since the physical slot remains intact, zero coordinates change. The browser only repaints the pixels where the element was, making toggling `visibility` computationally cheaper than toggling `display`.
💬 Interview Q: Why does vertical padding work on <span>, but vertical margin does not?
In the inline formatting context, the height of a line box is calculated solely by typography metrics (font size and line-height).
When you add padding-top: 20px to an inline <span>, the background color of the padding is painted on screen, but it does NOT expand the line box height — so it visually overlaps the lines above it. Margins, however, are explicitly defined by the CSS specification to have zero effect on vertical inline layout.