One of the most common questions I hear when discussing CSS best practices is “what unit should I use?” Most of us think and speak in terms of pixels but the
px unit is rarely the best choice. Here’s how this all breaks down:
flex-growunits when setting the size of container elements
pxonly when setting the size of ornamental elements for things like hairline borders
- Omit units altogether when defining
rems for everything else:
min-width, and media query breakpoints
What’s a rem?
rem, similar to
em, is a relative unit. There are great articles out there that explain this in detail so I won’t attempt to regurgitate all that here (see https://zellwk.com/blog/rem-vs-em/).
ems can be a bit tricky to use so 9/10 I’ll say stick with
rem. In short, here’s how the
rem unit works:
- Browsers have a default
16px. This is set at the root element (aka the
remunit is a size that is relative to the root element (that’s what the “r” in rem means: root).
This means if want something to be the equivalent of
14px, the math is 14/16 = the number of rem units =
Why should I use rems (or ems)?
Relative units are preferred over pixels because they honor user preference and are thus more accessible. Browsers allow users to overwrite the default font size. Changing this value sets the root element’s default font size (
font-size: 16px) to a different value. Because
rems are computed relative to the root font size, sizing elements in
rems means that content will scale proportionately. Thus, in almost all cases I recommend using
rems. This applies to
min-width, and so on.
Any drawbacks to rems?
I’ve read that using
rems in media queries containing both a
max-width can be problematic due to how browsers inconsistently round non-whole numbers. Personally, it's rare I need to specify both a min and max value in media query so I’m less concerned with this case and still recommend using
rems in media queries. I recommend always building mobile-first which, more often than not, means defining media queries only with
The “real” (and admittedly small) drawback I see with
rems boils down to my initial assertion: we talk about design in pixels. So when scanning code, if I see
min-width: 18.75rem, I need to do some quick math to convert that to something I can talk about with non-developers: 300 pixels. We can somewhat remedy this issue by creating a function in your preprocessor of choice that does the computation for us and makes it clearer what’s happening. In SCSS, this could look like this:
When to use px?
The short answer is: rarely. The slightly longer answer is pixels can be used when sizing elements that are ornamental and/or do not need to scale relative to the user’s preferred font size. Borders are a great example. Designers often create hairline borders that are only 1 pixel wide. This likely doesn’t need to scale with a user’s preferred font size.
What about %, fr, flex-grow?
Container elements are those that contain content. Think of them as the big rectangles that typically surface as columns containing text, images, and sometimes other container elements. These typically need some form of width specified in order to achieve the desired layout. Container elements should always be defined using relative values like percentage, the
fr unit (for CSS grids), or
flex-grow (for flexbox). This ensures the container element expands and contracts relative to the browser viewport dimensions.
When setting the size of elements using relative values, you may want to specify that the element does not shrink any less than some value. In this situation, I specify a
When should I go unitless?
There is one exception to everything I’ve said up to this point:
The line-height CSS property sets the height of a line box. It’s commonly used to set the distance between lines of text. On block-level elements, it specifies the minimum height of line boxes within the element. On non-replaced inline elements, it specifies the height that is used to calculate line box height.
It’s best to define the
line-heighas a value relative to the
font-size of the element. The way to achieve this is by omitting the unit altogether. As an example, if we want the font size of an element to be 14 pixels and the line height to be 20 pixels, the way we compute this:
font-sizeis value in pixels divided by root font size (= 14 / 16)
line-heightis equal to the desired value in pixels divided by the font size in pixels = 20 / 14