Background
This background section is large; here's a handy link to the new unit section if you would like to skip ahead.
However, I think it can be useful to understand how we got where we are. Additionally, this information will be useful to understand when talking about the dvh
and dvw
units later.
Note: while I'll focus mainly on the vh
unit, please know that the vw
unit had the same issues. It's just easier to talk about one of them.
History of vh
The vh
unit, as it originally existed, was defined as
Equal to 1% of the height of the initial containing block.
The initial containing block (ICB) definition can be found here, but I think the first bullet point summarizes it well (emphasis mine): The containing block in which the root element lives is a rectangle called the initial containing block. For continuous media, it has the dimensions of the viewport and is anchored at the canvas origin; In other words, it's the same size as the viewport; or the same size as the content of your website that you can see without scrolling.Expand for more info about the initial containing block
Which is very useful and good... that is, until mobile browsers started doing some tricks to maximize your phone's screen space. To see these tricks, open any webpage on your phone and scroll around some bit, while paying attention not to the content of the webpage but the browser's UI itself.
You may have noticed that the browser's UI changes size as you scroll. And if the browser's UI and viewport changes size, then the question regarding vh
became:
If
vh
is 1% of the initial containing block (ICB), but the ICB changes sizes as a user scrolls, what doesvh
really equal?
First Solution, First Problem
The first and simplest answer to that question was "vh
changes as the ICB changes." Logically, it would seem like that should be the final answer, too.
However, there's a problem with this solution:
Let's say you have a phone that has 100px
of screen space. When you load up a page, the browser UI takes up 15px
which leaves 85px
left for your website's content.
However, your browser is Super Cool, so when you scroll down the browser UI only takes up 10px
, which leaves your website content with 90px
. Or, in table form:
Browser UI State | Browser UI |
100vh in pixels |
---|---|---|
See everything / maximized / first page load / on scroll upward | 15px |
85px |
Small / minimized / on scroll downward | 10px |
90px |
On your Fancy Website™, you have 5 <section style="height: 100vh">
elements on your page. When someone first loads the page, each <section>
is 85px
tall. But as they begin to scroll down, the browser UI begins to change size which causes those section elements to grow by 5 pixels, to a total of 90px
!
Now, let's say the user's now at the bottom of the page looking at the 5th section element. They decide they want to scroll up, which has the side effect of changing the browser UI to the maximum size. That causes vh
to shrink, and your sections are now all 5px
smaller; when you're at the bottom of the page, that's a total of 20px
of difference (4 sections with 5px
each).
Just by scrolling upwards a tiny bit, the content of your page has jumped upwards 1/5 of your total screen space (100px total / 20px smaller)! That is a very jarring experience, and honestly it sucked.
Imagine if you had used vh
for things like font-size
, and how that would look!
Second Solution, Second Problem
With this problem in mind, in 2015 Safari / Webkit engineers decided to change the behavior of vh
units:
Dynamically updating the height was not working, we had a few choices: drop viewport units on iOS, match the document size like before iOS 8, use the small view size, use the large view size.
From the data we had, using the larger view size was the best compromise.
In other words, a dynamic vh
unit was not great, so they changed it to be a static unit equal to the size of the viewport when the browser UI was its smallest (and the content / "view size" was the largest).
About a year later Chrome / Blink engineers agreed and also updated vh
units to do the same.
Which is where we are now (as of the time of this writing) with vh
.
One of the problems with vh
being the "largest view size" is that anything that is height: 100vh
is now larger or overflows the screen when you first load a page. It's pretty difficult, using just CSS, to get content to fit the page exactly.
And so, in 2019, a new CSS proposal was born. And in 2021, that proposal, with feedback and improvements, was accepted in the CSS spec as several new units!
The New CSS Units
The large, small, dynamic, and traditional vh units.
Large Viewport Units
The lvh
& lvw
units are defined as:
The large viewport-percentage units (lv*) are defined with respect to the large viewport size: the viewport sized assuming any UA interfaces that are dynamically expanded and retracted to be retracted.
In other words, the size when the browser UI is the smallest and the website content is the largest. lvh
is essentially how the vh
unit currently (at the time of this writing) acts.
Small Viewport Units
The svh
& svw
units are defined as:
The small viewport-percentage units (sv*) are defined with respect to the small viewport size: the viewport sized assuming any UA interfaces that are dynamically expanded and retracted to be expanded.
Essentially, svh
gives you units that you can use to fill the screen when the browser UI is at its largest, and the website content is at its smallest.
Dynamic Viewport Units
The dvh
& dvw
units are defined as (with emphasis mine):
The dynamic viewport-percentage units (dv*) are defined with respect to the dynamic viewport size: the viewport sized with dynamic consideration of any UA interfaces that are dynamically expanded and retracted. This allows authors to size content such that it can exactly fit within the viewport whether or not such interfaces are present.
The sizes of the dynamic viewport-percentage units are not stable even while the viewport itself is unchanged. Using these units can cause content to resize e.g. while the user scrolls the page. Depending on usage, this can be disturbing to the user and/or costly in terms of performance.
While the dvh
& dvw
units may sound good on paper, the caveats noted in the definition above (and in the first problem & solution section above) actually lead me to believe that you should only use them in very rare and specific situations.
Traditional Viewport Units
With these new units, where does vh
and vw
sit? Interestingly enough, they are currently defined as:
The UA-default viewport-percentage units (v*) are defined with respect to a UA-defined UA-default viewport size, which for any given document should be equivalent to the large viewport size, small viewport size, or some intermediary size.
Personally, I find this definition to be too vague, and I have concerns about how this will affect users and developers. I guess we'll see where it goes!
Top comments (8)
Underrated article. Thank you!
amazing article...
the history makes difference, it makes it easy to understand those
l
,s
, andd
prefixesThis article is a fantastic deep dive into the various viewport units available in CSS! The detailed explanations of vh, dvh, lvh, svh, and vw are incredibly helpful, especially for developers who are looking to create responsive designs that adapt seamlessly across different devices and screen sizes. The visual examples and comparisons make it easy to understand the nuances between these units. It's great to see how dvh and svh can help address some of the limitations of vh in modern web design. Thanks for sharing this comprehensive guide!
Nice article - really appreciate the history, helps it stick in my mind more :)
Awesome articles with the detailed history, thank you!
Thanks for this really helpful article. Learning the history of how decisions are made is so insightful. Do you have any tips for how someone could go about researching the decisions made about
v*
since this article was published in 2021?Now,
min-h-[75dvh]
is best.tailwindcss.com/blog/tailwindcss-v...