DEV Community

Promise Tochi
Promise Tochi

Posted on • Updated on

Completely responsive CSS values, more than just media queries

Image of CSS code show example of responsive font-size values

The goal of this article is to achieve a font-size value that fluidly transitions from 14px at a browser window width of 769px, to 24px for a 2048px browser window width.

First off, let’s get the definition of a responsive DOM element out of the way. Responsive elements should respond to changes in viewport size, i.e when I reduce or increase the size of my browser window, a responsive DOM element should respond in some predefined way.

With CSS3 media queries, we are able to respond to screen resizes within CSS. Most of the time, these are breakpoints at 480px, 768px, and 769px. These are suitable for most web applications, but what if we could go further than just 3,4,5 break points? What if we could respond to every 1px browser resize all the way from over 2048px to 1px. That means we can create CSS declarations that respond to me reducing my browser window from 2048px to 2047px, responding to every 1px change all the way down to 0px.

Thanks to the CSS3 calc function, and viewport units (vh, vw), we can achieve this functionality.

The calc function lets you perform calculation when specifying CSS property values

Viewport units are represented as percentages of the visible area of a web page. That is the entire browser window, minus the address bar, scroll bar, tabs, etc.

Luckily both calc and viewport units have browser support all the way back to IE9.

html {
  font-size: 1vh;
}
Enter fullscreen mode Exit fullscreen mode

In the code snippet above, if the browser width minus scrollbar is 1800px, font-size will be 18px, that’s 1% of 1800. That’s okay, but on a 800px screen, font-size will be 8px 😮. That’s not what we want.

Thanks to some clever calculations possible with the calc function we can overcome this problem.

If you have written Javascript or some proper programming language, there’s a good chance you’d have come across the mathematical expression below, if you have not, I’ve tried to explain it below.

(Math.random() * (769 - 2048) + 769)
Enter fullscreen mode Exit fullscreen mode

This is a Javascript snippet and what it does is generate a random number within the range of 769 and 2048. Math.random() generates a random number between 0 to 0.9999999999999999. We get that number and multiply it by the difference between 2048 and 769, which is 1279. This ensures random number*(1279+769), always return a value between 769 and 2048. You can try it out yourself, 0*(1279)+769 is 769 and 0.99*(1279)+769 gives you 2035.21.

So we have the basis for further calculations.


In our case, we want a font-size within the range 14px to 24px, so our range is 10px and 14px is our base. What we want is to generate a random number between 0 and 0.999999999999, multiply it by 10 and add it to 14. So that, 0*10+14 is 14, and 0.9999*10+14 is 23.9999, but we don’t have access to Javascript’s Math.random within our CSS. How do we generate the random number we need then?

Let’s take a look at what we have. With the VW viewport unit, we can dynamically access the window’s width with 100vw. So 100vw on a 1366px screen is 1366px, on a 1560px screen, it’s also 1560px, without us hard-coding the specific pixel value.

With our target minimum screen width (769px), maximum screen width (2048px) and dynamically calculated screen width (100vw), we are armed with what we need to generate a random number from 0 to 0.99999999999. By simply doing (100vw — 769px)/2048px, we can generate any value from 0 upwards, depending on the value of 100vw. So if a users viewport width is 1800px, (100vw — 769px)/2048px is calculated as (1800px — 769px)/2048px by the browser, which results in 0.50341796875. Yay, we have our random number. We can now multiply 0.50341796875 by 10 (remember our range?), which results in 5.0341796875. The final step is to add 5.0341796875 to 14px 5.0341796875, which results in a 19.0341796875px font-size for a user with a 1800px viewport width.

The final formula can be written as,

html {
  font-size: minimumPixel + range * ((viewportWidth - minScreenWidth) / maxScreenWidth)
}

/* Example */

html {
  font-size: calc(14px + 10 * ((100vw - 769px) / 2048));
}
Enter fullscreen mode Exit fullscreen mode

So instead of serving all viewport widths between 769px and 2048px the same font width, usually 18px, we can dynamically serve users a more suitable range from 14px to 24px.

This can be combined with media queries to achieve as much responsiveness as possible

/* Example */

/* Mobile and Tablet */
@media (max-width: 768px) { 
  html {
    font-size: calc(16px + 2 * ((100vw - 360px) / 768));
  }
}

/* Laptop and Desktops screens */
@media (min-width: 769px) {
  html {
    font-size: calc(14px + 10 * ((100vw - 769px) / 2048));
  }
}

/* Excessively large screens */
html {
  font-size: 36px;
}
Enter fullscreen mode Exit fullscreen mode

This can be applied to be more than just font-size, it can be used to create paddings, margins, widths that stretch and squeeze as the viewport width increases and decreases.

I hope you enjoyed the article, hopefully you'll use this technique a lot more in your projects.

Top comments (18)

Collapse
 
chiangs profile image
Stephen Chiang • Edited

Awesome article!

Doesn't your final example require calc() to be included or am I missing something?

example:

/* Laptop and Desktops screens */
@media (min-width: 769px) {
  html {
    font-size: calc(14px + 10 * ((100vw - 769px) / 2048px));
  }
}
Collapse
 
promisetochi profile image
Promise Tochi

Wow, thanks for pointing that out, Stephen 😅

Collapse
 
trebuhd profile image
Hubert Dworczyński

Cool! Any chance for a codepen demo?

Collapse
 
alex_escalante profile image
Alex Escalante • Edited

Or you can use D3-scale :)

var x = d3.scaleLinear()
          .domain([14, 24])           // font size
          .range([769, 2048]);     // screen size

Haven't tried it, though…

Collapse
 
promisetochi profile image
Promise Tochi

oh. That looks interesting for Javascript values

Collapse
 
alex_escalante profile image
Alex Escalante • Edited

You can use it with a framework that injects CSS, styled-components or any other…

Collapse
 
katzy687 profile image
Natti Katz

Sooo dope!

Collapse
 
promisetochi profile image
Promise Tochi

Thanks! :)

Collapse
 
sithembelek profile image
sithembelek

Brilliant.

Collapse
 
promisetochi profile image
Promise Tochi

Thank you :)

Collapse
 
vikramj74 profile image
Vikram Jaswal

Brilliant. Thanks for sharing.

Collapse
 
promisetochi profile image
Promise Tochi

Thanks for reading :)

Collapse
 
muchwowdodge profile image
Anton Rhein

A very nice article, thanks for that. I will try it on my landing page project. Will help me alot with writing it completely from scratch while ensuring maximum responisveness. Thanks !

Collapse
 
djekanovic profile image
Dimitrije Djekanovic
Collapse
 
ayman_1012 profile image
Ayman Aladdin

it helped me a lot thanks =)) ❤

Collapse
 
promisetochi profile image
Promise Tochi

Glad to hear that :)

Collapse
 
ismail9k profile image
Abdelrahman Ismail

Thank you!
I think this is related to your post

twitter.com/sarah_edo/status/85654...

Collapse
 
promisetochi profile image
Promise Tochi

Yeah it is, thanks :)