One the biggest benefits of Sass its ability to create reusable blocks of code. I often use
@mixins to create reusable code modules. (Here’s a great article on the difference between placeholders and mixins. My short version: use mixins when you need to pass variables and placeholders when you don’t.)
I’m working on a site now that uses the same grid pattern in multiple pages: products, services, and industries all have the same archive layout. I don’t need any variable-controlled style, so my first thought was to use a placeholder. With Sass 3.3, you can create OOCSS/BEM selectors by referencing parent selectors with
&. In previous versions, you could create nested selectors, now you can create new selectors:
I wondered if I could do use a
%placeholder at the top of a
&-nested set of styles, extend that top placeholder in the container selector, and let Sass generate all the new
&-selectors I need. Turns out that doesn’t work with generated selector names. (It would work just fine if my nested selectors were parent/child selectors.) See what I mean:
Now I could use a
@mixin to get what I want here. That would work, but it would duplicate code: each time I run the
@mixin, I’ll get the same style properties repeated in a new place in my stylesheet. I don’t want to repeat myself. I can avoid repeating myself if I comma-chain all my parent selectors and call the
@mixin just once:
That’s almost the DRY-est way I know to do this. If you don’t need to keep your parent selectors in separate partials, you can declare them all together and run the
@mixin on them all at once. However, if you like advanced Sass and don’t mind working extra hard, keep reading for the bonus content!
If you need to keep your parent/container selectors in separate partials, but still want to avoid repeating identical style properties, you could set an empty list variable early in your project, add parent classes to it on each individual partial where appropriate, then call the
@mixin on that list toward the end. This gist shows what I mean:
@if loop (1) makes sure
$parent-classes isn’t empty, (2) converts all its items into a comma-separated string, and (3) calls the
@mixin on the classes that the string contains. Now none of the
@mixin code is repeated, all the parent classes can “live” in their own partials, and all the OOCSS/BEM sub-item classes are generated correctly.
Of course, this isn’t just for grid patterns: it applies to any nested styles you need repeated for elements with different class names. Leave a comment to let me know how else you might use this pattern. Or, if you see a better way to do this, share that too, thanks!
Thanks to Hugo & Stuart – Hugo posted a comment with a cleaner version that handles the parent class list in a stringier way and makes the final
@if loop unnecessary. Stuart recommended including the
comma to keep the list of classes comma-separated in the output.