Sass (Part 2): Tips and Tricks

My previous post on Sass (part 1) looked at the Architecture we use to organize our style sheets. It wasn’t intended to be a “part 1” but in preparing it I kept taking note of extra tricks and techniques that didn’t quite fit into the “architecture” of the code, and from this, “Part 2” was born! The ideas here have come from my past experience, random articles, and (mostly) as a result of being a part of the Delphic Front End Development team. It’s amazing the little things that come from a great group!

Organizing colors can get a bit messy, so in _settings.scss we have a pattern to help in which they are abstracted from the components. First, every color we use in the site is assigned a name variable, (eg, $colorPlum: #832C73;). Second, those named color variables are applied to the name of an object (eg, $primaryButtonBkg:$colorPlum;).

As a result, if one of the color values is off, there’s only one place it needs to be changed. Or, if an object in the site needs a different color, there’s only one place you need to look to modify it.

Avoiding @extend will save a few headaches. In short: it doesn’t work in @media, it’s not always clear what it’s doing, and it can cause some unexpected results depending on use. In fact, after reading up on this subject, I think I’m going to avoid it altogether, at least until I find a good reason to use them over mixins. But, if you really want to extend something, extend this: %class, not this: .class, do it locally (the extender is next to the extended), and try your best not to start nesting them.

Naming breakpoints is a really good idea! Although it’s been around a couple of years, I still thought it worth adding in here. Essentially, it’s easier to remember “big,” “medium,” and “small,” rather than device widths. (Considering there are so many different devices out there now styling for “mobile” or “tablet” has become a bit obsolete.)

Mapping breakpoints takes that idea one step further and even allows us, with a little modification, to split out styles from components into browser-specific (cough IE8 cough) style sheets. The example below comes straight out the Delphic boilerplate (with the extra 540px breakpoint) and includes the methodology of breaking out styles for various environments.

In the _settings.scss:

$breakpoints: (
    tiny: 320px,
    small: 540px,
    medium: 768px,
    wide: 980px,
    superwide: 1200px
);

See how much more friendly those names look? In addition to that – this acts as a single source of truth, one place to check for all our breakpoint values rather than having them scattered throughout.

In the _mixins.scss:

@mixin breakpoint($point) {
     @if $oldIE {
        @content;
    }@else{
        @each $breakpoint in $breakpoints {
            @if $point == nth($breakpoint, 1) {
                @media (min-width: nth($breakpoint, 2)) {
                    @content;
                }
            }
        }
    }
}

So our old friends IE8 and below were never introduced to media queries. The above spits out a media query-free sheet for them to use while everyone else gets the good stuff. To set up the extra sheet, add it in beside main.scss(eg, oldie.scss) and add this:

$oldIE: true;
@import "main.scss";

Now, you can set a conditional anywhere in your Sass files and it will pop out in that extra sheet:

@if $oldIE {
    /* Old IE stuff here! */
}

The beauty here is that the oldie styles for a component can live within that component’s file rather than in another directory. Things just keep getting better and better!

The component file structure is also benefited by this breakpoints idea.
As the saying goes Mobile first (or more recently, Offline first, but that’s for another day). For every component you have, build the styles for mobile. Then, add any additions for larger screen sizes within the relevant breakpoints. It may be simple, but keeping this organizational structure for each component file makes figuring out how everything works later on a dream.

.component { ... }
@include breakpoint(tiny) { ... }
@include breakpoint(small) { ... }
@include breakpoint(medium) { ... }
@include breakpoint(wide) { ... }
@include breakpoint(super-wide) { ... }

Mixing in your Icons as opposed to including them as extra classes on your HTML elements is a brilliant idea! The article I’ve linked to gives the option of specifying :before or :after. The version we have in our boilerplate only allows for the :before option, but it’s a little cleaner.

Below is our current (as of writing this) boilerplate solution:

In _settings.scss

$icons: (
    thumbsup: 'e800',
    thumbsdown: 'e801',
    thumbsmeh: 'e802',
);

In _helpers.scss

@each $iconName, $value in $icons {
 %icon-#{$iconName}:before {
 @extend %icon; /* all the base styling for :before icons */
 content: '#{$value}';
 }
}

%pull-icon-right:before{
 float: right;
 margin: 0;
}

