Sizing in CSS: px vs em vs rem

We have been conversant with using pixels for sizing in CSS, but why use em or rem? When building accessible websites, you need to consider inclusion. When you use px, you don't put user preferences at the forefront. When the user zooms in or change the browser font setting, websites need to adjust to fit the user's setting. px do not scale but em and rem scales.

Sequel to this, setting the font size of the html element in percentage is recommended. Assuming the browser font size is set to 16px (i.e. the default), setting the font size of the html (root) element to 62.5% will default 1rem to 10px.

You may have used em and rem CSS units for a while but the difference between the two still appears vague. In this article, I will discuss the difference and when to use a particular unit to avoid building websites with unproportionate sizing.

The Difference

Pixel (px) is a commonly used CSS unit on websites. px is not scalable, it is an absolute unit. Change in the value of another element does not affect the value of absolute units. The value assigned is fixed irrespective of the user setting.

Element (em) and Root element (rem) are responsive units interpreted into equivalent px unit by the browser. They are relative units. Change in the value of the parent or root element affects the value of relative units. They scale with the device. So, what makes the two different? The difference lies in how the values are derived by the browser. To view the computed values, open the Chrome Developer Tools and navigate to the Computed tab.

The computed pixel value of em unit is relative to the font size of the element being styled. This is also affected by inherited values from the parent elements unless it is explicitly overridden by a px unit which is not subject to inheritance.

The computed pixel value of rem unit is relative to the font size of the root (html) element. This is however affected by the font size setting on the browser as a result of inheritance unless it is overridden by a px unit which is not subject to inheritance.

Using em

With em unit, the computed pixel value is derived from the font size of the styled element while putting the inherited (parent and grandparent) values into consideration. Using em unit can turn out to be complex. em units should be used to allow for scalability within the context of a specific design element e.g. setting the padding, margin and line-height of menu items to use em values works well to properly scale navigation menu items.

em:

Unit = Font size of the element being styled x Specified value of the element being styled

Given a section element with a font size of 14px, when you create a rule, with the padding property set to 3em, it would evaluate to 42px (14 x 3 = 42). This is irrespective of the font size assigned to the html element. Simply put, the font size of the element on which em unit is declared determines the pixel unit value.

/* style */
html {
  font-size: 18px;
}

section {
  font-size: 14px;
  padding: 3em;
}
/* computed style */
html {
  font-size: 18px;
}

section {
  font-size: 14px;
  padding-bottom: 42px;
  padding-left: 42px;
  padding-right: 42px;
  padding-top: 42px;
}

Using rem

When you use rem, the px equivalence depends on the font size of the html element.

rem:

Unit = Font size of the root html element x Specified value of the element being styled

Given a web page with its root element assigned a font size of 18px, and the margin property assigned a value of 2rem. The computed value for the margin would evaluate to 36px (18 x 2 = 36).

/* style */
html {
  font-size: 18px;
  margin: 2rem;
}
/* computed style */
html {
  font-size: 18px;
  margin-bottom: 36px;
  margin-left: 36px;
  margin-right: 36px;
  margin-top: 36px;
}

The Effect of Inheritance on em Unit

When inheritance is applied to em CSS units, the method of calculating the equivalent pixel varies. With em, the child element inherits the value of its parent and up to the grandparent. This alters the supposed pixel value as the inherited value is put into consideration.

em:

Unit = Font size of the element being styled x Font size of the parent and grandparent elements (if any) x Specified value of the element being styled

<section class="page-wrapper">
  Grandparent
  <div class="container">
    Parent
    <div class="container">
      Child
    </div>
  </div>
</section>
/* style */
html {
  font-size: 16px;
}

.page-wrapper {
  font-size: 1.5em;
}

.container {
  padding: 2em;
}

To calculate the padding value of the .container class above, inheritance is put into consideration.

/* computed style */
html {
  font-size: 16px;
}

.page-wrapper {
  font-size: 24px;
}

.container {
  padding-bottom: 48px;
  padding-left: 48px;
  padding-right: 48px;
  padding-top: 48px;
}

The section having page-wrapper class inherits the font size of the parent (html) element (16px). It multiplies that value by the font size (1.5em) which computes to 24px (16 x 1.5 = 24px).

Apparently, the value of the padding specified on the container class will inherit from the parent element. Its padding value will now be computed to 48px (24 x 2 = 48).

