Why `1vh` CSS size resolve to different pixel size on screen

The problem you're running into here isn't in the CSS layer but is lower level - in the browser rendering engine, and to some extent the physical display hardware.

why CSS rounds a single float number to three different numbers?

This isn't right - the CSS is behaving correctly and is producing exactly the same height value for all three divs in each set. You can verify this by inspecting the elements in dev tools and looking at the calculated height property for each div.

However, that value isn't in whole pixels, it's a fraction of a pixel. And you've hit a classic problem in computer graphics - how do you display fractions of a pixel on a display with discrete pixels?

Short answer -- you can't, perfectly. That's why these three fractional pixel height divs ultimately render at what looks like different heights as you resize them and even move them around on screen. It's the rendering engine doing its best to make them look identical, with varying results.

The reason your manual 'rounding' solution in JS works is because, well, it rounds those heights to whole pixel values! When the pixel values are round, it's much easier for everything to line up perfectly (in the naive case, assuming there isn't fractional pixel padding, margin etc between the divs) and you are less likely to see differences.

Try it! If you remove the Math.round or even simply add 0.75 or something to the rounded result, you'll see the exact same issue with your JS solution, even though all the calculated values are obviously identical.

Again, the problem isn't that the values are different, it's that they're rendered differently by your browser / hardware. The only universally 'safe' workaround is to ensure that the values are in fact round pixel values.

Leading onto this question:

is there any pure CSS solution to safely use viewport sizes

In terms of the above, getting rounded pixel value results, unfortunately no. There is no way with CSS calc() or otherwise to round results dynamically.

As a general suggestion, if you need precise rendering down to the pixel for thin lines etc, responsive CSS probably isn't the tool you want to use. You probably want to stick with static pixel values, but if you really need things to be dynamic and grow and shrink as you change the viewport size, then yes probably you'll want to involve JS for greater control of the rendering.


For me it looks like the following. The result differs by 1px. That reason is because the calculated height of a div is not an integer, it's a float with subpixel values. And a screen cannot display subpixels. So it depends on the position on screen if the browser decide to round to lower or higher value.

enter image description here