The debate between using mixins or extends in Sass has been heating up recently. From the surface it appears they both provide solid benefits in helping us write consistent and modular code. However, the critics are out and extends specifically have come under fire. But why?

(If you’re unsure what mixins and extends are, or the Sass preprocessor, I’d recommend researching them before before continuing here.)

The Argument

There are a handful of arguments against extends, the most popular include:

Extends don’t allow arguments

Extends don’t work within media queries

Extends, when nested, can extend unintended code

Extends group the compiled CSS based on reused declarations, not on how the code is contextually written

Fair enough, those are good arguments, and mixins will solve for every one of them. That said, extends won’t duplicate our declarations where mixins will. And with mixins, that can be an enormous amount of duplication. Extends, on the other hand, will duplicate our selectors, combine them with other selectors, and rearrange them so they appear with the necessary declarations.

So this begs the question: if mixins and extends both have some amount of duplication, which is best?

In digging around I’ve only found one example of quantifiable research on the performance of mixins versus extends. The use case was somewhat arbitrary, with mock code, and only tested file size. This test created more questions than it answered.

For me, the choice between mixins and extends breaks down into three requirements:

Which method has the smallest file size? Which method has the fastest load time? Which method is the simplest to use?

Fortunately there are tools to help pull data for these requirements, and that’s exactly what I did.

The Test

I tested three live, production code bases as I wanted to see the real effects of mixins versus extends. The first code base was one of Belly’s largest web applications, our merchant portal. It’s an application that has been developed by 12 different contributors over the past 2 years and has roughly 32,700 lines of contributor written code. The second code base was our style guide, a smaller application (5 contributors and ~1,700 lines of code) that documents all of our design patterns and front-end framework Rolodex. The last code base was our front-end framework itself (5 contributors and ~4,400 lines of code), which contains all common source files and assets we use across a plethora of applications.

In implementing extends I went as far to find any declaration repeated ~10 times and created an extend for it. If I found shorthand property and value pairs that could be rewritten longhand with the use of extends, I did so. In all, it wasn’t uncommon to find extends for declarations such as display: block or float: left , all of which made up 285 different extends.

In implementing mixins I took the opposite approach. I only created a mixin if it would be able to share more than one declaration within a selector, and I used arguments accordingly in doing so. If a mixin couldn’t share more than one declaration I didn’t create one, and instead relied on variables for consistency.

In all, I had three code bases going head to head with mixins versus extends. The results are impressive.

The Results

File Size — Quantified Using StyleStats

Merchant Portal Extends Mixins Difference w/ Mixins File Size (kb) 115.6 131.5 13.75% File Size Compressed (kb) 102.3 109.4 6.94% File Size Gzipped (kb) 17.5 17.1 -2.29%

Style Guide Extends Mixins Difference w/ Mixins File Size (kb) 42.9 46.8 9.09% File Size Compressed (kb) 36.8 38.9 5.71% File Size Gzipped (kb) 7.1 7 -1.41%

Front-end Framework (Rolodex) Extends Mixins Difference w/ Mixins File Size (kb) 39.8 42.1 5.78% File Size Compressed (kb) 34.1 35 2.64% File Size Gzipped (kb) 6.5 6.2 -4.62%

File size for both raw and minified CSS was smaller using extends over mixins until the CSS was gzip, and then mixins were smaller. I’m really impressed and amazed by this. At a high level, gzip works by gathering repeated strings and compressing them. The more often a string is repeated, the better the compression. Turns out, repeating declarations is easier to compress than repeating selectors. And trust me, I repeated a ton of declarations (see below).

Verdict: Mixins win with the support of gzip.

Merchant Portal Extends Mixins Difference w/ Mixins color properties 26 169 550.00% font-size properties 34 199 485.29% float properties 3 42 1,300.00% display properties 6 87 1,350.00% margin properties 56 100 78.57% padding properties 60 152 153.33% height properties 112 117 4.46% width properties 164 232 41.46%

Style Guide Extends Mixins Difference w/ Mixins color properties 23 72 213.04% font-size properties 22 69 213.64% float properties 3 7 133.33% display properties 6 34 466.67% margin properties 2 16 700.00% padding properties 34 65 91.18% height properties 23 27 17.39% width properties 73 106 45.21%

Front-end Framework (Rolodex) Extends Mixins Difference w/ Mixins color properties 23 67 191.30% font-size properties 22 69 213.64% float properties 3 6 100.00% display properties 6 32 433.33% margin properties 2 16 700.00% padding properties 32 55 71.88% height properties 23 27 17.39% width properties 73 106 45.21%

At times I repeated properties over 1,300% more times with the use of mixins as compared to extends. Despite the massive amount of duplication, the file sizes using mixins were always smaller thanks to gzip compression.

Load Time — Quantified Using WebPagetest

Merchant Portal Extends Mixins Difference w/ Mixins 1st Run Load Time (s) 3.601 3.343 -7.16% Repeat Run Load Time (s) 2.821 2.532 -10.24% 1st Run Speed Index 3,652 3,444 -5.70% Repeat Run Speed Index 2,858 2,650 -7.28% Visually Complete (s) 5.800 5.400 -6.90%

Style Guide Extends Mixins Difference w/ Mixins 1st Run Load Time (s) 2.083 1.502 -27.89% Repeat Run Load Time (s) 0.756 0.734 -2.91% 1st Run Speed Index 1677 1,406 -16.16% Repeat Run Speed Index 600 512 -14.67% Visually Complete (s) 2.100 1.500 -28.57%

Mixins, by a fraction of a margin, resulted in a faster load time as compared to extends. I will say though, the difference here is minimal and enough to be considered a non-factor. Going into this test I thought this could likely be the case, and Paul Irish from the Google Chrome team seconded my thoughts.

Load time, and speed in general, was easily the hardest metric to quantify as there are a ton of factors that go into it other than CSS. If you’re looking to make some serious performance improvements (and looking at these numbers I need to) you’ll see much larger gains outside of CSS. That said, I still wanted to know if mixins or extends fared better. (Also note, I didn’t test Rolodex, our front-end framework, as there isn’t an interface for it. It’s purely CSS.)

Verdict: Mixins win by milliseconds.

Simplicity — Quantified as Rules Divided by Selectors

Merchant Portal Extends Mixins Difference w/ Mixins Rules 694 996 43.52% Selectors 2,764 1,271 -54.02% Simplicity 25.11% 78.36% 212.10%

Style Guide Extends Mixins Difference w/ Mixins Rules 390 432 10.77% Selectors 1,124 595 -47.06% Simplicity 34.70% 72.61% 109.25%

Front-end Framework (Rolodex) Extends Mixins Difference w/ Mixins Rules 361 365 1.11% Selectors 1,024 524 -48.83% Simplicity 35.25% 69.66% 97.59%

Simplicity, calculated as rules divided by selectors (hat tip to StyleStats), showed exactly how beneficial mixins are over extends, especially with larger code bases. Having worked intently with extends this wasn’t a huge surprise. (Take a look at the developer tools screenshot below for an idea of how difficult extends can be to work with.) Extends can break the cascade, cause you to increase specificity as a result, and spread your styles out all over the place making the compiled code nearly illegible.

Verdict: Mixins win big time!

The Winner

By now you likely know, mixins are the clear winner.

I have to say though, I’m surprised. I was an advocate of extends for the longest time, and went into this test thinking it would be a close race but felt extends would win purely on file size. Upon jumping into the test and watching gzip go to work I’ve been proven wrong.

From here on out I’ll be using mixins and would recommend you favor them over extends too. What do you think? Let me know!