{"id":321421,"date":"2020-09-25T07:24:35","date_gmt":"2020-09-25T14:24:35","guid":{"rendered":"https:\/\/css-tricks.com\/?p=321421"},"modified":"2020-09-25T07:24:37","modified_gmt":"2020-09-25T14:24:37","slug":"linearly-scale-font-size-with-css-clamp-based-on-the-viewport","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/linearly-scale-font-size-with-css-clamp-based-on-the-viewport\/","title":{"rendered":"Linearly Scale font-size with CSS clamp() Based on the Viewport"},"content":{"rendered":"\n

Responsive typography has been tried in the past with a slew of methods such as media queries and CSS calc()<\/code>.<\/p>\n\n\n\n

Here, we\u2019re going to explore a different way to linearly scale text between a set of minimum and maximum sizes as the viewport\u2019s width increases, with the intent of making its behavior at different screen sizes more predictable \u2014 All in a single line of CSS, thanks to clamp()<\/code>.<\/p>\n\n\n\n

The CSS function clamp()<\/code> is a heavy hitter. It\u2019s useful for a variety of things, but it\u2019s especially nice for typography. Here\u2019s how it works. It takes three values: <\/p>\n\n\n\n\n\n\n\n

clamp(minimum, preferred, maximum);<\/code><\/pre>\n\n\n\n

The value it returns will be the preferred value, until that preferred value is lower than the minimum value (at which point the minimum value will be returned) or higher than the maximum value (at which point the maximum will be returned).<\/p>\n\n\n\n

\"\"
In this example, the preferred value is 50%. On the left 50% of the 400px viewport is 200px, which is less than the 300px minimum value that gets used instead. On the right, 50% of the 1400px viewport equals 700px, which is greater than the minimum value and lower than the 800px maximum value, so it equates to 700px.<\/figcaption><\/figure>\n\n\n\n

Wouldn\u2019t it just always be the preferred value then, assuming you aren\u2019t being weird and set it between the minimum and maximum? Well, you\u2019re rather expected to use a formula for the preferred value, like:<\/p>\n\n\n\n

.banner {\n\u00a0 width: clamp(200px, 50% + 20px, 800px); \/* Yes, you can do math inside clamp()! *\/\n}<\/code><\/pre>\n\n\n\n

Say you want to set an element\u2019s minimum font-size<\/code> to 1rem when the viewport width is 360px or below, and set the maximum to 3.5rem when the viewport width is 840px or above. <\/p>\n\n\n\n

In other words:<\/p>\n\n\n\n

1rem \u00a0 = 360px and below\nScaled = 361px - 839px\n3.5rem = 840px and above<\/code><\/pre>\n\n\n\n

Any viewport width between 361 and 839 pixels needs a font size linearly scaled between 1 and 3.5rem. That\u2019s actually super easy<\/em> with clamp()<\/code>! For example, at a viewport width of 600 pixels, halfway between 360 and 840 pixels, we would get exactly the middle value between 1 and 3.5rem, which is 2.25rem.<\/p>\n\n\n\n

\"Line<\/figure>\n\n\n\n

What we are trying to achieve with clamp()<\/code> is called linear interpolation<\/em>: getting intermediate information between two data points.<\/p>\n\n\n\n

Here are the four steps to do this:<\/p>\n\n\n

Step 1<\/h4>\n\n\n

Pick your minimum and maximum font sizes, and your minimum and maximum viewport widths. In our example, that\u2019s 1rem and 3.5rem for the font sizes, and 360px and 840px for the widths.<\/p>\n\n\n

Step 2<\/h4>\n\n\n

Convert the widths to rem<\/code>. Since 1rem on most browsers is 16px by default (more on that later), that\u2019s what we\u2019re going to use. So, now the minimum and maximum viewport widths will be 22.5rem and 52.5rem, respectively.<\/p>\n\n\n

Step 3<\/h4>\n\n\n

Here, we\u2019re gonna lean a bit to the math side. When paired together, the viewport widths and the font sizes make two points on an X and Y coordinate system, and those points make a line.<\/p>\n\n\n\n

\"A
(22.5, 1)<\/code> and (52.5, 3.5)<\/code><\/figcaption><\/figure>\n\n\n\n

We kinda need that line \u2014 or rather its slope and its intersection with the Y axis to be more specific. Here\u2019s how to calculate that:<\/p>\n\n\n\n

slope = (maxFontSize - minFontSize) \/ (maxWidth - minWidth)\nyAxisIntersection = -minWidth * slope + minFontSize<\/code><\/pre>\n\n\n\n

That gives us a value of 0.0833 for the slope and -0.875 for the intersection at the Y axis.<\/p>\n\n\n

Step 4<\/h4>\n\n\n

Now we build the clamp()<\/code> function. The formula for the preferred value is:<\/p>\n\n\n\n

preferredValue = yAxisIntersection[rem] + (slope * 100)[vw]<\/code><\/pre>\n\n\n\n

So the function ends up like this:<\/p>\n\n\n\n

.header {\n\u00a0 font-size: clamp(1rem, -0.875rem + 8.333vw, 3.5rem);\n}<\/code><\/pre>\n\n\n\n

You can visualize the result in the following demo:<\/p>\n\n\n\n