I use REM for pretty much everything but still fall back to px for padding and margins which hasn't been a problem for me so far although I can see why selective use of EM could actually be useful.
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?
"hard-coding --large into the classname just makes it a hack"
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.
Context sensitive components is exactly what I want. At the moment you have to compute that context on the server and output the correct class names (or on the front-end with React etc, doesn't matter). It would be nice for a component to not be told about it's context but it's CSS can infer it either through parent container breakpoints or something else.
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.
The approach that I've used is components style themselves, components that contain other components know how to alter the child components, page layouts/templates can alter components, and each individual page can modify from there. I still consider that modular. The only way a component is impacted is when a parent component explicitly alters it.
In your example the articles would have a standard styling and the main/sidebar would alter the styling as needed.
I utterly loathe using em units. Rem is better, but px are nice and locked down. Em's are neat in theory, but reasoning about them after the CSS has solidified is so tedious.
Em units begin to feel like a weather app telling you today's forecast as a multiplier of yesterday's temperature.
Since obsolete unterbrowser users must suffer, rem FTW.
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.
While I don't have a solution that lets you reassign the CSS root to other elements, I do use a plugin in my own work that lets me use scoped styles, as well as element queries. It solves a lot of problems.
You should check it out, the learning curve is small, and it is even supported well in unterbrowsers: http://elementqueries.com
I would love to check it out, if only your page didn't hang my Firefox. It's really impossible to scroll. Lags are ~10-15s. Hardly even closed the tab. What's going on there? Was it really written with performance in mind? :)
Yeah, I'm not the JS dev, but the issue is known and being looked into.
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
The main issue I have with either of them, is sometimes having to resort to using crazy values like 15.974rem or 2.0736rem (taken directly from the author's website). Using pixels shouldn't be frowned upon, considering all the preprocessors available, and how CSS variables (the next big thing) are around the corner.
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.
After leveling up on typography and what it takes to define a nice typographic grid I found REMs to be a revelation.
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.
Can someone explain to me why I would want to use either over px? I just don't get it.
"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..?
A font size that looks great on desktop is not often optimal on mobile devices.
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.
In my experience most projects that need to worry about things like this are too big for a high level of consistency to work. Either that, or the design is sacrificed to make the code easier. Whenever a designer looks at a page they say "left a bit, down a bit" until they're happy with it, regardless of consistency.
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.
I got kind of excited at the prospects of a study seeing how EM radiation affects our REM sleep patterns, eapecially with the degree the IoT and 5G will envelop us in the very near future. Unfortunately that debate will be another day...
What about good old px? I recently came across this article [0] which argues that after all the "best practices" of rem vs em maybe px is actually the best way to go, in order to accommodate high density displays and zooming.
For me, both units are pretty useless. PX is the way to go except for some cases, e.g. a button's padding that scales with its text or baseline grids. The following article (not mine) explains why pixel win: https://mindtheshift.wordpress.com/2015/04/02/r-i-p-rem-viva...
In Semantic UI we include two distinct header types that sized using either REM or EM. Page headings which are generally consistent across a site and usually specified with H1-H5, are sized using REMs so they display consistently. Sizing variations, (tiny, small, large, huge etc) however use EM to allow them to be sized relative to its content container.
I rarely use rem since I only stopped needing to support IE8 recently. Instead, to deal with the pain of em calculations I use these sass mixins (feel free to use; license CC0 https://wiki.creativecommons.org/wiki/CC0) (below is my first attempt at "sassdoc," which I happened to discover while preparing this comment):
$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 blog has 3 FOUTs - first - the default fonts appear, next - all fonts disappear and after this everything appears as it was at the first time and only after it the correct fonts are loaded.
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.
There's also over half a megabyte that could've been saved if he had scaled and compressed his images losslessly, probably up to 1MB with a bit of lossy compression.
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?