I often see many junior developers struggling with em and rem when reading the instructor’s code or examples.
“Why can’t you just use px (pixels)? Isn’t that what matters in the end, no?”
I think it’s a valid question but an incorrect outlook. Using em and rem leads to a more responsive and interactive end-product, and they’re easier than using px for a big codebase once you understand the use case properly.
1. What are CSS Units?
Let’s go back a few steps and understand the fundamentals first.
In lay terms, CSS units define how elements are sized and spaced in a layout. Broadly speaking, these units fall into two categories: absolute units and relative units.
Absolute Units: These include px (pixels), cm (centimeters), mm (millimeters), and (inches). For example, 100px will always be 100 pixels on a small mobile screen or a large desktop monitor. While absolute units are predictable, they are less ideal for responsive design.
Relative Units: These units scale based on other values, with em and rem used most. Relative units are ideal for responsive and accessible designs since they can be adapted across different devices and screen sizes.
2. What is Em, and how to use it in CSS?
The em unit is a relative unit that scales based on the size of its parent element. So, any change in parent size will be accordingly reflected in the child elements as well.
It’s highly useful when you want your elements to remain scalable and flexible as the environment around them shifts.
Let’s break it down with an example:
<div class="parent" style="font-size: 16px;"> <p class="child" style="font-size: 2em;">This text will be 32px</p> </div>
In this example:
- The parent div has a font size of 16px.
- The child p element uses 2em, meaning its font size will be 2 times the parent’s (16px * 2 = 32px).
Note: Because em is a multiplier, it cascades down through your CSS. This can sometimes cause unintended issues when nesting elements.
For example, if you have multiple nested elements, the font size could keep multiplying, leading to unexpected, oversized elements.
<div class="parent" style="font-size: 16px;"> <div class="nested-parent" style="font-size: 1.5em;"> <p class="child" style="font-size: 1.5em;">This text might become too large!</p> </div> </div>
Here’s the math:
- The nested parent has a font size of 1.5em, meaning 1.5 * 16px = 24px.
- The child inside the nested parent has a font size of 1.5em, meaning 1.5 * 24px = 36px.
Effective Use of em:
This CSS unit is great for scalable layouts where you want to maintain flexible sizing within a specific module or component of your design.
It works great, provided you know the cascading effect and don’t use it in (complicated) nested elements. Em is not ideal for globally consistent sizing, as it depends heavily on parent elements.
3. What is Em, and how to use it in CSS?
The rem unit, short for root em, is also relative, but instead of the parent, it’s calculated based on the root element’s font size — usually the <html> element.
Let’s look at an example:
<html style="font-size: 16px;"> <div class="container"> <p class="text" style="font-size: 2rem;">This text will be 32px</p> </div> </html>
In this case:
- The root <html> element has a font size of 16px.
- The p element uses 2rem, meaning its font size will always be 32px, regardless of the font size of any parent elements.
Unlike em, rem avoids the compounding issue. It stays consistent across the entire page, so it’s widely preferred for global sizing systems like padding, margins, and typography.
Pro Tip: If the root element <html> doesn’t have a pixel size defined, rem will default to whatever the browser (client-side) has as default. And this is usually 16px for most browsers and devices.
4. How do you choose between em and rem?
Choosing between em and rem largely depends on the context of your design and the output you want to achieve.
Use Rem for Consistent, Global Sizing:
Here’s a stylesheet example:
html { font-size: 16px; } h1 { font-size: 2rem; /* Always 32px, regardless of nesting */ } p { margin-bottom: 1rem; /* Always 16px */ }
Here, both the heading and paragraph margins scale based on the root font-size. If the user changes their default font size in the browser, all elements using rem will scale accordingly.
Use Em for Component-Specific Scaling:
Em is useful when you want elements to scale relative to their immediate parent, like modular components or nested elements.
This is great for self-contained components that must be flexible within their context.
.button { font-size: 1.2em; /* Relative to the parent font size */ padding: 0.5em 1em; /* Padding scales with font size */ } .large-button { font-size: 1.5em; /* Larger buttons inherit scalable padding */ }
In this example, the padding for buttons is determined based on the button’s font size. When the large button gets a bigger font size, its padding scales automatically.
Combine Rem for Layout and Em for Components:
For global layouts and typography, use rem to maintain a consistent scale. Use em for elements that need to adapt to parent-specific styles, like buttons, menus, or cards.
html { font-size: 16px; } .container { padding: 2rem; /* Consistent padding regardless of nesting */ } .card-title { font-size: 1.5em; /* Scales based on parent size */ } .card-text { font-size: 1em; /* Matches parent size for consistency */ }
The container uses rem for consistent padding across the site, while the card’s text uses em, allowing the content within the card to scale based on the parent font size.
5. Can I mix rem, em, and px in the same stylesheet?
Yes, you can mix rem, em, and px in the same stylesheet, but it’s important to do so thoughtfully and for specific reasons.
To create an accessible, responsive, scalable and (most importantly) effective stylesheet, you should combine rem, em and px properly. Remember their strengths.
Rem is great for global sizing, em is ideal for component-specific sizing such as padding and margins on specific elements that should respond to the size of text. And px should be used for precision on elements that shouldn’t respond to screen or size changes.
For example, use rem for layout properties, em for component-level adjustments, and px for precise elements like borders and icon sizes.
/* Global settings */ html { font-size: 16px; /* Base font size for rem */ } body { font-family: Arial, sans-serif; margin: 0; padding: 0; } /* REM for Layout and Typography */ .site-header { background-color: #333; color: white; padding: 2rem; /* Spacing based on root font size */ text-align: center; } .logo { font-size: 2rem; /* Header logo scales with root font-size */ margin: 0; } .main-nav ul { list-style-type: none; padding: 0; } .main-nav li { display: inline-block; margin-right: 1rem; } .main-nav a { color: white; text-decoration: none; font-size: 1rem; /* Consistent font-size using rem */ } /* EM for Component-Based Scaling */ .cta-button { font-size: 1.2em; /* Scales based on button's font size */ padding: 0.5em 1em; background-color: #007bff; color: white; border: 2px solid #007bff; /* Border in px */ border-radius: 5px; /* Exact size in px */ } .cta-button:hover { background-color: white; color: #007bff; } /* Mixing REM, EM, and PX in Components */ .hero { text-align: center; padding: 4rem 1rem; /* REM for consistent layout spacing */ } .hero h2 { font-size: 2.5rem; margin-bottom: 1.5rem; } .features ul { list-style-type: none; padding-left: 2rem; } .features li { font-size: 1.2em; /* EM for component-specific scaling */ margin-bottom: 0.5rem; } /* Footer uses rem for typography, px for specific sizing */ .site-footer { background-color: #f4f4f4; padding: 1.5rem 0; text-align: center; border-top: 1px solid #ddd; /* Pixel-perfect border */ } .site-footer p { font-size: 1rem; /* Scaled with rem */ margin: 0; }
Here’s the HTML page:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mixing rem, em, and px</title> <link rel="stylesheet" href="styles.css"> </head> <body> <header class="site-header"> <h1 class="logo">My Website</h1> <nav class="main-nav"> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Services</a></li> <li><a href="#">Contact</a></li> </ul> </nav> </header> <main class="content"> <section class="hero"> <h2>Welcome to My Website</h2> <p>We are happy to provide you with the best services in the industry.</p> <button class="cta-button">Learn More</button> </section> <section class="features"> <h3>Our Features</h3> <ul> <li>High Quality</li> <li>Expert Support</li> <li>Affordable Pricing</li> </ul> </section> </main> <footer class="site-footer"> <p>© 2024 My Website. All Rights Reserved.</p> </footer> </body> </html>
Explanation of Mixing rem, em, and px:
The layout of the site (headers, body, and spacing) is controlled using rem. This ensures consistency across the site. If the root font size (html { font-size: 16px; }) changes, all rem-based values scale proportionally.
The .cta-button uses em for font size and padding. This allows the button to scale based on its context. If the parent element’s font size changes, the button scales with it.
Similarly, the .features section uses em for list items (li), allowing each list item to scale based on the section’s font size.
Specific elements like borders (2px solid #007bff for buttons and 1px solid #ddd for the footer) use px for pixel-perfect sizing.