How to implement max-font-size?
Asked Answered
Z

5

105

I want to specify my font size using vw, as in

font-size: 3vw;

However, I also want to limit the font size to say 36px. How can I achieve the equivalent of max-font-size, which does not exist--is the only option to use media queries?

Zeldazelde answered 10/11, 2016 at 13:0 Comment(0)
A
202

font-size: 3vw; means that the font size will be 3% of the viewport width. So when the viewport width is 1200px - the font size will be 3% * 1200px = 36px.

So a max-font-size of 36px can be easily implemented using a single media query to override the default 3vw font-size value.

Codepen demo (Resize Browser)

div {
  font-size: 3vw;
}
@media screen and (min-width: 1200px) {
  div {
     font-size: 36px;
  }
}
<div>hello</div>

Update: With the new CSS min() function, we can simplify the above code - without using media queries (caniuse)

div {
  font-size: min(3vw, 36px);
}

In the above example, the font-size will be at most 36px, but will decrease to 3vw if the the viewport is less than 1200px wide (where 3vw computes to a value less than 36px )


That being said, using viewport units for font-size in the above way is problematic because when the viewport width is much smaller - say 320px - then the rendered font size will become 0.03 x 320 = 9.6px which is very (too) small.

In order to overcome this problem, I can recommend using a technique called Fluid Type AKA CSS Locks.

A CSS lock is a specific kind of CSS value calculation where:

  • there is a minimum value and a maximum value,
  • and two breakpoints (usually based on the viewport width),
  • and between those breakpoints, the actual value goes linearly from the minimum to the maximum.

So let's say we want to apply the above technique such that the minimum font-size is 16px at a viewport width of 600px or less, and will increase linearly until it reaches a maximum of 32px at a viewport width of 1200px.

This can be represented as follows (see this CSS-tricks article for more details):

div {
  font-size: 16px;
}
@media screen and (min-width: 600px) {
  div {
    font-size: calc(16px + 16 * ((100vw - 600px) / 600));
  }
}
@media screen and (min-width: 1200px) {
  div {
    font-size: 32px;
  }
}

Alternatively, we could use this SASS mixin which does all of the math for us so that the CSS would look something like this:

/* 
     1) Set a min-font-size of 16px when viewport width < 600px
     2) Set a max-font-size of 32px when viewport width > 1200px and
     3) linearly increase the font-size from 16->32px 
     between a viewport width of 600px-> 1200px 
*/

div {
  @include fluid-type(font-size, 600px, 1200px, 16px, 32px);
}

// ----
// libsass (v3.3.6)
// ----

// =========================================================================
//
//  PRECISE CONTROL OVER RESPONSIVE TYPOGRAPHY FOR SASS
//  ---------------------------------------------------
//  Indrek Paas @indrekpaas
//
//  Inspired by Mike Riethmuller's Precise control over responsive typography
//                                                                         
//
//  `strip-unit()` function by Hugo Giraudel
//  
//  11.08.2016 Remove redundant `&` self-reference
//  31.03.2016 Remove redundant parenthesis from output
//  02.10.2015 Add support for multiple properties
//  24.04.2015 Initial release
//
// =========================================================================

@function strip-unit($value) {
  @return $value / ($value * 0 + 1);
}

@mixin fluid-type($properties, $min-vw, $max-vw, $min-value, $max-value) {
  @each $property in $properties {
    #{$property}: $min-value;
  }

  @media screen and (min-width: $min-vw) {
    @each $property in $properties {
      #{$property}: calc(#{$min-value} + #{strip-unit($max-value - $min-value)} * (100vw - #{$min-vw}) / #{strip-unit($max-vw - $min-vw)});
    }
  }

  @media screen and (min-width: $max-vw) {
    @each $property in $properties {
      #{$property}: $max-value;
    }
  }
}

// Usage:
// ======

// /* Single property */
// html {
//   @include fluid-type(font-size, 320px, 1366px, 14px, 18px);
// }

// /* Multiple properties with same values */
// h1 {
//   @include fluid-type(padding-bottom padding-top, 20em, 70em, 2em, 4em);
// }

////////////////////////////////////////////////////////////////////////////

div {
  @include fluid-type(font-size, 600px, 1200px, 16px, 32px);
}
@media screen and (max-width: 600px) {
  div {
     font-size: 16px;
  }
}
@media screen and (min-width: 1200px) {
  div {
     font-size: 36px;
  }
}
<div>Responsive Typography technique known as Fluid Type or CSS Locks. 
  Resize the browser window to see the effect.
</div>

Codepen Demo


