Home > Others > Generic First CSS: New Thinking On Mobile First

Generic First CSS: New Thinking On Mobile First

December 21st, 2018 Leave a comment Go to comments

Generic First CSS: New Thinking On Mobile First

Generic First CSS: New Thinking On Mobile First

Alastair Hodgson

2018-12-21T14:45:16+01:002018-12-21T14:49:27+00:00

I think it’s safe to say that Ethan Marcotte’s Responsive Web Design was a welcome revelation for web developers the world over. It triggered a whole new wave of design thinking and wonderful new front-end techniques. The reign of the oft-despised m dot websites was also over. In the same era and almost as influential was Luke Wroblewski’s Mobile First methodology — a solid improvement that built upon Marcotte’s impressive foundations.

These techniques are at the bedrock of most web developers lives, and they’ve served us well, but alas, times change, and developers constantly iterate. As we increase the efficiency of our methods and the project requirements become more complex, new frustrations emerge.

The Journey To Generic First

I can’t pinpoint exactly what made me change the way I write my CSS because it was really a natural progression for me that happened almost subconsciously. Looking back, I think it was more of a by-product of the development environment I was working in. The team I worked with had a nice SCSS workflow going on with a nifty little mixin for easily adding breakpoints within our CSS declarations. You probably use a similar technique.

This wonderful little SCSS mixin suddenly made it easy to write super granular media queries. Take a hypothetical biography block that looks a little something like this:

.bio {
  display: block;
  width: 100%;
  background-color: #ece9e9;
  padding: 20px;
  margin: 20px 0;

  @include media('>=small') {
    max-width: 400px;
    background-color: white;
    margin: 20px auto;
  }

  @include media('>=medium') {
    max-width: 600px;
    padding: 30px;
    margin: 30px auto;
  }

  @include media('>=large') {
    max-width: 800px;
    padding: 40px;
    margin: 40px auto;
  }

  @include media('>=huge') {
    max-width: 1000px;
    padding: 50px;
    margin: 50px auto;
  }
}

Fig.1. Typical mobile first with cascading media queries

This works nicely — I’ve written a lot of CSS like this in the past. However, one day it dawned upon me that overwriting CSS declarations as the device width increased just didn’t make sense. Why declare a CSS property for it only to be overwritten in the following declaration?

This is what lead me to begin writing compartmentalized media queries as opposed to the more common approach of media queries that cascade upwards (or downwards) like the example in Fig.1.

Instead of writing media queries that cascade upwards with increases in screen size, I began creating targeted media queries that would encapsulate styles at desired screen widths. The media query mixin would really come into its own here. Now my SCSS media queries are starting to look like this:

.bio {
  display: block;
  width: 100%;
  padding: 20px;
  margin: 20px 0;

  @include media('>=small', 'medium') {
    max-width: 400px;
    margin: 20px auto;
  }

  @include media('>=medium', 'large') {
    max-width: 600px;
    padding: 30px;
    margin: 30px auto;
  }

  @include media('>=large', 'huge') {
    max-width: 800px;
    padding: 40px;
    margin: 40px auto;
  }

  @include media('>=huge') {
    max-width: 1000px;
    padding: 50px;
    margin: 50px auto;
  }
}

Fig.2. An example of compartmentalized media queries

This new approach just felt more intuitive to me, it cut down on having to reset styles from the previous breakpoint, and it was making the CSS easier to read. More importantly, it was making the media queries self-documenting in a more significant way.

I still wasn’t 100% happy with the above though, It seemed like there was still a major issue to overcome.

The Problem With Mobile First

The issue with mobile first is that by definition you will most likely have to override mobile-first styles in subsequent media-queries. This feels like a bit of an anti-pattern.

So — to me — the answer was obvious: let’s take the idea of media query compartmentalization to its logical conclusion — we will also compartmentalize the mobile specific styles into their very own media queries. I know, I know, this goes against the common convention we’ve learned over the years. “Mobile First” is so ubiquitous that it’s usually one of the “skills” questions a hiring manager will ask. So surely any alternative must be wrong, shouldn’t it? This is usually the part where people shake their heads at me whilst uttering mobile first over and over.

