In this article we will see what happens to the layout model of HTML elements when you use this particular CSS declaration.
The CSS display
property allows us to specify a layout model for HTML elements. When you declare a layout model, browsers internally select a specific algorithm that will be applied to the final rendering of HTML elements.
When we declare display: none
, we're actually performing an hard reset of the default layout model of a given element. The most important consequence of this from a pure JavaScript point of view is that computed dimensions are completely zeroed, especially heights.
Suppose that we want to show a modal overlay on a page. We can create the following HTML structure.
<html>
<body>
<main id="site"></main>
<div id="overlay"></div>
</body>
</html>
Now when we show the overlay we want to hide the main site's container with display: none
. Our overlay should have an height that is equal to the overall height of the viewport. We can write the following CSS code:
#overlay {
width: 100%;
min-height: 100vh;
position: absoute;
top: 0;
left: 0;
z-index: 100000;
background-color: #fff;
display: none;
}
This is the simplest scenario that we can handle. When the overlay switches from none
to block
, browsers see the min-height: 100vh
declaration, which is applicable to a block layout model, and automatically adjust the element's computed height to the desired value. So far so good.
But what happens to #site
? Simply put, now its computed height is zero. In this case this is not a problem, because we don't need to take it into account when we want to display our overlay element.
The question is: what is the actual computed height of the document
object when we apply display: none
to an element? The answer is simple: it's given by the computed height of all elements that still have a display
value othen than none
minus the original computed height of all elements that now have the declaration display: none
.
In our example, the computed height of the document
object is zero. As we said earlier, this is not a problem because our overlay element has a declaration of min-height: 100vh
and there are no more top level elements on that page.
Problems arise when our overlay element must have a dynamic height calculated via JavaScript. In this case we can't simply assign a static minimum height but we actually need to specify an height that equals the original document
computed height.
The solution is to save the original computed height before our hide/show logic (see the MDN reference page).
'use strict';
const originalHeight = document.body.clientHeight;
const overlay = document.querySelector('#overlay');
const site = document.querySelector('#site');
site.style.display = 'none';
overlay.style.minHeight = originalHeight + 'px';
overlay.style.display = 'block';
Two more questions:
- Why did we choose
absolute
instead offixed
? - Why did we choose
min-height
instead ofheight
?
The answer is simple: the overflow
property. When we have some predetermined content, such as a single image or video with fixed dimensions, it doesn't matter which positiong or height algorithm you choose.
But when you have some dynamic content with variable heights, such as a list of blog posts, choosing a fixed height algorithm will force the browser to decide whether to show or not a scrolling mechanism. This is particularly evident on mobile devices, when you'll get the unwanted side effect of having a portion of your contents which is not visible due to the fact that the page scrolling stops at the very bottom of the document.