CSS
07-August-2024

What is the difference between display: none, visibility: hidden and opacity: 0 in CSS?

CSSBrowserdisplayvisibilityopacity

display visibility opacity difference | Hero Image | s.mani.in

CSS offers us few properties in order to "not show” an element on the screen. These properties are display: none, visibility: hidden and opacity: 0. Although the apparent outcome is the same, they are inherently different from each other. Let’s explore them in this article.



Some background on Rendering Pipeline

For an element to be visible on the screen, the browser pushes that element through a process called Critical Rendering Path (CRP) or Rendering Pipeline.

CRP consists of 6 stages -

  1. DOM Tree Construction
  2. CSSOM Tree Construction
  3. Render Tree Construction
  4. Layout
  5. Painting
  6. Compositing

We won’t go into details of CRP stages as this is out of scope of this article, but will briefly explain to create a ground for the main objective of this article.

When a browser receives an HTML file from the server, it creates a DOM Tree out of the structure mentioned in the HTML file. Similarly, when the browser receives a CSS file, it creates a CSSOM Tree.

These two kinds of trees themselves are not enough to supply the necessary information to the browser for drawing and painting the element on the screen. We need to combine them into another kind of tree, called the Render Tree. This tree has all the information required by the browser (such as element’s dimension, position, coordinate, color, stacking context etc) to draw out an element on the screen.

Note

You can compare Render Tree with the blue print of a building to be developed. The way we need a blue print of a building before the actual construction starts, we need the render tree before showing anything on the screen.

Once the render tree is made, the layout phase starts. In this, the browser actually draws and places the element’s corresponding skeleton, or box, on the screen.

In the coloring phase, the browser gives the color to the pixels of the element box drawn in the previous step.

And in compositing, the browser combines the layers residing in different stacking contexts into one layer to get the final pixel values in the screen.



Base Code

Let’s consider the following code as the base, and on this we will do the appropriate modifications to demonstrate the difference as mentioned in the title of this article.

HTML Code
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Display-Visibility-Opacity</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div class="section">Section-1</div>
    <div class="section target" id="targetSection" tabindex="0">
      <p>Target Section</p>
      <button id="targetButton" tabindex="0">Click Me</button>
    </div>
    <div class="section">Section-3</div>
    <script type="text/javascript" src="./index.js"></script>
  </body>
</html>
HTML
CSS Code
* {
  box-sizing: border-box;
}

.section {
  position: relative;
  padding: 20px;
  border: 1px solid black;
  background-color: lightgray;
  transition: all 0.2s ease-in-out;
}

.section.target {
  margin: 20px 0;
  background-color: rgb(253, 173, 76);
}

.section.target:hover {
  background-color: blueviolet;
}

.section.target:focus {
  background-color: green;
}

.section.target > button:focus {
  background-color: green;
}
CSS
JavaScript Code
const targetSection = document.querySelector("#targetSection");
const targetSectionButton = document.querySelector("#targetButton");

targetSectionButton.addEventListener("click", () => {
  console.log("Section 2 Button Clicked");
});

targetSection.addEventListener("click", () => {
  console.log("Section 2 Clicked");
});

targetSectionButton.click();
JavaScript

This is how it currently looks like.

Display Visibility Opacity | Base Code| Hero Image | s.mani.in

We will apply those 3 css properties on the target section. We have applied the click handler on the target section container and button. We are clicking the button programmatically, as can be seen from the console output as soon as the page is loaded.

Target section also has the css hover logic. Moreover, we can access the target section container and the button inside it using tab button on keyboard. Single tab means that the target section container is selected, and double tab means that the button inside is selected.



What does display: none do?

When you set the display property of an element as none, the render tree is constructed without that element. As a result, the layout and painting process for that element does not occur and it seems that the element is not even there.

Naturally, the pointer and keyboard events, such as click, hover, tab events etc, are not emitted on elements having this css property.


Example

Let's change the css of target section in this way

.section.target {
  display: none;
  margin: 20px 0;
  background-color: rgb(253, 173, 76);
}
CSS

The page looks like this after making above change.

Display None Output | Base Code| Hero Image | s.mani.in

We can see that after assigning none to the display css property, the "target section" is not visible on the screen, as if it wasn't the part of HTML ever. On top of that, pointer and keyboard events can't be emitted in the usual way.

However, even though target section is not visible, we can see that as soon as page was loaded, all the click handlers were called and console statement were logged in response to the programmatic click of the button, implying that the element is a part of the dom tree, but not render tree.

Note

You can programmatically click the button again. Just execute the following in the browser's console -

targetSectionButton.click();
JavaScript


What does visibility: hidden do?

When you set the visibility property of an element as hidden, the element receives the dimensions and placement coordinates in the layout phase, but it is not assigned any color in the painting phase.

In other words, in the final outcome, that element, having visibility as hidden, will occupy the same space and dimensions, but that space would not have any coloring pertaining to that element. The pointer and keyboard events are also not emitted on the elements having this css property.


Example

Let's apply the visible:hidden css to the target section -

.section.target {
  visibility: hidden;
  margin: 20px 0;
  background-color: rgb(253, 173, 76);
}
CSS

Following changes were observed after making the above-mentioned changes-

Visibility Hidden Output | Base Code| Hero Image | s.mani.in

We can see from the above image that nothing pertaining to target section is printed on the screen but it is occupying the screen space with the exact dimensions as what we saw in base code example, implying that that element reached till the layout phase, but didn't proceed further to the painting phase.

Like the results of display: none, we can see that the click handlers were called and console statement were printed upon the programmatic invocation of button click on page load.


Now the questions arises - why does visibility: hidden even exist?

We have seen earlier that display: none element is not part of the Render Tree. When display property is set to a value other than none, browser calculates its dimensions and draws it out on the screen.

Now suppose, with the help of a variable, you are toggling the display css property of that element between none and block. Due to this, browser will everytime do the calculation for its dimensions and placements, causing the layout to shift.

If your objective is just to make the element invisible without having layout to shift, visibilty: hidden turns out to be the recommended approach.



What does opacity: 0 do?

When you set the opacity property of an element as 0, the element receives the dimensions and placement coordinates in the layout phase, but it is not assigned any color in the painting phase.

It may seem like the effects caused by visibility: hidden, but it is different from that slightly. With this CSS property and value, the element emits "pointer & keyboard" events, even though the element is not visible on the screen.


Example

Change the css of target section in the following way -

.section.target {
  opacity: 0;
  margin: 20px 0;
  background-color: rgb(253, 173, 76);
}
CSS

The result of this change is like below -

Opacity Zero Output | Base Code| Hero Image | s.mani.in

As you can see, the output of opacity: 0 is same as the output of visiblity: hidden. However, there is a difference. Try clicking in the empty space where target section was rendered.

Opacity Zero Click Output | Base Code| Hero Image | s.mani.in

The click handler for the target section container is called and the corresponding statement is logged. If you place your cursor at the position where button was rendered and click over there, you will observe the click handler corresponding to the button will be called.

It implies that in the case of opacity: 0, the pointer and keyboard events are emitted.

Note

Try hitting the tab keyboard button twice and hit enter. You will observe that both the console statements are logged in response to the invocation of programmatic click of the button.



Summary

PropertyIn Render Tree?In Layout?PaintedPointer EventsKeyboard Events
display: noneNoNoNoNoNo
visibility: hiddenYesYesNoNoNo
opacity: zeroYesYesNoYesYes