DRY-ing Out Your Sass Mixins

by Sam Richard

26 Reader Comments

Back to the Article
  1. Well done Sam! Great examples to take things to the next level!
    Copy & paste the code below to embed this comment.
  2. Why not just create a placeholder for the “static button” stuff… and extend it within the button mixin.. seems to accomplish the same ending result?
    - crazy Sass - http://codepen.io/adamaoc/pen/rgcCJ/?editors=010
    - eazy stuff - http://codepen.io/adamaoc/pen/glyBj?editors=010
    Copy & paste the code below to embed this comment.
  3. The reason not to create a placeholder first is A) you need to maintain the placeholder separately from the mixin and B) in the simple examples given, while it doesn’t make much of a difference, when creating large systems, extends get populated where the placeholder is extended. As such, if you define the placeholder anywhere but exactly where you want it to appear in the source order, it’s going to be drastically out of place and may cause cascading issues. Creating it dynamically when the mixin is called ensures it lives in the correct place in your cascade.
    Copy & paste the code below to embed this comment.
  4. Awesome stuff Sam. Thank you
    Copy & paste the code below to embed this comment.
  5. With the final version of the mix-in, why wasn’t `$button-selector: map-get($Placeholder-Selectors, ‘button’)` inside the `@extend == true clause`? Wouldn’t that be an unnecessary `map-get` operation?
    Copy & paste the code below to embed this comment.
  6. No matter how much I love over-engineering Sass, I have to say I am with Adam Moore on this one: manually creating the placeholder is enough in most cases. It keeps the code base simpler and won’t do much harm in almost every case. That being said, the final code is pretty clever and I tip my hat for thinking about using `unique-id()` for something actually useful. It’s very smart in this case. In the end, I think it’s sad we have to do things like that (or like the kind of code I featured on SitePoint lately to achieve cross-@media extend directives).
    It clearly shows how screwed Sass is when it comes to this stuff. As you said, both mixins and extends are half-solutions. Meanwhile, this is something that should be in the Sass core, not engineered by some crazy developers (a.k.a: us ;)).
    Copy & paste the code below to embed this comment.
  7. While this solution solves the problem you set out to solve, it feels over engineered. If your CSS was written in a BEM way, your CSS would already be leaner than your final output and you wouldn’t have all that overhead for Sass to compile (or others to come along and understand). Or maybe I’m just missing the point? Ha.
    Copy & paste the code below to embed this comment.
  8. Great insights. This is the reason why I love Sass to begin with. Optimising your CSS output without losing maintainability.
    Copy & paste the code below to embed this comment.
  9. Great work. Love how you have achieved this. I think this nicely bridges the gap between placeholder and mixins in a sensible way. I think even using BEM notation there is a call for using this even if it’s just for a clearfix and a few other minor elements. I found that with your example you could move the css to replace the @include button-static(false); and drop the else and the whole extend bit since the logic for creating the placeholder is independent of that. For me that’s easier to read unless there’s a specific reason for it being where it is? Not sure If I can link to things in my comments but I made a codepen of the stripped down mixins if it helps
    Copy & paste the code below to embed this comment.
  10. I’m with Benjamin Reid. This seems way too complex when you could use the BEM/SMACSS/OOCSS method instead.
    Copy & paste the code below to embed this comment.
  11. Great work Sam! I think examples like this should always be YMMV or your needs may vary. I would have never thought about using a dynamic placeholder to keep the declarations close to when the mixing was first used. Very neat idea and yet another example of the power of Sass and pushing our thinking using it. Lastly, a few thoughts: 1) The !global when resetting the $Placeholder-Selectors map should be moot right? If you just call map-merge it edits the contents of that map right? For example this (https://github.com/Team-Sass/toolkit/blob/2.x.x/stylesheets/toolkit/_placeholders.scss#L9) need not reset the var. 2) You use the word “properties” referring “declarations”. Is this correct? I like using the right words for things and just wanted to make sure.
    Copy & paste the code below to embed this comment.
  12. I’ve just joined the pre-processing world of SASS and have been scratching my head about bloated code. Thanks for the brilliant insights.
    Copy & paste the code below to embed this comment.
  13. Good read!
    This is pretty highly engineered solution. While I kinda like it if feels a little bit over the top for me.
    I would just go for a “mixin” for my dynamic part + a “extend” of my static properties.  I know this sort of goes into components “ambiguously defined” but I think there’s a win in simplicity and readability.
    Copy & paste the code below to embed this comment.
  14. Awesome technique! I feel like you’re taking a lot of heat for it because most people see it as overkill, but I think we all appreciate the elegance in your solution. I’m currently in the static extends camp for the same reasons as everyone else. Following up on your reply to Adam Moore’s question, I don’t see how making button-static into a placeholder class would require you to maintain it separately from the button mixin any more than you would already be maintaining as the mixin it currently is. Having said that, I’m currently charged with refactoring a large scale application’s stylesheets, and I can easily see a situation where the source position will matter. I’m using a combination of Atomic architecture with BEM syntax, so hopefully those situations are few and far between.
    Copy & paste the code below to embed this comment.
  15. Really interesting read. As some before me said, using BEM/SMACSS/OOCSS would make the output code leaner, on the other hand I don’t see why this technique can’t be used to create building blocks for modules. Apart from that, is it just me on Chromium 37 or am I missing some indentation on the code snippets?
    Copy & paste the code below to embed this comment.
  16. One can hardly imagine a better argument for abandoning the entire failed experiment of CSS pre-processors.
    Copy & paste the code below to embed this comment.
  17. Thanks for your article highlighting these new features of Sass which I’ve yet to play with. I’ve learned the hard way that there’s beauty in simplicity and avoiding technical debt when other developers take over the project, so I’m interested to see how this pattern evolves to satisfy our desire for new features while remaining accessible.
    Copy & paste the code below to embed this comment.
  18. Great article on #sassmixins. There are some great possibilities here, but maybe a little over the top for most use cases.
    Copy & paste the code below to embed this comment.
  19. Of course, why didn’t I think of that! Great and thank you. Toko Jual - Service Laptop & Aksesoris Komputer
    http://sodagarkomputer.com
    Copy & paste the code below to embed this comment.
  20. Great article! I’m so going to use this.
    Copy & paste the code below to embed this comment.
  21. This method results in obscure, overly-complicated, hard to maintain SASS code. I prefer to KISS ;)
    Copy & paste the code below to embed this comment.
  22. While this is a very smart approach to DRY-ing a mixin, the cognitive overhead is too much for me.
    Copy & paste the code below to embed this comment.
  23. These ideas are brilliant. I’ve needed $extend in every Component Mixin i’ve ever written. Thanks Sam.
    Copy & paste the code below to embed this comment.
  24. Wow, this is probably the coolest way I’ve seen to DRY out css, SO AWESOME! To the comments about just using better OOCSS and SMACCS, you’re right, to a degree. The problem with OOCSS and SMACCS that this solves is there is it removes ambiguity in what classes you need to style a certain object. This isn’t an issue if there’s only a handful of maintainers and you all are familiar with the css code base, and everyone knows to get your e-mail me button you need the classes .btn .btn-secondary .btn-emailme. Or in smaccs land that your layout to create the secondary element on the left nav is actually #leftNav .l-wide .l-morePadding or whatever it may be. Chaining css classes / id’s is difficult to maintain across larger teams, or teams where the backend / frontend is separated. OOCSS and SMACCS leave the components intentionally de-coupled so they can be skinned. The problem is the ties between all of your classes exist in documentation, in the dev minds, or in naming conventions. These are hard to keep up and maintain, so why not make your code maintain this for you? The approach above is also easy to explain once it’s implemented. You’re writing extensible classes for your css code. Sure someone will likely have to architect the core building blocks, but this is necessary in every other part of webdev. It’s moving towards making css manageable like any other language. Also, DRY CSS like this will eventually make a TDD approach to CSS possible.
    Copy & paste the code below to embed this comment.
  25. Great article Sam! Very inspiring. I currently have ver 3.3 installed but somehow I cannot get maps to work.
    Any hint on this ?
    Copy & paste the code below to embed this comment.
  26. Very cool idea, but I’d have to agree with Hugo Giraudel on this being over-engineered. I especially don’t want to have to write a {mixin-name}-static mixin for every mixin I write. If you really want to write this kind of mixin, why not at least generalize it to a mixin called static(), and then you can use it inside any mixin like this:
    \@mixin button($color) {
              \@include static(‘button’) {
                          border: 1px solid;
                          border-radius: 5px;
                          padding: .25em .5em;                       &:hover {
                                    cursor: pointer;
                          }
              }           background-color: $color;           &:hover {
                          background-color: mix(black, $color, 15%;
              }
    }
    Very simple to use now - all you need to do is stick any static properties inside the content of the static() mixin.
    Here’s an example using my generalized static() mixin: http://codepen.io/joelbyrd/pen/npiyo
    Copy & paste the code below to embed this comment.