Skip to content

Instantly share code, notes, and snippets.

@ChrissiQ
Last active June 25, 2021 21:52
Show Gist options
  • Save ChrissiQ/c1df2e455e7912700f7d06497f11bde5 to your computer and use it in GitHub Desktop.
Save ChrissiQ/c1df2e455e7912700f7d06497f11bde5 to your computer and use it in GitHub Desktop.
CSS Units Post

A bit of CSS Unit Theory

For a while I've been talking about how I am not a fan of the Derekstrap solution for text scaling (using vw), but have not been clear about what is wrong with it, or how I would propose fixing it. I have organized my thoughts and a few references on what is wrong with using vw units for the base font size of a website.

Types of Units

The w3 defines 2 categories of length units:

  • relative lengths, of which there are 2 sub-categories:
    • font-relative lengths (eg. em, rem)
    • viewport-relative lengths (eg. vh, vw, vmin)
  • absolute lengths (eg. px, cm, in)

*The percentage dimension is not a length and has different values depending where it's used. More on that later.

These units each behave differently and have different base calculations. Some are obvious and some are less obvious.

Font-relative lengths are the only type of length defined as being based on the user's chosen font size configuration. These sizes will respond properly to system font size and browser zoom, and have a predictable size based on that defined by the user (for most users, who have not customized their font size, this is just the system size). As far as I know, all browsers know how to deal with font-relative lengths properly, though there are some browser bugs around using em in pseudo-elements (however, rem does not have these issues).

Viewport relative lengths are tied directly to the user's viewport size and do not normally respond to user configuration or browser zoom, and thus are a problem for users who have configured a larger font size - their preference may not be reflected. When using vw units, the user's chosen font size configuration is normally entirely ignored, and zoom behaviour is unpredictable, being implemented differently across browsers.

Absolute lengths are complicated.

Originally the px unit was as straightforward as it seems (1px = one pixel on your device, right?), but over time it has evolved along with our devices to be more complex. In the CSS3 spec, the px unit is called the visual angle unit. Browser and device manufacturers may implement px either based on physical measurements where 1px = 1/96th of 1in, or by using the reference pixel which is the visual angle of one pixel on a device with a pixel density of 96dpi.

Complicated, right?!? If you think a pixel is a pixel is a pixel, that probably hasn't been true in 20 years or so (source needed!!).

I thought this section from the w3 spec on absolute lengths was enlightening:

All of the absolute length units are compatible, and px is their canonical unit.

For a CSS device, these dimensions are anchored either

  1. by relating the physical units to their physical measurements, or
  2. by relating the pixel unit to the reference pixel.

For print media at typical viewing distances, the anchor unit should be one of the standard physical units (inches, centimeters, etc). For screen media (including high-resolution devices), low-resolution devices, and devices with unusual viewing distances, it is recommended instead that the anchor unit be the pixel unit. For such devices it is recommended that the pixel unit refer to the whole number of device pixels that best approximates the reference pixel.

W3 CSS3 specification: Absolute lengths

The percent unit (%) behaves differently depending on where they are used, and so are a versatile unit. font-size defined in percent units behaves like em, but width defined in percent units uses the width of the parent and is not related to any font-size. Contrast this with a width defined in rem units, which will correspond to the current base font size and does not have awareness of the parent's width.

Which unit should I use for font sizes?

Using font-relative lengths (rem) for base font size is sensible, predictable, and good for accessibility.

If you consistently use font-relative lengths (rem), your text will always be readable at the size that the user or device manufacturer intended, and zoom behaviour will be predictable.

Using viewport-relative lengths (vw) for base font size is sensible and predictable, but bad for accessibility (font size cannot be customized by the user).

If you consistently use viewport-relative lengths, some browsers will not properly respond to zoom behaviour, and you will completely clobber the user/device's preferred text size.

In decorative settings this can be good (eg. setting an element with a decorative background image to width: 50vw so that it always fills half the screen), but as a base font size, you have deliberately chosen to ignore the user/device's text size or scaling preferences. This is a terrible accessibility choice and causes unpredictable behaviour across browsers.

Absolute lengths (px), in my opinion, are confusing and far more complicated than most developers realize. Many developers know that, on mobile devices and high-DPI displays, 1px on a webpage may have a different definition than exactly one hardware pixel, but think that it's as simple as dpi or device pixel ratio. Most developers are unaware that px may have a different definition, for example, on non-traditional devices such as televisions and projectors. On those devices, sometimes the visual angle may be used.

If you consistently use absolute lengths (px), everything will probably be fine, but figuring out what this size actually means for different devices can be confusing. 1px is not a hardware pixel and you cannot rely on this measurement.

Conclusion/Application

You should use font-relative lengths for font sizes and containers holding text (you can roughly predict and limit line length this way!). The base font size should always be 1rem. If you set it to something different, you may be clobbering the user's configured font size, and if the user is depending on this in order to read text, you may have made your webpage unusable for them.

You can use viewport-relative lengths with caution and deliberately, but you should never set the base font size to a viewport-relative length. This destroys accessibility and device/user font size/scaling.

You can use absolute lengths, but please remember that 1px on a webpage is not a device pixel, and the 16px = 1rem rule isn't always true. The definition of a visual pixel on web pages is complicated and I think that you should be using rem instead especially if you do not feel like you really understand px.

References and more reading

@davejtoews
Copy link

davejtoews commented Jun 25, 2021

Repeating what I said in Slack:

The accessibility argument is compelling. The only counter I have is that setting the base size is required for some of the magic scaling stuff that Derekstrap does. Setting the base size lets us size non-text elements with ems and have them all scale together. The purpose isn’t just to set font size, but to use a scaling font size around which everything else can be organized. The downsides might make it not worth it. It’s a clever hack, but may, after all, still be a hack.

@davejtoews
Copy link

davejtoews commented Jun 25, 2021

As for what should be in Derekstrap, a couple points.

  1. Derekstrap was not built or intended to be an opinion imposed on all EH projects. With the right config, you can opt in or out of any individual module, including the one with the sizing module
  2. My goal for 1.0 is to make opting in or out of modules even clearer. Rather than including or not including specific files directly I want to set it up to take config variables that will cause an opt in

So, I'm pretty convinced there are some downsides to this approach and we definitely want to make sure you can opt out of it. Perhaps we should make it even an opt out by default. Maybe it should be removed entirely, or reworked, but I think with an opt out that gets less urgent.

@davejtoews
Copy link

For a potential rework I wonder if it would be possible to still use the base size hack, but make sure body text got excluded.

This is potentially even more hacky, but just spitballing.

I think maybe for headings vw sizes still aren't bad, but body text certainly should adhere to user's adjusting w/ zoom.

@ChrissiQ
Copy link
Author

Thanks @davejtoews. I think vw is great for cool effects and headers, but as a base font size it just has too many issues. The accessibility issue is a big one and I think is the worst problem, which, to me, takes it out of consideration. I do like it as a unit, it's extremely useful and versatile! Just not for base font size.

I get your point about Derekstrap not being mandatory - totally cool - but in a lot of projects that use it, the entire site and every component has been designed with this scaling factor in mind, so it can be quite hard to remove or fix. We should at least stop setting the base font size as proportional text with vw and start using it more selectively.

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