Ben Frain, a front-end developer, writes about CSS, Sass, responsive design, and web performance.
HN commenters cite his posts on CSS selector performance, icon fonts, and the viewport meta tag as reasonable, practical references.
Memory impact, no. Atomic stylesheets are generally fractions of the size of a traditional monolithic CSS file. I've loaded up a 6MB CSS file for development locally and it's instant.
Performance is more complicated, but generally it's never an issue. We've had huge webpages forever, often with many different CSS files and HTML included from all across an application and organization. When the browser has all of the CSS files finally loaded into memory, it's FAST.
Here's an old article[0] that looked into some performance metrics. 7000 DOM nodes per page, with crazy nested selectors. The delta between the different tests was around 10% (10-100ms depending on the browser) from the simplest to most complicated, but the absolute rendering time has was still under 200ms for all browsers. Important to note that this test was also conducted when IE9 was still relevant. Computers, and even low end devices, are much faster than what was available in that era.
I reran the tests from the article in Chrome just now, and the insanity selector test ran consistently in under 100ms on a 2020 quad core MacBook Pro. Chrome's performance benchmarking tools confirmed that number as well as the simple benchmark included in the test source.
We also have to take into account that the types of classes included with atomic CSS frameworks are extremely simple for browsers to parse and apply. Because they aren't deeply nested spaghetti, the browser can more quickly index them for use later in the…
> bucketing ...
"All of that is very different between the various engines, making the whole process even less predictable."
Source: https://benfrain.com/css-performance-revisited-selectors-bloat-expensive-styles/
In worst case complexity of styles resolution is O(nS*nD) where nS is a number of style rules and nD is a number of DOM elements. That's for current flat style table used by CSS. You can optimize bits and cases but it in general problem is like that.
> @media queries ... at least in Blink they're handled entirely different.
@media and @set are different mechanisms. :root in @set matches element that has this set applied. @set's are scoped set of rules. @media are not.
But I was talking about different thing - parsing, in particular in syntax highlighters and other tools.
----
Consider this DOM:
<body>
<aside styleset="styles.css#aside-set">...</aside>
<main styleset="styles.css#main-set">...</main>
</body>
And CSS:
@set aside-set
{
:root
{...}
... nA more rules
}
@set main-set
{
:root
{...}
... nM more rules
}
<aside> content style resolution will always be constant and independent from <main>, no matter how many nM rules you will have. While currently (with the flat table) adding rules for <main> content will increase complexity of <aside> DOM resolution too.
As a bonus: rules in two sets are completely isolated. Adding rule in main-set will never break existing aside design.
I tried using your app on an iPhone (with Add to Home Screen).
- If I press the settings gear, the text on the settings page is about twice as wide as the screen, requiring horizontal scrolling.
- On the front page, if I open the color picker, it's partially offscreen.
- On all pages, if I do a scroll gesture in the wrong direction, it scrolls the entire UI rather than just the scrollable part. Admittedly, iOS has long made this hard to avoid without hacky JavaScript, but it's been doable, and it's much easier now [1].
- The hamburger button on the left opens a modal view that covers all of the screen but a small margin on the right, making it unreasonably hard to exit.
- If I try to create a tag or folder, the name prompt appears under the other modal view and is improperly sized.
- Oh, and the UI looks thoroughly non-native, e.g. Google-style floating action button, UI not covering the status bar, bottom tab buttons too short, etc. The animations are also haphazard.
My point is not just to nitpick. It's just that while I sympathize with the idea of PWAs in principle, almost every single time I see someone talk about theirs, the PWA in question has immediately obvious glaring UI defects that have nothing to do with browser limitations, and leave it far below the standard of a good native app, or even a bad one. I honestly don't know why this is, but experiencing it over and over makes it hard for me to care about PWAs.
[1]…
Pedantic point. It’s ‘Sass’ and not ‘SASS’.
Sass certainly pushed things forward in CSS world. Without Sass and LESS, Stylus et al. I am quite certain we wouldn’t have CSS custom properties and colour functions. Great additions to the language.
That said, I left Sass specifically some years ago. https://benfrain.com/breaking-up-with-sass-postcss/
Tangentially related — in terms of dealing with CSS tooling/output for large projects with many devs I have found the PostCSS ecosystem indispensable.
I wrote this a few years back after setting things up with PostCSS at bet365.com this way: http://ecss.io/chapter9.html
The good thing about PostCSS is you can reduce the features as CSS becomes more capable and easily incorporate extra tooling like autoprefixer.
Bear in mind that BEM (CSS-wise) is just a nomenclature. What it addresses is exactly excessive nesting and dependence between mark-up and styling.
It roughly means that you imply structure via naming conventions instead of nesting (e.g. if you have a box inside a block, you'd style it via single class such as .my-block__my-box, instead of the traditional nesting approach .my-block .my-box). You can - and should - still use SASS (or other preprocessor) with BEM.
Some interesting resources regarding this:
http://philipwalton.com/articles/css-architecture/
http://philipwalton.com/articles/side-effects-in-css/
http://philipwalton.com/articles/extending-styles/
http://benfrain.com/the-ten-commandments-of-sane-style-sheets/
Couple of other things to try.
Hold off on loading and playing the videos until they are visible:
https://web.dev/lazy-loading-video/#video-gif-replacement
Automatically pause the video when they are scrolled off the screen and no longer visible:
https://benfrain.com/automatically-play-and-pause-video-as-it-enters-and-leaves-the-viewport-screen/