Okay, so we’re going to break through the mobile first dogma and compartmentalize all our styles into the relevant media queries. What we’re now left with is pure generic styles declared on a CSS selector, with all other device specific styles encapsulated in media queries that only apply to the relevant screen dimensions. We now have Generic First CSS:

.bio {
  display: block;
  width: 100%;

  @include media('>=0', 'small') {
    padding: 20px;
    margin: 20px 0;
  }

  @include media('>=small', 'medium') {
    max-width: 400px;
    margin: 20px auto;
  }

  @include media('>=medium', 'large') {
    max-width: 600px;
    padding: 30px;
    margin: 30px auto;
  }

  @include media('>=large', 'huge') {
    max-width: 800px;
    padding: 40px;
    margin: 40px auto;
  }

  @include media('>=huge') {
    max-width: 1000px;
    padding: 50px;
    margin: 50px auto;
  }
}

Fig.3. An example of Generic First CSS

Yes, there are slightly more media queries, however, I see this as a benefit, any developer can now looks at this CSS and see exactly what styles are applied at each and every screen size without the cognitive overhead of having to pick apart media-query specificity.

This can be great for people unfamiliar with the code base or even the future you!

When Not To Compartmentalize

There are still times when media query compartmentalization is a burden, and in some cases a good old >= media query is fine. Remember, all we’re trying to do is avoid property overwrites.

Dev Tool Bliss

One major unintended consequence of writing compartmentalized Generic First CSS is the experience you will get from your developer tools style panel. Without the media query cascade, you will now have a clearer overview of which styles are applied — You won’t have a style panel full of struck-out declarations from overwritten media query rules — The noise is gone! This — for me — is one of the biggest benefits of the Generic First CSS technique. It brings a little extra sanity to the CSS debugging experience, and this is worth its weight in gold. Thank me later.


Before and after screenshot of how the generic first CSS approach affects chrome dev tools style panel.
Fig.4. How generic first, compartmentalized css can help bring joy and sanity to your dev console. (Large preview)

Performance Implications

So all these Generic First CSS benefits are starting to sound pretty good, but I think there is one last key question that I think needs to be addressed. It’s on the subject of performance optimization. Now I don’t know for certain yet, but I have an inkling that fully compartmentalized media queries may have a slight performance benefit.

Browsers perform a rendering task called computed style calculation. It’s the browsers way of calculating which styles need to be applied to an element at any given moment. This task is always performed on initial page load, but it can also be performed if page content changes or if other browser actions take place. Any boost you can give to the speed of the process is going to be great for initial page load, and it could have a compound effect on the lifecycle of your websites pages.

So going back to generic first CSS: Are there any performance issues related to the browser having to work out the CSS specificity of a multitude of cascading media queries?

To answer that, I’ve devised a test case that can be used to measure any speed benefits or indeed drawbacks.

The Test Case

The test case is comprised of a basic HTML page that outputs a “bio” block 5000 times, the markup is the same for each block, but the classes are slightly different (numeric differentiator), the CSS for this block is also outputted 5000 times, with class names being the only thing to differ. The outputted CSS is piped through a tool called CSS MQPacker, this helps dramatically reduce file size of CSS that uses a lot of inline media queries by combining all the separate instances of a specific media query into one — It’s a great tool that will probably benefit most modern CSS codebases — I’ve used it as a standalone cli tool via a npm task in the test projects package.json, you can also use it as a postcss plugin, which is nice and convenient!

The first test case is a mobile-first cascading media queries example, the second test case is a generic first compartmentalized variant of the CSS. The CSS for these cases is a little verbose and could probably be written in much more concise terms, but it really just serves as a rough example to test the argument.

The test was run 20 times for each CSS variation in desktop Google Chrome v70, not a massive set of data, but enough to give me a rough idea of a performance gain/loss.

