Mixins are arguably one of the more widely used tools in the Sass language next to the variable. Coming with that, mixins are more apt to be the most abused tool in the language. Mixins are extremely powerful and capable of doing a great number of things, but as we are creating these massive bodies of complex code, it’s easy to find ourselves in a place where we have too many arguments in order to use our mixin. It’s at this point we have started to lose comprehension of what’s happening. The complexity of the tool starts to outweigh its value.
Recently in refactoring a mixin with too many arguments, I began to think of how I could use list-maps to solve this issue.
The classic way
Say you are creating a mixin that is relatively complex in scope and will consume a large number of arguments due to the number of alternative outcomes. We have all done it, I know I sure have. In the following example I am using a button mixin, one of the most frequently written and over-engineered solution after Grids, so the following code shouldn’t seem that crazy to you:
Given the relative simplicity of the mixin, it still takes 7 arguments (yes you can have defaults, but that’s not the point). From here things can only get more complex. The number of times you may need to compare back and forth, between the mixin itself and the use of it, to make sure that you are placing the correct value in the proper argument placement. So, you end up with this:
Great, a list of hex values. In the moment, it makes perfect sense, you know the order of things. But next time you come back to this, will you remember what
#ba0060 is referencing? Was it
Logically, the next step when implementing this would likely be to store the list of values in a variable so you can easily re-use them with other buttons, right? So the process goes as follows … see selector > see mixin > see variable. Search for variable > search for mixin > compare argument list > update and hope you got it right. What usually happens was, “Oh crap, I wanted to update the 4th value, not the 5th!”
Not sure about you, but this has annoyed me for years.
The “options” way
With recently moving a large project to the latest version of Libsass, I have spent a good amount of time refactoring old code. One tool that I am trying to find 1001 uses for is list-maps. If you are not familiar with list-maps, here is an article I wrote over a year ago that can help you get started. Excitingly, it looks like Sass’s list-maps support is going to get even more robust in the future, as the features that are found in sass-maps-plus are on the roadmap to becoming an integrated feature of the official Sass library.
List-maps bring to the table a great way to really manage a variable as a series of key-value pairs. Just like a real programming language!
Looking back at the mixin above, wouldn’t it be great if we could only have only one argument, a list of
options perhaps, and then pass in a list-map of variables within? Good news, we can!
As illustrated in the following example, I have removed the dependency on an ordered list of arguments within the mixin. This
options method allows me to use list-maps to have a complex array of named arguments in the form of key/value pairs and not have to deal with the complexities and ambiguity of an ordered list of arguments:
I’ve seen this before …
. syntax, you can basically make a single argument into an object and parse out the individual values for later use.
option in a mixin versus passing in a list of individually named arguments. Interestingly enough, and this was pointed out to me by a colleague, this very same model is heavily used in much of Backbone. The concept of
Houston, we have a problem
With the new
In the following example I am creating a standard list-map variable and am using key/value pairs to address variable values.
I already love how this looks. Now instead of a list like we had before,
#ffffff, #ededed, #b2005c ..., or a series of overly complicated variables with a naming convention, we have something that makes sense. It reads much like an object in any other language. We understand the role of each value in that list and that can mean a whole lot when you are managing thousands of lines of code.
Update the signal, improve the receiver
Now that we have a list-map with key/value pairs, we need to update all the variables within the mixin so that we can get them out of the list-map. In the following example you will see that I replaced the more traditional ordered argument/variable pairs with the
map-get function and the named variables. IMHO, this is WAY more human readable. It’s clear that we are targeting a single variable which is inherited from the
$options argument. Then from that
map-get function we are asking for simple values,
border-color. The mixin itself should remain pretty stable post this set up configuration.
There is something that I really just love about looking at this code. It’s expressive, it’s clear, it’s direct to the point. What I love even more is how it’s actually used. In the following example you will see a mixin with a single argument, or
option, that is able to address multiple concerns:
One variable to rule them all!
Once all the values are in an easy-to-read list-map variable, we are not beholden to one use case. The variable of
$core-buttons can be global so these values are not trapped inside the scope of the mixin as they were before. Say I had a simpler case, like making a quick button? In the following example you will see that I can reference that same list-map and just pull out a few key values that I want to make use of without any extraneous naming conventions like
core-button--button-color, or use the mixin and find ways to ignore rules I don’t want, or worse yet … just write in regular CSS!
Same variable. No copy/paste. No long naming conventions to find the original values from variables. All the values I ever need all scoped correctly within the same concept, or dare I say … object.
Coming to this conclusion and having worked on many Sass projects in my career, I can only say, “If you are not using list-maps, what the hell are you waiting for?”
The more I use list-maps, the more I find myself greatly reducing the complexity of my code. I too was victim of variable naming conventions. For me, finding new and creative ways of using list-maps, like reducing the number of arguments within a super-mixin, really just helps to dial in the sanity of my code.Tweet this article