REM vs EM - The Great Controversy

Original author: Zell Liew
  • Transfer


I present to you the translation of a rather large and voluminous article about the eternal debate about which units to use for typesetting: em 's or rem 's. In which cases it is worth using some units, and in which others. You will find a lot of code, examples and their explanations.

Welcome to the world of typography and relative units =)

************

One of the most effective typographic methods on the web is to use relative units of measure rem and em.

The question is what to use? For a long time the debate between the adherents of rem'ov and em'ov who are trying to prove that it is necessary to use "their" units.

In this article I will take the liberty of making a comparison between rem and em. You will learn what rem is, and what em are, and how to use them to build modular components.

What is EM?


Wikipedia tells us:
em - in typography, a relative unit of length equal to the size of the current font


This statement does not make sense on the web, since we do not use point-size. But it makes sense if we replace the point size with the font size (font-size).

This means that: 1em = 20px in the case when the css selector has the font-size rule: 20px;
h1 { font-size: 20px } /* 1em = 20px */
p { font-size: 16px } /* 1em = 16px */


The em unit can be used to specify font sizes. In fact, using relative values ​​like em for font-size is good practice .

h1 { font-size: 2em } /* Что это вообще означает?! */


What is the actual font-size of h1?

We will have to take a look at the parent element to calculate the font size of this h1. Lets say the parent is html and its font-size is set to 16px.

Following this, we can see that the calculated value of h1 is 32px, or 2 * 16px.

html { font-size: 16px }
h1 { font-size: 2em } /* 16px * 2 = 32px */


In fact, it’s a bad idea to set the font-size for html in pixels (px), as this will override the user's browser settings.

Instead, you can choose percentages as the font-size value, or just don't set it in html.

Note: font-size will be set to 100% if you yourself did not specify it.

html { font-size: 100% } /* это значит, что по умолчанию размер шрифта будет 16px*/


For most users (and browsers), a font size of 100% will default to 16px until they change it in their browser settings. Although rarely anyone does this.

Okay, what's next? Back to em.

Em is also used to set values ​​for other properties , in addition to font-size. margin and padding are two of those properties that are measured in ems.

This is where most people get confused with em values.

Consider the following code. What will be the margin-bottom value for both elements: h1 and p? (Assume the font-size of the html element is set to 100%)

h1 {
  font-size: 2em; /* 1em = 16px */
  margin-bottom: 1em; /* 1em = 32px */
}
p {
  font-size: 1em; /* 1em = 16px */
  margin-bottom: 1em; /* 1em = 16px */
}


Are you surprised that the margin-bottom value set to 1em is different in both cases?

This phenomenon is explained by the fact that 1em is equal to the font size of the element. Since the font-size of the h1 element was set to 2em, other properties of this h1 (the same margin-bottom) will already start from the new font-size value. That is, for them 1em will be equal to 32px.

People are confused by the fact that 1em can take on different meanings in different parts of the code. This can confuse you specifically if you just started to deal with em.

These are these em. Well, let's go further. Ahead of us are waiting for rems.

What is a REM?


Rem is the root em (Root Em). It is designed to ease the computational problems that many sometimes encounter.
This is a typographic unit equal to the root (base) font-size value. This means that 1rem will always be equal to the font-size value that was defined in html.

Consider the same code as above, only we will use rems already. How will the margin-bottom value change now?

h1 {
  font-size: 2rem;
  margin-bottom: 1rem; /* 1rem = 16px */
}
p {
  font-size: 1rem;
  margin-bottom: 1rem; /* 1rem = 16px */
}


As you can see, 1rem will always take a value equal to 16px, and it does not matter where you apply it (until you change the font-size of the html element)
There is a dependency. This is easy to understand.

Such are the rems. It’s not so difficult to understand how they work, knowing how em works, do you agree?

Now, let's get to the tastiest part of the article. So rem or em?

REM's or EM's?


This is a very controversial issue.

Some developers have completely avoided using rem, claiming that using these units makes their components less modular. Other developers use them for everything, preferring the simplicity that they provide.