The test metrics I have chosen to use are:

  • Overall page load time
    A basic metric to check page load time using the Performance API markers in the the start of the and very end of
  • The Recalculate Style
    Time from within the dev tools performance pane.
  • The Overall Page Rendering
    Time from within the dev tools performance pane.

Table of results from the Google Chrome performance profiler
Fig.5. The key metric being measured is “Recalculate Style”. (Large preview)

Results Table (all times in milliseconds)

Mobile First Generic First
Load time Calculate styles Total render time Load time Calculate styles Total render time
1135 565.7 1953 1196 536.9 2012
1176 563.5 1936 1116 506.9 1929
1118 563.1 1863 1148 514.4 1853
1174 568.3 1929 1124 507.1 1868
1204 577.2 1924 1115 518.4 1854
1155 554.7 1991 1177 540.8 1905
1112 554.5 1912 1111 504.3 1886
1110 557.9 1854 1104 505.3 1954
1106 544.5 1895 1148 525.4 1881
1162 559.8 1920 1095 508.9 1941
1146 545.9 1897 1115 504.4 1968
1168 566.3 1882 1112 519.8 1861
1105 542.7 1978 1121 515.7 1905
1123 566.6 1970 1090 510.7 1820
1106 514.5 1956 1127 515.2 1986
1135 575.7 1869 1130 504.2 1882
1164 545.6 2450 1169 525.6 1934
1144 565 1894 1092 516 1822
1115 554.5 1955 1091 508.9 1986
1133 554.8 2572 1001 504.5 1812
AVG 1139.55 557.04 1980 1119.1 514.67 1903.15

Mobile First
Load time Calculate styles Total render time
1135 565.7 1953
1118 563.1 1863
1174 568.3 1929
1112 554.5 1912
1105 542.7 1978
1106 514.5 1956
1164 545.6 2450
1115 554.5 1955
Generic First
Load time Calculate styles Total render time
1196 536.9 2012
1148 514.4 1853
1124 507.1 1868
1111 504.3 1886
1121 515.7 1905
1127 515.2 1986
1169 525.6 1934
1091 508.9 1986

Fig.6. 20 test runs measuring key load/render metrics of mobile first vs generic first CSS.

From my admittedly small dataset, it does seem like my initial suspicion may be correct. On average, I see the Style Recalculation task take 42ms less time which is a 7.6% speed increase, and therefore the overall rendering time also decreases. The difference isn’t mind-blowing, but it is an improvement. I don’t think the dataset is big enough to be 100% conclusive and the test case is a little unrealistic, but I’m very glad not to be seeing a performance degradation.

I would be very interested to see the generic first methodology applied to a real-world existing codebase that has been written in the mobile-first way — the before after metrics would be much more realistic to everyday practice.

And if anyone has suggestions on how to automate this test over a broader set of iterations, please let me know in the comments! I’d imagine there must be a tool that can do this.

Conclusion

To recap on the benefits of this new development methodology…

  • CSS that does exactly as intended, no second guessing;
  • Self-documenting media-queries;
  • A better dev tools experience;
  • Pages that render faster.

I’d like to think I’m not the only person espousing the writing of CSS in this style. If you have already adopted the generic first mindset, hurray! But if not, I think you’ll really like the benefits it brings. I’ve personally benefited greatly from the uncluttered dev tools experience, which in itself will be a huge positive to a lot of devs. the self-documenting nature of this way of writing your media-queries will also have benefits to yourself and the wider team (if you have one). And finally, these benefits won’t cost you anything in performance terms, and in fact have been shown to have marginal speed gains!

Final Word

Like all development methodologies, it may not be for everyone, but I’ve fallen into Generic First CSS quite naturally, I now see it as a valuable way of working that gives me all the benefits of mobile first with some positive new additions that make the tough job of front-end development that little be easier.

Resources

Test Case Repo

If you’d like to fire up the test case and give it a go yourself, you can find it on GitHub, I’d love to see some reports from others.

Tools
Smashing Editorial(dm, ra, yk, il)
Categories: Others Tags:
  1. No comments yet.
  1. No trackbacks yet.
You must be logged in to post a comment.