Update: We can use the new clamp() CSS function (caniuse) to refactor the above code to simply:

div {
  font-size: clamp(16px, 3vw, 32px);
}

see MDN:

clamp() allows you to set a font-size that grows with the size of the viewport, but doesn't go below a minimum font-size or above a maximum font-size. It has the same effect as the code in Fluid Typography but in one line, and without the use of media queries.

p { font-size: clamp(1rem, 2.5vw, 1.5rem); }
<p>
If 2.5vw is less than 1rem, the font-size will be 1rem.
If 2.5vw is greater than 1.5rem, the font-size will be 1.5rem.
Otherwise, it will be 2.5vw.
</p>

--


Further Reading

Fluid Typography

How Do You Do max-font-size in CSS?

Fluid Responsive Typography With CSS Poly Fluid Sizing

Non-linear interpolation in CSS

Although answered 10/11, 2016 at 14:30 Comment(4)
@Although Thanks for this great answer. I learned a lot from this. I wonder why you need to add the extra @media queries for max- and min-width. Isn't it enough to just use the fuild-type mixin only?Shockey
@Shockey You are totally right. Those media queries weren't necessary because they are taken care of in the SASS mixin. I have updated the post and the relevant codepen. Thanks!Although
I use the polyfluid sizing one regularly, and it's great for scaling multiple things at once and keeping everything in check. Honestly, the fact it works is incredible.Endosmosis
@AlexMcCabe That polyfluid sizing one looks great, thanks! The clamp attribute looks like it does not allow all adjustments (linear interpolation implies 2 parameters).Haight
L
59

Here is another idea. The calc function uses double precision float. Therefore it exhibits a step function near 1e18. For example,

width: calc(6e18px + 100vw - 6e18px);

This will snap to values 0px, 1024px, 2048px, etc. see pen https://codepen.io/jdhenckel/pen/bQNgyW

The step function can be used to create abs value and min/max with some clever maths. For instance

max(x, y) = x - (x + y) * step(y - x)

Given step(z) is zero when z<0 and one otherwise.

just an idea, not very practical, but maybe fun to try.


(Caution: this technique depends on an implementation detail that is not in any specification; currently, it works in Chrome and Safari, but not in Firefox, Edge or Internet Explorer, which don’t use double-precision floats for CSS values.)


UPDATE: this post is no longer useful (was it ever?) since CSS now supports min, max, and clamp.

Ledet answered 5/11, 2018 at 0:43 Comment(6)
This has nothing to do with the question (interesting behavior though)Korykorzybski
This has everything to do with the question. font-size: max(3vw, 36px) would be exactly what was asked, and this shows how to make max(x, y) a thing given clever maths, and doesn't even use media queries, which was a secondary (implicit) point in the question.Orcutt
Interesting. This seems to work in Chrome and Safari, but not Firefox, or at least not recent versions of FF. Looks like an artifact of the underlying rendering engine. I'm guessing if this used to work in FF, the Quantum engine fixed it.Liberty
I'm upvoting this answer as it's very clever, but I would never use it in production as it's very obscure. Also, as a previous comment pointed out, not actually reliable.Pubilis
Probably it doesn't work in Firefox because Firefox uses 32-bit numbers rather than 64-bit as Chrome does?Asyut
Christ... I love this. No idea how it works, but nonetheless.Endosmosis
H
36

Another way increases font size slowly, this will not limit max font size, but even on very wide screens, it will look better. Does not answer question in perfect way, but its 1 line...

font-size: calc(16px + 1vw);

Update: CSS improved and i recommend using clamp(min, preferred, max) function:

font-size: clamp(12px, 2vw, 20px);
Honora answered 23/3, 2018 at 10:8 Comment(2)
This one is very interesting one, Below @john Henckel seems to extend this further. He doesnt deserve downvote too either.Oratory
This combines well with the accepted answer's use of @media query to limit the max size.Picasso
P
4

At some point, the font-size exceeds the 36px scale right, find that. Assuming, it exceeds when the width: 2048px:

@media screen and (min-width: 2048px) {
  .selector {
     font-size: 36px;
  }
}

Yes, unfortunately you need to use the @media queries. I hope that doesn't affect anything.

Picklock answered 10/11, 2016 at 13:3 Comment(0)
A
1

According to this website (there are ads in this site), If you don't want to use clamp():

font-size: 24px;  

font-size: min(max(3.5vw, 16px), 40px);

Line one for IE.
Line two for others, means font-size:3.5vw, max-font-size:40px, min-font-size:16px.

Avalon answered 23/2, 2022 at 2:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.