If the container class specifies a font size in em unit, the calculation will be extended further to use that value. e.g If a font size of 1.5em is specified on the container class,

/* style */
html {
  font-size: 16px;
}

.page-wrapper {
  font-size: 1.5em;
}

.container {
  font-size: 1.5em;
  padding: 2em;
}

the padding value will be computed as:

Font size of the grandparent element (html) x Font size of the section (page-wrapper) x Font size of the div (container) x the padding value

This will equate to 57.6px (16 x 1.5 x 1.5 x 2 = 72).

/* style */
html {
  font-size: 16px;
}

.page-wrapper {
  font-size: 24px;
}

.container {
  font-size: 36px;
  padding-bottom: 72px;
  padding-left: 72px;
  padding-right: 72px;
  padding-top: 72px;
}

To override this inherited value, you need to explicitly set the unit of the element being styled to px.

For instance,

<section class="page-wrapper">
  Grandparent
  <div class="container">
    Parent
    <div class="container">
      Child
    </div>
  </div>
</section>

With style:

html {
  font-size: 16px;
}

.page-wrapper {
  font-size: 24px;
}

.container {
  font-size: 1.5em;
}

Note that the font size value of the div with container class above is computed based on its parent element, not the root. The interesting thing here is that the Parent and Child in the HTML above do not have the same font size irrespective of the fact that they share the same class name. The font size of Child is computed based on its parent i.e Parent and the font size of Parent is computed based on its parent i.e Grandparent.

It is computed as:

<section class="page-wrapper">
  Grandparent (24px)
  <div class="container">
    Parent (24 x 1.5 = 36px)
    <div class="container">
      Child (36 x 1.5 = 54px)
    </div>
  </div>
</section>

While using em, it is advisable to define the font size on the html element instead of declaring it explicitly on other elements.

The Effect of Browser Settings

The font size set on the browser by the user can affect the value when CSS rem unit is used within a web application. This affects em units also as a result of inheritance.

When no font value is set on html element

Given the example below,

/* style */
html {
  box-sizing: border-box;
}

.page-wrapper {
  font-size: 2rem;
}

the font size of the element with the class name of page-wrapper will depend on the browser settings since no font size is set on the root element. By default, the browser font size is set to 16px and inherited by the root element. If a user alters the font size of the browser through the settings, the page would be rendered to conform to the settings. Assuming the user sets the default font size to 14px, the computed font size value for page-wrapper will equate to 28px (14 x 2 = 28).

When em or rem font value is set on html element

When an em or rem font value is set on the html element with a custom browser setting, the computed pixel value will be a multiple of the browser font size setting with the specified font size.

For instance, if a website's html element has a font-size property set to 1.5em, and the browser font size set to 14px, the computed pixel value of the root element would be 1.5 x 14 = 21px.

The Recommended Setting

Setting the font size of the html element in percentage is recommended. This solves the problem.

Assuming the browser font size is set to 16px (i.e. the default), setting the font size of the root html element to 100% will default 1rem to 16px. This is still not the optimal solution. A better approach will be to use 62.5%. This will equate 1rem to 10px. Starting with this as the base simplifies the calculations.

* {
  box-sizing: border-box;
}

html {
  font-size: 62.5%;
}

body {
  margin: 0;
  font-size: 1.6rem; /* 16px */
}

.page-header {
  font-size: 3.2rem; /* 32px */
}

For browsers that do not support the usage of rem, you can use SCSS mixin or provide a fallback.

* {
  box-sizing: border-box;
}

html {
  font-size: 62.5%;
}

body {
  margin: 0;
  font-size: 16px;
  font-size: 1.6rem;
}

.page-header {
  font-size: 32px;
  font-size: 3.2rem;
}

Final notes

  • Use preprocessors to abstract the calculations using a px to rem converter function
  • Use em only for sizing that needs to scale based on the font size of an element other than the html (root) element.
  • Use rem unit for elements that scale depending on a user's browser font size settings. Use rem as the unit for most of your property value.
  • For complex layout arrangement, use percentage (%).

You may want to learn more about writing better CSS in a codebase

Article Tag  CSS, Accessibility

Share this article:

Stay Updated

    More Articles


    I write about accessibility, performance, JavaScript and workflow tooling. If my articles have helped or inspired you in your development journey, or you want me to write more, consider supporting me.