Calculate Viewport Size in CSS

Geoff Graham on

A way to calculate the viewport’s width and height without JavaScript, by way of Temani Afif over at CSS Tip:

@property --_w {
  syntax: '<length>';
  inherits: true;
  initial-value: 100vw; 
}
@property --_h {
  syntax: '<length>';
  inherits: true;
  initial-value: 100vh; 
}
:root {
  --w: tan(atan2(var(--_w),1px)); /* screen width */
  --h: tan(atan2(var(--_h),1px)); /* screen height*/
  /* The result is an integer without unit  */
}

The snippet is a hat tip to Jane Ori who originally published it and wrote an explainer for how it works. I’m no math whiz, but I do recognize the tan() function from my high school days as a method for calculating a ratio for the opposite and adjacent sides of a right triangle based on a provided angle.

In other words, tan() divides the triangle’s height (opposite) by the width (adjacent) to produce an angle. All we do is supply it with the angle, i.e. tan( <angle> ).

Why the heck would we do that when we have calc(), right? The problem is that calc() is unable to do the type of division we need. So, what Jane Ori cleverly did was nest the atan() function inside: tan(atan()).

The cleverness is that atan() is the inverse of tan() where we supply it with a ratio dividing the width and height values: atan( <ratio> ). This way, the triangle’s width and height are taken as separate arguments that are calculated before the tan() function does its thing, giving it what it needs to calculate the tangent of an angle.

I’ll let Jane take it home:

So what this trick is doing is kind of silly in most worlds (and probably why nobody pointed it out sooner) because we’re using two trig functions instead of division that calc() implementations can’t do yet.

atan2( Height, Width ) = angle

tan( angle ) = Height / Width

tan( atan2( Height, Width ) ) = Height / Width

Jane Ori, “CSS Type Casting to Numeric: tan(atan2()) Scalars”

You’ll want to check out Jane’s full explainer for another example that calculates an element’s font-size value.