A Sass Component in 10 Minutes

Kitty Giraudel
Share

Developers today recognize that while it’s great to write your website or application code as a collection of smaller pieces (i.e. components), accomplishing this is not always easy. So let’s look at this topic in detail using Sass.

Because nothing works better than a good ol’ example, I suggest we take something that is needed in almost every website or application that responds to user interaction: Alert messages (or notifications — or whatever you cool kids are calling them these days).

Creating a component to deal with different types of alert messages is the perfect case to level up your Sass. So roll up your sleeves, guys, ’cause we’re dippin’ in!

Defining our alert colors

What do we want? Messages! But what kind of messages? Let’s lean on a framework that already does something like this: Bootstrap. Bootstrap defines 4 types of alert messages:

  • Validation
  • Error
  • Warning
  • Information

That sounds good for our example component! Similar to how we use our tone of voice in real life to express different emotions, we can use colors to convey a message using alerts on the web. Hence, four types of alerts, each with its own color scheme. Once again, let’s borrow what Bootstrap has already done, and define our alert colors:

  • Green for success
  • Red for error
  • Yellow or orange for warning
  • Light blue for information

Writing our base styles

All messages will share common styles like padding, margins, and probably some typographic styles. In the end, the only differentiating styles will be the ones related to colors representing the different alerts.

As I discussed in the article Sass: Mixin or Placeholder?, it is best practice to extend a placeholder for static rules and to use a mixin for dynamic ones (that is, ones that are likely to vary according to context-related variables).

Let’s start with the placeholder:

%message {
  padding: .5em;
  margin-bottom: .5em;
  border-radius: .15em;
  border: 1px solid;
}

The first thing to note is that we’re not specifying any font styles like size, family, or line height. This module is going to be used in a project that already defines those elsewhere, and this helps our component be more isolated.

We also don’t define a color for the border. The border-color property is set by default to currentcolor, which is the color value, which, in many user agents, will be black.

And now the mixin:

@mixin message($color) {
  @extend %message;
  color: $color;
  border-color: lighten($color, 20%);
  background: lighten($color, 40%);
}

As you can see, the mixin does two things: First, it sets the color-related properties, accepting a unique color as a parameter, and it creates two variations of the color, thanks to Sass’s lighten color function. Using Sass color manipulation functions is a great way to reduce the number of arguments for a mixin.

The second thing the mixin does is extend the %message placeholder so you don’t have to rewerite those styles for each message type. And with this, the code is getting very DRY (Don’t Repeat Yourself).

Calling the mixin

We’re almost done. All we have left is to call the mixin for each type of message, passing in the correct color value for the type of message we want:

.message-error {
  @include message(#b94a48);
}

.message-valid {
  @include message(#468847);
}

.message-warning {
  @include message(#c09853);
}

.message-info {
  @include message(#3a87ad);
}

Making things DRYer

What we have done so far is pretty neat. Adding a new alert type is just a matter of dumping the mixin with the color of your choice to the freshly created class. But what if we want to make it even more portable?

Wouldn’t it be nice to have a way to map each type of alert to a color and nothing more? Well, there is: Nested lists. By creating a two-dimensional list and looping through its values, we can easily achieve this.

$message-types: (
  (error    #b94a48)
  (valid    #468847)
  (warning  #c09853)
  (info     #3a87ad)
) !default;

@each $message-type in $message-types {
  $type:  nth($message-type, 1);
  $color: nth($message-type, 2);

  .message-#{$type} {
    @include message($color);
  }
}

This Sass code produces the exact same result as the one from the code we wrote in the previous section. Except now the variables are set in a list; a list you can move to the top of your stylesheet or configuration file, making it very easy to add/edit/delete a message type.

Note: If you plan on adding this to a library or framework, the !default flag that I’ve included in the @message-types variable allows you to easily overwrite the variable, if needed.

Using a map (Sass 3.3)

We could additionally make use of the brand new Sass type added in Sass 3.3: Maps. Maps are like associative arrays in PHP, or objects in JavaScript. They, well, map a value to another one.

$message-types: (
  error   :  #b94a48,
  valid   :  #468847,
  warning :  #c09853,
  info    :  #3a87ad
) !default;

@each $type, $color in $message-types {
  .message-#{$type} {
    @include message($color);
  }
}

How awesome is that?

Gracefully handling errors

One thing that is often overlooked by Sass developers is the ability to gracefully handle errors. You should always make sure parameters passed to your custom functions and mixins are accurate and provide a warning message if they are not. This is so much better than letting the Sass compiler fail at doing something.

In our case, we should make sure the $color argument passed to the mixin is indeed a color.

@mixin message($color) {
  @if type-of($color) == color {
    @extend %message;
    color: $color;
    border-color: lighten($color, 20%);
    background: lighten($color, 40%);
  }

  @else {
    @warn "#{$color} is not a color for `message`.";
  }
}

This is enough to prevent the Sass compiler from crashing when trying to lighten a value that isn’t a valid color. Plus, it warns the developer that he made a mistake by passing an invalid argument to the mixin. It could be a typo or something deeper — whatever it is, it helps.

Final words

In about 30 lines of SCSS, we’ve managed to write a component that’s:

  • Clean and understandable
  • DRY and lightweight
  • Portable and configurable
  • Easy to scale

Which is a good set of rules to apply to all your components. Below is a demo showing the code in action:

See the Pen Messages & @extend by Hugo Giraudel (@HugoGiraudel) on CodePen.

This article is available in French over at La Cascade. Thank you for the translation, Pierre!