REM vs. EM – The Great Debate
zellwk.com
zellwk.com
Tangentially related. It bothers me a lot that we have to add classes like header--large onto a component. The classname header--large should be able to automatically switch depending on it's parent containers size (and not the window size like media queries work). My component may be presented it 3 different styles depending on the size constraints of it's container and hard-coding --large into the classname just makes it a hack. It's not large on mobile so why am I overriding the styles of my desktop header--large classname.
Ideal situation, parent container media queries so that variations can be kept solely in css and you could just drop a component into anywhere. I'm guessing there are some circular dependency issues stopping this from working maybe?
You're gonna infuriate lots of CSS people! That's the basis of modularity: you can just move around a component anywhere on the page, it will keep its styling (thanks to classes like header--large) and not be disturbed by its surroundings.
Personally, I agree with you, and think it's a bad approach. Elements should be able to be styled according to context.
Let's say I have 2 columns: "main" and "sidebar". I have a list of my latest articles in "main". I want to show another list of articles in my "sidebar", but display them smaller, because it's secondary content.
Why should I have to add the ".post--small" class to all my posts? Why can't I use the context of the parent ".sidebar" and use that in my CSS? I could then keep the exact markup for all posts across the website.
"Ideal situation, parent container media queries"
Yes, that's exactly what CSS is missing, but you found the reason why it hasn't been implemented: circular dependency issues.
In your example the articles would have a standard styling and the main/sidebar would alter the styling as needed.
There's too many negotiation between containers because a child component doesn't understand where it is, components are very "dumb" right now. We need smart context sensitive components.
Em units begin to feel like a weather app telling you today's forecast as a multiplier of yesterday's temperature.
Today is going to be 1.1!
[uninstall]
What's REALLY missing in modern CSS3 standard is the ability to reassign CSS root to any other element than <html>, according to font properties of which all nested rems would be calculated. So, for now, we have to stick to assigning base font sizes to <html>, not even to <body>.
My microframework (999.css - http://999.surge.sh) uses pixels to assign base font size to <html>, rem for <body>, ems for headings and rems for all other nested typography.
You should check it out, the learning curve is small, and it is even supported well in unterbrowsers: http://elementqueries.com
Strangely it didn't affect previous versions of Firefox and whatever is broken at the moment is already fixed in upcoming beta versions of Firefox. I'm not sure what or why, but it might become fixed from mozillas end before a workaround gets diagnosed.
How does it work in IE8 and previous Firefox, but have issues with the current build, but not with upcoming builds? It baffles me
But I would always use EMs for any WYSIWYG generated value, where the design solely relies on HTML tags, not CSS classes. It's then easy to alter the container's font-size while maintaining consistency and balance between all its children.
For borders, in any case, it's better to stick with pixels. Some people started writing things like "border: 0.065rem solid #ccc", which would make the border disappear if you either zoomed out, or set the font-size to something smaller than 16px.
A key concept of good typographic grid design is that the body copy line height (or font size as a proxy) is a very important measurement to be reused across your grid.
TLDR; By using your body font size as a basic unit of measure for other visible distances eg padding, margins it's possibly to make your design look better and feel more unified.
My crude rule of thumb for beginners is to use REM for everything by default and then change over to EM anywhere this is not working for you (and this is a crude summary of key advice in this article)
One style guide I read suggested that pixels were ok for anything up to 5px and that REM/EM should always be used otherwise (towards ensuring a nice typographic grid) and I think that's a good practical approach.
If you're essentially thinking in REMs and just translating that to px in certain circumstances to get around crazy numbers, great,if that works for you. But I think that generally REMs provide free design benefits for those that switch to them rather than adding arbitrary non-proportional pixels lengths everywhere within a design.
"One of the best practices to typography on the web is to use relative units like rem and em.", it says, but why?? I get as a general philosophy that relative might be preferable over absolute, the way you prefer relative paths in your build system. But "relative" in this case means relative to the font size which is either specified or the default, both which makes s using absolute values just as valid and easier to comprehend..?
You can change your base font size with a media query and have the rest of the website adapt accordingly because they're all sized relative to the base font size.
Advantage of "em" and "%" (relative) without the cascading (thus absolute).
So, yeah, use rems or ems if it makes your life easier. Use a CSS preprocessor with lots of helpful variable names and functions. And just don't worry about it.
[0] https://mindtheshift.wordpress.com/2015/04/02/r-i-p-rem-viva...
html {
font-size: 62.5%;
}
You can convert from pixels to rems (or ems) quite easily: p {
font-size: 1.4rem; // 14px
}
I use rems for stuff that needs to scale with text, ems for line-height and pixels for everything else. $current-font-size: 16;
// Remove the units from a value (pretty sure someone else wrote this originally)
@function strip-units($number) {
@if unit($number) == '' {
@return $number;
}
@return $number / ($number * 0 + 1);
}
/// Sets font-size and line-height using percentage and unitless values respectively, with support for nesting.
/// @param {Number} $new-font-size - Desired new font size in pixels (units ignored)
/// @param {Number} $new-line-height - New line height in pixels (units ignored)
/// @param {Number} $context-font-size - Current font size where you're including this mixin, if it isn't the global $current-font-size
@mixin font-scale($new-font-size, $new-line-height:null, $context-font-size:$current-font-size) {
// Set the font size
$context-font-size: strip-units($context-font-size);
$new-font-size: strip-units($new-font-size);
$font-ratio: $new-font-size / $context-font-size;
font-size:$font-ratio * 100%;
// Set the line height
@if $new-line-height != null {
$new-line-height: strip-units($new-line-height);
// Honestly don't remember why the "+ 0.0001" here:
$line-ratio: $new-line-height / $new-font-size + 0.0001;
line-height:$line-ratio;
}
// Include nested content with global $current-font-size set to the new value
$last-cfs: $current-font-size;
$current-font-size: $new-font-size !global;
@content;
// Reset the global $current-font-size to what it was before
$current-font-size: $last-cfs !global;
}
/// Convert a pixel length to ems at the current (or given) font size
/// @param {Number} $px-length - Length in pixels (units ignored)
/// @param {Number} $font-size - Current font size in px, if it isn't the global $current-font-size (units ignored)
@function ems($px-length, $font-size:$current-font-size) {
$px-length: strip-units($px-length);
$font-size: strip-units($font-size);
@return ($px-length / $font-size)*1em;
}
(Those are modified slightly and haven't been tested in this exact form.) This lets me do, for example: .title {
// Make the text in .title 112.5% (18 ÷ 16) with a line-height of 1.22 (22 ÷ 18)
@include font-scale(18, 22) {
// Give it 15 pixels of padding using em units
padding:ems(15);
// Make the text of a .subtitle inside a .title 14px (112.5% × (14 ÷ 18) = 87.5%)
// (line-height remains 1.22 in this case, working out to 17.11px)
.subtitle {
@include font-scale(14);
// Give .subtitle 5 pixels of padding, but instead of nesting
// the mixin again, I'll just tell ems() that the current
// font size is 14 directly.
padding:ems(5, 14);
}
}
}
The nesting isn't attractive and `ems(15)` is a little more typing than `15em` (though not more than `(15/18)×1em`), but I think just using em for everything reduces some cognitive load.It also lets you do some tricks, like you can set the root element of some component to `font-size:(16/1024)*100vw` and it'll have a "normal" size when the viewport is 1024px wide but scale up smoothly in every dimension when the viewport is larger (and down when smaller). And you can still scale the whole page, including that component, by changing the font-size of html/body.
Thus far I only use rem when I need to override something for an inner element, like if a piece of the aforementioned vw-sized component gets too small when the viewport is less than 640, I would set the font-size for just that piece in a media query using rem, allowing the rest of the component to continue to scale down.
This is why
font-display: < auto | block | swap | fallback | optional >
is going to be useful.More info: https://tabatkins.github.io/specs/css-font-display/
----------
Alternatively, something I've been trying is loading fonts in an embedded stylesheet (<style></style>) in the <body> element, loading critical CSS in the <head>.
This results in content being displayed in a base/system font initially, and then when the web font is loaded in the body, it replaces the base font, but without blocking render and at the same time resulting in only one brief FOUT.