Skip to content

Instantly share code, notes, and snippets.

@getify

getify/1.html

Last active Mar 30, 2021
Embed
What would you like to do?
Ever noticed how vw/vh units in CSS seem to be a bit unreliable on various devices (especially mobile)? Here's my solution.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<title>Test Page</title>
<script>
// early compute the vw/vh units more reliably than CSS does itself
computeViewportDimensions();
</script>
<link rel="stylesheet" href="2.css" />
</head>
<body>
<h1> Test Page</h1>
<p>Some test content.</p>
<script src="3.js"></script>
</body>
</html>
:root {
/* initial CSS computation values, that are overriden by the JS */
--vw-unit: 1vw;
--vh-unit: 1vh;
}
h1 {
/* make the h1 50% of the width of the viewport */
width: calc(50 * var(--vw-unit)); /* instead of '50vw' */
/* make the h1 80% of the height of the viewport */
height: calc(80 * var(--vh-unit)); /* instead of '80vh' */
background-color: blue;
color: white;
}
"use strict";
function computeViewportDimensions() {
if (document.documentElement && document.documentElement.style && document.documentElement.style.setProperty) {
document.documentElement.style.setProperty(
"--vw-unit",
(document.documentElement.clientWidth / 100).toFixed(1) + "px"
);
document.documentElement.style.setProperty(
"--vh-unit",
(document.documentElement.clientHeight / 100).toFixed(1) + "px"
);
}
}
(function listenForViewportChanges(){
// keep the CSS vw-unit/vh-unit CSS variables updated as the viewport changes size (or orientation!)
window.addEventListener("resize",computeViewportDimensions,false);
// work-arounds for browsers that don't fire "resize" when the orientation changes
// ref: https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation/onchange
if (typeof window.screen != "undefined" && typeof window.screen.orientation != "undefined") {
window.screen.orientation.addEventListener("change",computeViewportDimensions,false);
}
// ref: https://www.reddit.com/r/javascript/comments/lttxdy/js_workaround_for_fixing_how_css_vwvh_units_arent/gp61ghe/
// ref: https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/matches
else if (typeof window.matchMedia != "undefined") {
var query = window.matchMedia("(orientation: landscape)");
// handle variances in the event handling in various older browsers
if (typeof query.addEventListener != "undefined") {
query.addEventListener("change",computeViewportDimensions,false);
}
else if (typeof query.addListener != "undefined") {
query.addListener(computeViewportDimensions);
}
else {
query.onchange = computeViewportDimensions;
}
}
// make sure nothing during HTML parsing invalidated the early
// computation (from the <script> embed)
//
// has the DOM already loaded?
if (document.readyState != "loading") {
computeViewportDimensions();
}
// otherwise, assume we can listen for the future DOM-ready event
else {
document.addEventListener("DOMContentLoaded",computeViewportDimensions,false);
}
})();
@privatenumber

This comment has been minimized.

Copy link

@privatenumber privatenumber commented Mar 4, 2021

I love it. Very elegant work around! Have you considered packaging this on to npm?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment