Skip to content

Instantly share code, notes, and snippets.

Last active May 10, 2023 03:25
Show Gist options
  • Save getify/150ea5a3b30b8822dee7798883d120b9 to your computer and use it in GitHub Desktop.
Save getify/150ea5a3b30b8822dee7798883d120b9 to your computer and use it in GitHub Desktop.
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>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
<title>Test Page</title>
// early compute the vw/vh units more reliably than CSS does itself
<link rel="stylesheet" href="2.css" />
<h1> Test Page</h1>
<p>Some test content.</p>
<script src="3.js"></script>
: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.clientWidth / 100).toFixed(1) + "px"
(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!)
// work-arounds for browsers that don't fire "resize" when the orientation changes
// ref:
if (typeof window.screen != "undefined" && typeof window.screen.orientation != "undefined") {
// ref:
// ref:
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") {
else if (typeof query.addListener != "undefined") {
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") {
// otherwise, assume we can listen for the future DOM-ready event
else {
Copy link

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

Copy link

Find: (?<!-)(\d+)(v(w|h))
Replace: ($1*var(--$2-unit))

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