Skip to main content

CSS display property

CSS display - the property that controls how an element participates in document layout: block box, inline box, flex container, grid container, or nothing at all.

Theory

TL;DR

  • block owns the full row: new line, full parent width, dimensions work
  • inline sits inside text flow: no forced line break, ignores explicit width and height
  • inline-block places inline but respects sizing (the sweet spot for buttons and badges)
  • flex and grid turn the element into a layout container for its children
  • none removes the element from layout completely, no space reserved

Quick example

html
<style> .block { display: block; background: #bcd; margin: 4px 0; } .inline { display: inline; background: #bdc; } .iblock { display: inline-block; background: #dbc; width: 120px; height: 40px; } </style> <div class="block">Block: stretches full width, new line</div> <div class="block">Block: second one stacks below</div> <span class="inline">Inline: flows</span> <span class="inline">next to each other</span> <span class="iblock">inline-block</span> <span class="iblock">respects size</span>

Blocks stack vertically and fill the container. Inlines sit side by side and ignore width: 120px. inline-block does both: flows inline, respects dimensions.

Key difference: block vs inline

Browsers compute display during layout to build the box tree. block creates a block-level box that starts on a new line and stretches to fill the parent's width. inline creates inline boxes that flow horizontally inside the line box and ignore explicit width or height settings. That gap matters: sizing a <span> with width does nothing until you switch it to inline-block.

When to use

  • Full-width sections, cards, navbars -> block
  • Text emphasis, icons inside a sentence -> inline
  • Buttons, badges, image thumbnails with controlled sizing -> inline-block
  • Single-axis alignment: rows of buttons, columns of sidebar links -> flex
  • Two-dimensional layouts: dashboards, page templates, calendar grids -> grid
  • Hiding modals, collapsing error messages, toggling sidebars -> none

Comparison table

ValueBox typeWidth/HeightLine breakWhen to use
blockBlock boxFull parent widthYesSections, cards, navbars
inlineInline boxShrinks to contentNoText spans, icons in prose
inline-blockInline-blockRespectedNoButtons, form inputs
flexFlex containerFlexibleYesRow/column layouts
gridGrid containerGrid-definedYes2D layouts, dashboards
noneNo boxNoneN/AHiding elements

How the browser handles this

CSS engines parse display during the cascade, then use it in the layout phase to build the box tree. block triggers a block-level containing block. flex activates the flex algorithm: it collects children as flex items and distributes free space via justify-content and align-items. Changing display in JavaScript queues a full style recalculation and reflow. none is cheapest: the browser skips the subtree entirely, no box is created, no paint happens.

One thing I noticed in production: toggling display on a large component inside a scroll container causes visible jank because surrounding elements reflow. visibility: hidden or opacity: 0 are cheaper when you only need to hide without removing from flow.

Common mistakes

Mistake 1: expecting transitions with display: none.

css
/* Wrong - transition has no effect */ .modal { display: none; transition: opacity 0.3s; } /* Fix */ .modal { opacity: 0; visibility: hidden; transition: opacity 0.3s, visibility 0.3s; } .modal.open { opacity: 1; visibility: visible; }

display: none removes the element instantly. No intermediate state exists, so no transition fires. Use opacity with visibility when you need a fade effect.

Mistake 2: inline-block baseline jumping.

css
/* Wrong - items align to text baseline, rows look uneven */ .card { display: inline-block; } /* Fix */ .card { display: inline-block; vertical-align: top; }

inline-block aligns to the text baseline by default. Cards of different heights shift up and down in a way that looks broken. vertical-align: top fixes this.

Mistake 3: display: flex on <ul> without resetting list styles.

css
/* Wrong - bullets appear outside the flex container */ ul { display: flex; } /* Fix */ ul { display: flex; list-style: none; padding: 0; margin: 0; }

Mistake 4: display: contents on a flex item.

display: contents makes the element act as if it has no box. Its children become direct participants in the parent flex layout. Apply it to a flex item expecting it to still occupy space, and it disappears from the flex flow. Wrap in a <div> if you need the box to stay.

Real-world usage

  • React: display: isOpen ? 'flex' : 'none' in sidebar and drawer components (Material-UI, Chakra UI)
  • Tailwind CSS: hidden, block, inline-block, flex, grid utility classes
  • Bootstrap: d-none, d-flex, d-block for responsive visibility
  • styled-components / CSS Modules: display: grid for dashboard layouts, display: flex for navigation bars

Follow-up questions

Q: What is the difference between display: none and visibility: hidden?
A: none removes the element from layout entirely, no space is reserved, siblings close in. hidden hides the element visually but the space stays. Use hidden when layout shift would break the design.

Q: Why does vertical-align have no effect on block elements?
A: vertical-align only applies to inline and inline-block boxes. Block elements do not participate in inline formatting context, so the property is ignored.

Q: When does display: contents actually help?
A: When you have a semantic wrapper (like a <li> inside a flex nav) that you do not want to interrupt the flex flow. The wrapper's box disappears but its children are treated as direct flex items. Use with caution: it has known accessibility issues in some browsers.

Q: flex vs grid - when to pick which?
A: Flex handles one axis at a time: a row of buttons, a column of sidebar links. Grid handles both axes simultaneously: a full page layout, a photo gallery with defined rows and columns. They nest freely.

Q (senior): In a flex container with flex-direction: column, why does align-items: stretch make children fill the full width, but margin: auto on a child centers it horizontally instead?
A: align-items: stretch expands the cross-axis size before margins are resolved. margin: auto consumes all remaining free space after the flex algorithm distributes sizes. The spec resolves definite sizes first, then auto margins. So the child gets sized by stretch, but the auto margin overrides alignment by absorbing leftover space.

Examples

Block vs inline side by side

html
<!DOCTYPE html> <html> <head> <style> .container { border: 2px solid #333; padding: 10px; } .block { display: block; background: #adf; margin: 4px 0; padding: 4px; } .inline { display: inline; background: #afd; padding: 4px; } </style> </head> <body> <div class="container"> <div class="block">Block 1: takes full width</div> <div class="block">Block 2: stacks below</div> <span class="inline">Inline 1</span> <span class="inline">Inline 2 - same line</span> </div> </body> </html>

The two block divs stack vertically. The two inline spans sit next to each other on the same line. Setting width: 200px on the inline spans does nothing.

jsx
function Sidebar({ isOpen }) { return ( <nav style={{ display: isOpen ? 'flex' : 'none', flexDirection: 'column', width: 240, background: '#f5f5f5', }} > <a href="/dashboard">Dashboard</a> <a href="/settings">Settings</a> </nav> ); } // isOpen=true -> flex column nav is visible // isOpen=false -> removed from layout, no gap left behind

When isOpen is false, the nav takes zero space and the main content area expands to fill the gap. This is the standard pattern used in Material-UI drawers and Chakra UI sidebars.

Auto margin in flex (senior edge case)

css
.toolbar { display: flex; height: 50px; align-items: center; padding: 0 16px; } .logo { flex: none; } .spacer { margin-left: auto; } /* pushes nav to the right edge */ .nav { display: flex; gap: 16px; }
html
<div class="toolbar"> <img class="logo" src="logo.svg" alt="Logo"> <div class="spacer"></div> <nav class="nav"> <a href="/">Home</a> <a href="/docs">Docs</a> </nav> </div>

margin-left: auto on .spacer consumes all free horizontal space, pushing the nav to the right. This is the standard flex trick for a logo-left, nav-right toolbar without absolute positioning.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?