Exploring the CSS display property: A deep dive
Tags: css, webdev
Published: 2024-06-25 16:07:18

**Written by [Ibadehin Mojeed](https://blog.logrocket.com/author/ibadehinmojeed/)✏️**

HTML elements typically follow the standard flow layout — also called “normal flow” — and naturally arrange themselves on the page. In this flow layout, some elements expand to fill their entire parent container and stack vertically, one above the other. Others only occupy the space needed for their content. 

These different behaviors arise from the default `display` property assigned to these elements. In this lesson, we'll dive into the CSS `display` property. We’ll examine its various values in detail with examples and code snippets to illustrate how each value can be utilized.

## What is CSS `display` property?

The CSS `display` property specifies an element’s outer and inner `display` values:

*   **Outer `display` value**: Determines whether its box takes up the full width of its parent container or gets sized based on its content
*   **Inner `display` value**: Controls the layout of the element’s children — that is, whether they adhere to normal flow or follow other layout options

The `display` property also manages whether the element generates any box at all.

### The `display` syntax

The syntax for the CSS `display` property is as follows:

```css
element {
   display: value;
}
```

You can use different values to adjust the element’s outer and inner `display` behavior. Keywords that affect the outer `display` include:

*   `block`: The element fills the entire width of its container. Each new element appears on a new line unless otherwise specified
*   `inline`: The element is sized according to its content. Each new element appears on the same line unless otherwise specified, and will wrap to the next line if there is not enough horizontal space in the parent container

Meanwhile, keywords that affect the inner `display` include:

*   `flow`: The default layout model for elements participating in the normal document flow. Elements are laid out according to their type (block-level or inline)
*   `flow-root`: Creates a new block formatting context, causing the element's children to be laid out using the normal flow while preventing margin collapse with other elements
*   `flex`: Establishes a flex container, ensuring the element's direct children (flex items) participate in a flexible box layout
*   `grid`: Establishes a grid container, ensuring the element's direct children (grid items) are positioned into a grid defined by rows and columns
*   `table`: Ensures the element behaves like a `<table>`, and that its children behave like table-related elements (`<caption>`, `<tbody>`, `<thead>`, `<tfoot>`, `<tr>`, `<th>`, `<td>`)

In the coming sections, we’ll discuss the various `display` values available and how to use them strategically in your web projects. We’ll also explore using multiple `display` property values to specify both the outer and inner `display`.

## The default `display` values: `block` and `inline`

Before we start to apply display values explicitly on elements, the CodePen below demonstrates how some elements are displayed by default. We added background colors to make the example elements stand out individually.

See this [example on CodePen](https://codepen.io/ibaslogic/pen/zYXQdNp).

We’ll use this example to explore the `block` and `inline` values in more detail.

### Block-level elements

In the CodePen above, you can see that the example `<section>`, `<div>`, `<p>`, and `<footer>` elements fill the entire width of their container, each appearing on a new line. These types of elements are called block-level elements, and by default have a display value of `block`:

```css
element {
  display: block;
}
```

Other block-level elements include `<article>`, `<aside>`, `<table>`, `<form>`, and more. 

Setting the `display` property‘s value to `block` can turn a non-block element into a block-level element. 

In addition, block-level elements can accommodate other block-level elements and inline elements. We can adjust various properties for block-level elements, including their height, width, margins, and padding. They are often used to structure webpage layouts, create text content, list, and so on.

### Inline elements

Elements like `<span>` and `<a>` — which you can also see in the CodePen above — only occupy the space required by their content, and they don’t push other elements away. These elements are called inline elements, and they have a `display` value of `inline` by default:

```css
element {
  display: inline;
}
```

Other inline elements include `<img>`, `<button>`, `<strong>`, `<input>`, `<textarea>`, and more. They’re useful when you need elements to appear in line with text without causing line breaks. Setting the `display` property’s value to `inline` transforms a non-inline element into an inline element. Inline elements can’t contain block-level elements, but can accommodate other inline elements. 

Although inline elements typically don’t accept `height` and `width` properties, exceptions like the `<img>` element exist. Applying padding to inline elements doesn't push other elements away, as shown in the CodePen example, and margins only affect horizontal displacement. 

We can target any of these elements in the flow layout and use the `display` property to change their default display values.

## Using multiple `display` property values in CSS

As we mentioned earlier, an element’s `display` property defines both its outer and inner display types. Previously, we could only use a single keyword for this property’s value, as demonstrated above. However, in most cases, this syntax lacks an explicit description of its functionality. 

For instance, `display: block;` or `display: inline;` solely defines the element’s outer display type — that is, whether the element takes up its container’s full width or gets sized based on its content. It doesn’t specify the inner display type, although the default layout behavior for the children is implied, meaning they follow the normal flow. 

Note that in the CodePen above, the `<section>` element’s children are also laid out in the normal flow, following the expected default behavior as block and inline boxes. 

Since [the `display` property’s Level 3 Specification](https://www.w3.org/TR/css-display-3/) was released, we can now utilize two keywords to specify both the outer and inner `display` values. The syntax is as follows:

```css
element {
  display: outer-value inner-value;
}
```

In many cases, using a multi-keyword value will result in the same behavior as a single value. The multi-keyword values simply provide clarity by defining both the outer and inner `display` values. For example, in the earlier CSS specification, we might use the single-keyword value `block` in our `display` property:

```css
element {
  display: block;
}
```

However, it’s now recommended to use the multi-keyword value `block flow` to be more explicit:

```css
element {
  display: block flow;
}
```

This will convey the actual meaning of the `display` value more clearly, although it won’t change the expected behavior.

Here’s a table summarizing how to take a single display property used in older CSS specifications and rewrite it using the more explicit syntax recommended in the Level 3 specification:

<table>

<thead>

<tr>

<th>Old syntax</th>

<th>New syntax</th>

</tr>

</thead>

<tbody>

<tr>

<td>display: block;</td>

<td>display: block flow;</td>

</tr>

<tr>

<td>display: inline;</td>

<td>display: inline flow;</td>

</tr>

<tr>

<td>display: flex;</td>

<td>display: block flex;</td>

</tr>

<tr>

<td>display: grid;</td>

<td>display: block grid;</td>

</tr>

<tr>

<td>display: flow-root;</td>

<td>display: block flow-root;</td>

</tr>

<tr>

<td>display: table;</td>

<td>display: block table;</td>

</tr>

<tr>

<td>display: inline-flex;</td>

<td>display: inline flex;</td>

</tr>

<tr>

<td>display: inline-grid;</td>

<td>display: inline grid;</td>

</tr>

<tr>

<td>display: inline-block;</td>

<td>display: inline flow-root;</td>

</tr>

</tbody>

</table>

Note that `inline-flex` and `inline-grid` are single-keyword display values used in earlier CSS specifications. The updated syntax recommended in the Level 3 specification replaces the hyphen with a space, making them multi-keyword display values.

Similarly, `inline-block` is a single keyword that creates a block formatting context (BFC) on an inline element. It’s now called `inline flow-root`, allowing us to use the inner `display` value of `flow-root` to create a BFC on an inline box. Using both the outer and inner value types enables us to immediately understand the role of an element in the normal flow and the layout used for its children. Let’s look at a few examples of how to apply multi-keyword values to the CSS `display` property.

### Switching to a block-level element

If you’re working with an inline element, setting its `display` property value to `block` `flow` can turn it into a block-level element. The children of that element will follow the normal `flow` layout, behaving as block or inline boxes.

For example, here’s the result of transforming the `<span>` and `<a>` elements in our previous example to block-level elements. See this [example on CodePen](https://codepen.io/ibaslogic/pen/XWQwEKb).

This can be useful if you want an inline element to take up the full width of its parent container, display on its own line, or use block-level style properties. 

Note that [CSS `position` property](https://developer.mozilla.org/en-US/docs/Web/CSS/position) values like `absolute` and `fixed` also affect the element's display. This happens because these values take an element out of the normal flow, making it function independently.

### Switching to an inline element

You can also turn a block-level element into an inline element using multi-keyword values in the `display` property. The children of that element will then follow the normal `flow` layout, behaving as block or inline boxes.

Here’s the result of transforming the `<li>` block elements to inline lists. Check out the [CodePen example](https://codepen.io/ibaslogic/pen/qBGVjQj).

### `display: block flex;` and `display: inline flex;`

Setting the `display` property to `flex` defines an element as flex container. This establishes a new flex formatting context for the element’s contents. The element’s direct children also become flex items and are laid out using [the flex layout model](https://blog.logrocket.com/ux-design/designers-guide-flexbox-grid-layout/) rather than following the normal flow. 

Note that an element’s outer display type is `block` by default when a `flex` value is applied. However, thanks to the CSS Level 3 specification, rather than using a single-keyword value:

```css
element {
  display: flex;
}
```

We can use two-keyword values for clarity, like so:

```css
element {
  display: block flex;
}
```

The CodePen below demonstrates how elements in the normal flow behave when you apply `block flex` to the `display` property. See the [CodePen](https://codepen.io/ibaslogic/pen/oNOrGKb).

As you can see, we have an inline `span` container element with `span` and `a` children. We also have a block-level `article` container element with two `div` children elements. These all behave as expected in the normal flow in their natural state. 

If we switch the display from **default** to **flex** or **block-flex** using the `select` dropdown, the inline container element will become block-level. Meanwhile, the block container element remains unchanged, but its contents change their behavior as they are laid out using the flex layout model.

Suppose you instead wanted to turn the container elements into inline-level elements using the flex layout model. You can do so by applying the `inline-flex` keyword value — or better yet, applying the updated, more explicit syntax and applying the `inline flex` multi-keyword value.

See this [example on CodePen](https://codepen.io/ibaslogic/pen/dyEXXmz).

Remember, the single-keyword value `inline-flex` and the multi-keyword value `inline flex` will result in the same behavior. 

Using both the outer and inner keywords in the `display` property allows for more clarity. 

Switching the display to `inline` `flex` turns the block-level container element into an inline-level element. The contents of the container are also laid out using the flex layout model. 

With this in mind, we can understand the role of a flex element when building a layout with flexbox.

### `display: block grid;` and `display: inline grid;`

Setting the `display` property’s inner value to `grid` defines an element as a grid container. This establishes a grid formatting context for its contents, ensures that direct children become grid items, and lays out the child elements according to [the CSS grid specification](https://www.w3.org/TR/css-grid-1/).

Like Flexbox, the [grid also helps solve certain layout problems](https://blog.logrocket.com/css-grid-guide/). The CodePen below demonstrates how elements in the normal flow behave when you apply the `grid` keyword to the `display` property.

[See the CodePen](https://codepen.io/ibaslogic/pen/gOJMvZm).

If we switch the `select` dropdown from **default** to **grid** or **block grid**, the inline container element becomes block-level, filling the entire parent container, while the block container element remains unchanged. The contents of the containers are also laid out into a grid — you can see how this changes the appearance of the `span` and `a` elements. 

An element’s outer display type is `block` by default when you apply a `grid` value. So, the single-keyword value `grid` and the multi-keyword value `block grid` will produce the same result.

But what if you want to define an element as an inline-level element in a grid container instead? You can do so using the `inline grid` multi-keyword value, which was previously written as the single keyword `inline-grid`. Check out this updated example:

See the [CodePen example](https://codepen.io/ibaslogic/pen/KKLMoKG).

If we switch the display from **default** to **inline-grid** or **inline grid**, the block-level container element will become an inline-level element. The contents of the containers are also laid out into a grid.

### `display: block flow-root;`

Setting the `display` property value to `flow-root` helps contain elements within their parent. `flow-root` creates a “block-level” element with its own BFC. That means the element will behave like a `display: block flow;` but with the new root as its formatting context where everything inside is contained.

If you understand the [CSS concept of margin collapsing](https://blog.logrocket.com/why-your-css-fails/), you’ll know that the vertical margins of adjacent block-level elements collapse into a single margin. A clear example is margin collapsing between sibling elements, like the paragraphs in the CodePen below:

See the [CodePen example](https://codepen.io/ibaslogic/pen/oNRYwNK).

Each paragraph has a `16px` margin at the top and bottom. However, due to margin collapsing, the paragraphs don’t have a `32px` margin between them. Instead, the resulting margin will be the larger of the individual margins — but in our case, the values are equal, so the margin is just `16px`. 

While margin collapsing between siblings prevents extra spacing, margins can also collapse between parents and children, which may lead to undesired results.

The CodePen below demonstrates the issue. Try using the dropdown to apply a `margin-top` to the heading element, creating space within the parent. The `margin-top` of the child is not contained within the parent but collapses to the outside of it:

[See the CodePen](https://codepen.io/ibaslogic/pen/OJYbbwM).

Even though the margin is not contained within the parent, it’s still contained within the viewport. This is because the root `<html>` element itself creates a block formatting context. 

To contain the `margin` within the parent element, we can make the parent a new flow root. The multi-keyword syntax explicitly describes the values like this:

```css
element {
  display: block flow-root;
}
```

In the CodePen below, applying `display: block flow-root;` ensures that the child’s `margin-top` is contained within the parent block element. See this [example on CodePen](https://codepen.io/ibaslogic/pen/rNgWwmP).

Applying some other CSS properties on the parent — like `padding`, `border`, or `overflow` — can also ensure margin is contained within its parent.

### `display: inline flow-root;`

Similar to how `display: block flow-root;` creates a BFC on a block box, we can create a BFC on an inline box. This way, everything inside the inline box will be contained within it. For instance, applying `padding`, and `margin` on inline elements can now push other elements away. Similarly, `width` and `height` values will also apply. 

Previously, we had to use a single-keyword value to achieve this, like so:

```css
display: inline-block; 
```

Now that we can use multi-keyword values, we can write our `display` property more explicitly for better clarity:

```css
display: inline flow-root;
```

Let’s update our [original CodePen example](#default-display-values-block-inline) to demonstrate this behavior. [See the CodePen](https://codepen.io/ibaslogic/pen/mdYOjWE).

The `<span>` and `<a>` are placed inline, as expected of inline elements. However, everything inside the box is now contained. As we can see, we can now apply `width`, `height`, `margin`, and `padding` properties.

### `display: block table`

Adding the `table` value to a block-level element’s `display` property makes it behave like an HTML `<table>` element. This value used to help with creating complex page layouts. Now, we rarely use it, as we can use [the flexbox and grid CSS layout systems](https://blog.logrocket.com/css-flexbox-vs-css-grid/), which provide more flexibility. 

Consider the following HTML table structure in its simplest form:

```html
<table>
  <tr>
    <td>Id</td>
    <td>Name</td>
  </tr>
  {/* ... */}
</table>
```

The CodePen below demonstrates how we can replicate the HTML table in CSS with `display: block table` and other `display` utilities:

[See the CodePen](https://codepen.io/ibaslogic/pen/VwOPaER).

In the code, nested elements are displayed as `table-row` and `table-cell`.

### Reference table: Using multiple CSS `display` property values

You can use the table below as a reference for how to combine inner and outer `display` property values to achieve various effects:

<table>

<thead>

<tr>

<th style="width:20%">Inner display type</th>

<th style="width:40%">Outer display type: `block`</th>

<th style="width:40%">Outer display type: `inline`</th>

</tr>

</thead>

<tbody>

<tr>

<td>`flow`</td>

<td>`display: block flow;`  
Behaves as a block-level element laid out in a document using the normal flow. Essentially the same as display: block, as block elements default to the standard flow layout.</td>

<td>`display: inline flow;`  
Behaves as an inline element laid out in a document using the normal flow. Essentially the same as display: inline, as inline elements default to the standard flow layout.</td>

</tr>

<tr>

<td>`flow-root`</td>

<td>`display: block flow-root;`  
Behaves as a block-level element with a new block formatting context, causing its children to be laid out using the normal flow while preventing margin collapse with other elements. Essentially the same as display: flow-root.</td>

<td>`display: inline flow-root;`  
Behaves as an inline-level element with a new block formatting context, causing its children to be laid out using the normal flow while preventing margin collapse with other elements. Essentially the same as inline-block.</td>

</tr>

<tr>

<td>`flex`</td>

<td>`display: block flex;`  
Behaves as a block-level element, but its children are laid out using the flexbox layout. Essentially the same as display: flex, but with explicit outer block-level behavior.</td>

<td>`display: inline flex;`  
Behaves as an inline-level element, but its children are laid out using the flexbox layout. Essentially the same as display: inline-flex, but with explicit outer inline-level behavior.</td>

</tr>

<tr>

<td>`grid`</td>

<td>`display: block grid;`  
Behaves as a block-level element, but its children are laid out using the grid layout. Essentially the same as display: grid, but with explicit outer block-level behavior.</td>

<td>`display: inline grid;`  
Behaves as an inline-level element, but its children are laid out using the grid layout. Essentially the same as display: inline-grid, but with explicit outer inline-level behavior.</td>

</tr>

<tr>

<td>`table`</td>

<td>`display: block table;`  
Behaves as a block-level table element, making the element behave like an HTML table &lt;table&gt;</td>

<td>N/A</td>

</table>

## Single `display` values

There are two `display` values that can only be used by themselves — `none` and `contents`. Let’s explore how these keywords work with the `display` property.

### `display: none`

Using `display: none` hides an element and its descendants on a webpage. This property is often used to temporarily hide elements that should appear only at specific screen sizes or when triggered by JavaScript. 

Be aware that using `display: none` can cause a potential reflow of the page's layout. If you want to hide an element while keeping the page layout stable, you can use another CSS declaration called `visibility: hidden`. This declaration makes the element invisible while maintaining its space in the layout.

The CodePen below demonstrates the behavior of the `display: none` and `visibility: hidden` declarations. See the [CodePen example](https://codepen.io/ibaslogic/pen/jOoVQgQ).

Selecting `display: none` in the CodePen removes the target `span` element from the layout. In contrast, `visibility: hidden` makes the element invisible while retaining its space.

### `display: contents`

Using `display: contents` makes the element itself disappear, making its children behave as if they are direct children of the parent element. This `display` value is useful when you don’t have control over the markup, which can affect styling — for instance, when we need to have items in the same container for flex or grid layouts.

In the CodePen example below, the `.wrapper` element introduces unnecessary nesting, complicating the flex layout. We want the `.item` elements treated as direct children of the `.flex-container` so they can be distributed accordingly. So, we apply `display: contents` to `.wrapper` to effectively remove it from the layout.

See the [CodePen example](https://codepen.io/ibaslogic/pen/GRarJoz).


## Conclusion

Understanding the CSS `display` property is important for creating well-organized and attractive websites. This guide explained key display values like `block`, `inline`, `inline-block`, `flex`, and `grid`, and how they affect element layout and behavior. It also covered multi-keyword values, which provide clarity by defining both outer and inner display types. 

If you found this guide helpful, please share it online. Feel free to ask questions or share your thoughts in the comments section.

---

##Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, [try LogRocket](https://lp.logrocket.com/blg/css-signup).

[![LogRocket Signup](https://blog.logrocket.com/wp-content/uploads/2019/12/cpu-memory-usage.png)](https://lp.logrocket.com/blg/css-signup)

[LogRocket](https://lp.logrocket.com/blg/css-signup) is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web and mobile apps — [start monitoring for free](https://lp.logrocket.com/blg/css-signup).