Oddly enough, but I still fell into the trap of using em'y and rem'y in my work at different stages of development. I was delighted with how ems helped me in creating modular components, but I could not stand all the difficulties that they introduced into my code. I also liked how with the help of rems all the calculations were much easier, but I was enraged by the hacks that had to be written to make my components modular.

It turns out that em and rem have both strengths and weaknesses. And they need to be used in different ways, depending on the circumstances.

How? I have two simple rules :

  1. Set values ​​in em if properties scale relative to font-size;
  2. In all other cases, set the values ​​to rem.


Has it become a little easier? Well, let's look at writing a simple component (let it be a title) using both em and rem, and you will see these two rules in action.

Use only REMs to create the title element.


Say you have an h2 header element that looks like this:

Hello! I am the headline!

The header styles should be similar to the following if you specify everything in rem:

.header {
  font-size: 1rem;
  padding: 0.5rem 0.75rem;
  background: #7F7CFF;
}


Everything goes according to plan.

Next, let's create a bigger heading, because elements of different sizes can be located on one page.
When we do this, let's try to inherit as many styles as possible.

The markup for our second header will look something like this:

заголовок!


CSS will be like this:

.header {
  font-size: 1rem;
  padding: 0.5rem 0.75rem;
  background: #7F7CFF;
}
.header--large {
  font-size: 2rem;
}


Unfortunately, our code did not look better. There is too little free space between the edges of our .header - large element and the title text itself.


There is not enough free space between the edges and the text of our large header.

If you insist on using only rems, the only way to solve this problem is to override the padding with .header - large:

.header {
  font-size: 1rem;
  padding: 0.5rem 0.75rem;
  background: #7F7CFF;
}
.header--large {
  font-size: 2rem;
  padding: 1rem 1.5rem;
}



Well, now it’s become easier to breathe!

Have you noticed anything? The font-size of the .header element is large twice that of the .header element. As a result, the padding for the .header - large element is also double that of the .header element.

What happens if we have more headings of different sizes, or if the headings need to be resized? You already understand how specifying property values ​​in rems can cause duplication and super complex code.

We can simplify our code in such a way that we don’t have to redefine the padding of the .header - large element, if we are not afraid to use both em and rem in the aggregate.

.header {
  font-size: 1rem;
  padding: 0.5em 0.75em;
  background: #7F7CFF;
}
.header--large {
  font-size: 2rem;
}


As you can see, ems can be incredibly useful if you have properties that need to be scaled along with the font size of the element. From here the first rule is born.

Next, let's see what happens if you use only em's in your header.

Use only EMs to create the title element.


The header implementation code on ems is not much different from the code on rems that we have already met. All we need is to replace rems with ems:

.header {
  font-size: 1em;
  padding: 0.5em 0.75em;
  background: #7F7CFF;
}
.header--large {
  font-size: 2em;
}


Both .header and .header - large will look exactly like their doubles on rems.

Exactly what is needed?

Nah!

It is highly unlikely that your site will contain only one title element and nothing else. We need to consider how it interacts with other elements.

As a rule, these elements go before or after the heading, as here:


Headings have different connections with other elements.

The markup for this block will be like this:

Заголовок

Параграф с текстом

Параграф с текстом

Заголовок

Параграф с текстом



We will also add margin-right and margin-left for paragraphs:

p {
  margin-left: 0.75em;
  margin-right: 0.75em;
}



Oh, the padding at the first heading is not aligned with the text of the paragraph