With that setup we can call `@extend %icon-arrow-left;” to add it to any element! I know @extend is something I mentioned to avoid, but you know how it goes with exceptions and rules. Also, Fontello is a great resource for building our icon fonts.

Grid systems might be something I’ll be trying to move away from. I’ve recently come across the very promising-looking concept of grid frameworks, specifically Susy. Admittedly, this is just one of many, so my choice there might be somewhat arbitrary.

Responsive JavaScript isn’t exactly a Sass thing, but it relies on CSS to implement so I thought I’d just include it here anyway! Essentially, we set font-family: 'small'; / font-family: 'medium'; etc on the html element from within a media query, then reset our real default fonts on the body. This lets us check the context with JavaScript and make it responsive—no desktop-specific JS on mobile and vice versa!

Sass animations I do not get to work with enough. (It may just be my nature but I think working out all the fiddly bits of the timings and transitions is fun!) But, alongside all the fun stuff, there is quite a lot of overhead in terms of writing to get these things up and running. Fortunately, you guessed it, Sass is great at working its magic here, too.

In _mixins.scss we can set up some code to deal with all the vendor prefixes. Add this into your project, and then forget about them! (Unless you’re already using a vendor prefixing post-pre-processor, but as mentioned before, another time…).

@mixin animationName($aName){
 -webkit-animation-name: $aName;
 -moz-animation-name: $aName;
 -o-animation-name: $aName;
 animation-name: $aName;
}

@mixin animationDuration($aDur){
 -webkit-animation-duration: $aDur;
 -moz-animation-duration: $aDur;
 -o-animation-duration: $aDur;
 animation-duration: $aDur;
}

@mixin keyframes($keyName) {
 @-webkit-keyframes #{$keyName} {
 @content;
 }
 @-moz-keyframes #{$keyName} {
 @content;
 }
 @-ms-keyframes #{$keyName} {
 @content;
 }
 @keyframes #{$keyName} {
 @content;
 }
}

Now we can build our animation. My suggestion would be to create a new file for every animation (or pair—in and out) within utilities/animations/ _animationName.scss The example below may seem short, but these things can get pretty long when you start including multiple properties over a number of keyframes.

@mixin animationNameIn(){

    @include animationName( animationNameIn);
    @include animationDuration( .2s );
    @include keyframes( animationNameIn ) {
        0% {
            opacity:0;
        }
        100% {
            opacity:1;
        }
    }
}



@mixin animationNameOut(){

    @include animationName( animationNameOut);
    @include animationDuration( .2s );
    @include keyframes( animationNameOut ) {
        0% {
            opacity:1;
        }
        100% {
            opacity:0;
        }
    }
}

There’s a great opportunity here to pass variables to your animation mixin to customize for the context, depending on your needs.
When applying an animation to an element:

.element {
    @include animationNameOut();
    &:hover {
        @include animationNameIn();
    }
}

Through this example I’ve included a pair of animations. Here they are the same, but flipping this approach (as opposed to just reversing the animation) gives us the ability to have a different reverse which I feel creates a much more interesting effect.

The BEM naming convention is something I’ve only recently started using and already it’s become one of the biggest single improvements to my workflow. In addition to that, it slots into our SMACSS / OOCSS way of doing things perfectly.

Globbing is a handy addition to your Sass. Instead of defining every new file added to your main.scss, simply point to a directory and import every .scss file within it. Think of all those components we’ll be building! Note, in using with grunt there seems to be some problems—”grunt-sass-globbing” will only work with version 1.1.0 (1.2.0 was broken). (post writing! 1.3.0 has just been released, fingers crossed that bug is fixed) (post-post writing, I’ve just used it with gulp – it works perfectly there!)

Finally The shame.css file is an optional addition. If you need a super quick fix and just need to !important something because working into the real styles above just isn’t feasible because of time or money or confusion,—however best-practice it may be—we have the shame file. Best practice for dealing with bad practice. Déjà vu?

Oh and also, prefix js- to classes/ids used for Javascript selectors, something I’ve just read a note on, sounds like a good idea!


That’s about everything I’ve got on Sass! For now. Hopefully I’ve shed some light on at least one new thing for you. If there are any more you know of that I’ve missed, feel free to include them in the comments, if I get time I’ll pop them into this article and give you a shout out! No doubt there will be an unending list of improvements to workflow that are yet to come. Next up for me is grid frameworks—fingers crossed they’ll provide another big leap in my styling work flow! Finally, I’ve got to give thanks to the rest of the FED team here for introducing me to a whole bunch of the stuff I’ve written about here—it’s all improved my styling to no end!

« Prev Article
Next Article »