Simplifying Contexts and Events

Avatar of Kitty Giraudel
Kitty Giraudel on (Updated on )

Sass can somehow be a little of a black box, especially for young developers: you put some things in, you get some things out. Take the selector reference (&) for instance, it is a bit scary.

That being said, it doesn’t have to be like this. We can make its syntax friendlier with nothing more than two very simple mixins.

Events

When writing Sass, you often find yourself writing things like this:

.my-element {
    color: red;

    &:hover,
    &:active, 
    &:focus {
        color: blue;
    }
}

Quite tedious, and not necessarily easy to read. We could create a little mixin to make it simpler.

/// Event wrapper
/// @author Harry Roberts
/// @param {Bool} $self (false) - Whether or not to include current selector
/// @see https://twitter.com/csswizardry/status/478938530342006784 Original tweet from Harry Roberts
@mixin on-event($self: false) {
    @if $self {
        &,
        &:hover,
        &:active,
        &:focus {
            @content;
        }
    } @else {
        &:hover,
        &:active,
        &:focus {
            @content;
        }
    }
}

Rewriting our previous example:

.my-element {
    color: red;

    @include on-event {
        color: blue;
    }
}

Much better, isn’t it?

Now if we want to include the selector itself, we can set the $self parameter to true. For instance:

.my-element {
    @include on-event($self: true) {
        color: blue;
    }
}

This SCSS snippet will yield:

.my-element,
.my-element:hover,
.my-element:active,
.my-element:focus {
    color: blue
}

Contexts

Along the same lines, it is not uncommon to style an element depending on the parent he has. For instance, something like this:

.my-element {
    display: flex;

    .no-flexbox & {
        display: table;
    }
}

Let’s make the syntax a bit more friendly again with a simple mixin:

/// Contexts
/// @author Kitty Giraudel
/// @param {String | List} $context
@mixin when-inside($context) {
    #{$context} & {
        @content;
    }
}

Rewriting our previous example:

.my-element {
    display: flex;

    @include when-inside('.no-flexbox') {
        display: table;
    }
}