Nooooo! :( the

padding on the left and right of the .header element - large is too big!

If you insist on using only ems, the only way to solve this problem is to override the padding-left and padding-right properties on .header - large:

.header {
  font-size: 1em;
  padding: 0.5em 0.75em;
  /* Прочие стили */
}
.header--large {
  font-size: 2em;
  padding-left: 0.375em;
  padding-right: 0.375em;
  margin: 0.75em 0; 
}



Now everything looks right!

Have you noticed anything? The font-size of the .header element is large twice that of the .header element. However, the padding-left and padding-right of the .header element are large half the size of the padding-left and padding-right of the .header element!

As in the previous case, we can simplify our code if we agree to use em and rem together. In particular, for padding-left and padding-right we will use rems, and for padding-top and padding-bottom we will use ems.

.header {
  padding: 0.5em 0.75rem;
  font-size: 1em;
  background: #7F7CFF;
}
.header--large {
  font-size: 2em;
}


As you can see, ems can be incredibly useful if you have properties that need to be scaled along with the font size of the element. However, you will run into problems if you need to change the property values ​​relative to the root (initial) font-size value.

It has become more clear how rem and em work in the same component, agree?

Now, let's go up a notch and see how the heading and paragraph interact with the grid.

Grid Components


Before we continue, let's combine our heading and paragraphs into a single component:



Заголовок

Некий текст внутри параграфа



Here are the basic styles for our component:

.component {
  background: white;
  border: 2px solid #7F7CFF;
}
.component__header {
  font-size: 2em;
  padding: 0.5em 1.5rem;
  background: #7F7CFF;
  margin: 0;
}
.component p {
  padding-left: 1.5rem;
  padding-right: 1.5rem;
  margin: 1.5rem 0;
}


So far so good. Here we see everything that we have already met before.

Move on. This component can be anywhere on our site. For instance:

  1. In the content part;
  2. In the sidebar;
  3. In any part of our grid;
  4. ...



Likely places where our component can be located The

title of our component should become smaller (i.e., decrease its font-size) if the component is located in a narrow part of the site, for example, in the sidebar.


A title element on the grid.

There is an option on how to do this. We can modify the class of our component. The markup will now look like this:



Well, the style:

.component--small .component__header {
  font-size: 1em;
}


Now for the component styles. The same rules apply here:

  1. Set values ​​in em if properties scale relative to font-size;
  2. In all other cases, set the values ​​to rem.


As in the case of the title element, you can determine for which properties it will be necessary to set sizes in ems. This will need to be done for those properties that directly interact with the rest of the page. There are two ways to think about the best way to build our component:

  1. Properties of all internal elements are scaled along with the font-size of the component;
  2. The properties of only some internal elements are scaled along with the font-size value of the component.


Let's look at both cases, go through each of the paths, and you will understand what I had in mind.

The first way. The properties of all internal elements are scaled along with the font-size of the component


Let's start with an example to see what such a component looks like:



Have you noticed how the font-size, margin and padding of all the elements inside the component change at the same time?

If your component behaves in the same way when resizing, then you need to specify all sizes in ems. That is, the code becomes:

.component {
  background: white;
  border: 2px solid #7F7CFF;
}
.component__header {
  font-size: 2em;
  padding: 0.5em 0.75em; /* заменили единицы измерения на em */
  background: #7F7CFF;
  margin: 0;
}
.component p {
  padding-left: 1.5em; /* заменили единицы измерения на em */
  padding-right: 1.5em; /* заменили единицы измерения на em */
  margin: 1.5em 0; /* заменили единицы измерения на em */
}
// Маленький вариант
.component--small .component__header {
  font-size: 1em;
  padding-left: 1.5em; /* добавили изменяемый padding в em'ах */
  padding-right: 1.5em; /* добавили изменяемый padding в em'ах */
}


Then, in order for the changes in sizes to work, you need to change the font-size property of the component.

.component {
  // Другие стили
  @media (min-width: 800px) {
    font-size: 1.5em;
  }
}




So far so good.

Let's complicate our example a bit now.

Imagine that you have a grid like this. The vertical and horizontal margins on all devices should remain the same (from an aesthetic point of view, this will be correct).


The same indentation on a grid of the form 1 + 2.

The markup for this grid is as follows:



I set the gaps between the grid elements in 2em, given that the base font-size is 16px. In other words, the calculated width of each gap is 32px.

The challenge is this: separate the small components A and B with 32px indentation. For starters, we can try setting the margin-top component B to 2em.

.component {
  /* Другие стили */
  @media (min-width: 800px) {
    font-size: 1.25em;
  }
}
.component + .component {
  margin-top: 2em;
}


Unfortunately, the result is not happy. The margin between the small components A and B is greater than the width of the vertical gap with a visible area (viewport) of more than 800px.


The space between the small blocks A and B is not the same as the space of the vertical gap at viewport> 800px

Buuuu :(

This is because the font-size of the component is 1.5em (or 24px) when the visible area becomes more than 800px. At that moment, when the font-size becomes 24px, the calculated value of 2em becomes 48px, which is different from the 32px we were trying to get.

Rrrrrr! (╯ ° □ °) ╯︵ счастье

What a blessing that we can solve this problem by simply replacing units measurements on rem, because we know that the width of the gaps varies depending on the bases of font-size.

.component + .component {
  margin-top: 2rem;
}



The vertical indent is now horizontal!

TA-dah! The problem is solved :) Here is an example on Codepen , you can play around with the code.

Note: You will have to use Flexbox to build such a grid. I will not explain how I built it, as this is beyond the scope of the article. I advise you to read this article if you want to learn more about Flexbox.

Yes, by the way, I didn’t come up with this technique. Chris Coyier wrote about this a year ago (he is a genius!).

Anyway, ready to move on? If yes, we pass to the second case. If not, feel free to leave comments, and I will try to explain this to you in some other way.

Путь второй. Свойства лишь некоторых внутренних элементов масштабируются вместе со значением font-size компонента.


The first case is easy to explain. The drawback, however, is that you have to adhere to your modular grid ( Note lane: what it is, you can read it here ), vertical rhythms ( Note lane: what it is, you can read it here ) and you have to be sure that all components are the same size at the same time (especially when you create responsive sites).

Sometimes you need to change a small area of ​​a component without resizing everything else.

For example, you need to change the font-size of the headers with a larger visible area (viewport).


Only the headings change in size when the visible area changes.

Let's describe the styles of this example, taking as a basis the styles that we described above:

.component {
  background: white;
  border: 2px solid #7F7CFF;
}
.component__header {
  font-size: 2em;
  padding: 0.5em 1.5rem;
  background: #7F7CFF;
  margin: 0;
}
.component p {
  padding-left: 1.5rem;
  padding-right: 1.5rem;
  margin: 1.5rem 0;
}
.component--small .component__header {
  font-size: 1em;
}


As soon as the font-size of the header changes, at the border of the visible area of ​​1200px, we can safely use rems as the units of measure for each property (except for the padding-top and padding-bottom at the header)

.component {
  background: white;
  border: 2px solid #7F7CFF;
}
.component__header {
  font-size: 2rem; /* заменяем единицы измерения на rem */
  padding: 0.5em 1.5rem; /* заменяем единицы измерения на rem */
  background: #7F7CFF;
}
.component p {
  padding-left: 1.5rem; /* заменяем единицы измерения на rem */
  padding-right: 1.5rem; /* заменяем единицы измерения на rem */
  margin: 1.5rem 0; /* заменяем единицы измерения на rem */
}
.component--small .component__header {
  font-size: 1rem; /* заменяем единицы измерения на rem */
}


After that, you can change the font size in the header on different viewports by simply adding media to them:

.component__header {
  font-size: 2rem;
  @media (min-width: 1200px) {
    font-size: 3rem
  }
}
.component--small .component__header {
  font-size: 1rem;
  @media (min-width: 1200px) {
    font-size: 1.5rem
  }
}




TA-dah! Noticed that when we resize the browser window, only the font-size of the title changes? This is what you need to do in the second case :)

One more moment


Since only a few typography sizes are recommended, I often abstract the font-size property of the component. Thus, I can be sure that my typography will remain the same in all components.

h2 { 
  font-size: 2rem;
  @media (min-width: 1200px) {
    font-size: 3rem
  } 
}
h3 { 
  font-size: 1rem; 
  @media (min-width: 1200px) {
    font-size: 1.5rem
  }
}
.component__header { @extend h2; }
.component--small .component__header { @extend h3; }


That's all with the second case. Here is an example on Codepen , you can play around with the code.

I already anticipate your question, so first I will answer it: What method should you use?

I will say that it all depends on the design.

Personally, I often use the second rather than the first, as I prefer to abstract typography into a separate file.

To summarize


What to use, rem or em? I think this question is not entirely correct. Both rem and em have their strengths and weaknesses, and they can be used together - this will help you write simple, modular components!

Now for you! Which side do you take in this dispute? In the comments below, I would gladly read what you think about this :)

Also popular now: