A Sass Component in 10 Minutes

Tweet

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!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://maximelaforet.com/ Maxime

    Very clean and well-explained, as usual.

    Thank you!

  • http://www.rjwebdesign.cz/ Roman Janko

    Awesome! :)

  • http://www.rjwebdesign.cz/ Roman Janko

    Hugo, how is possible that U use version 3,3? I updated SASS now (via Ruby CMD — gem update sass –) and get version 3.2.14. Thx

    • http://hugogiraudel.com/ Hugo Giraudel

      You can download it by running `gem install sass –pre`. Also http://sassmeister.com is using Sass 3.3.

      • http://www.rjwebdesign.cz/ Roman Janko

        is it a stable version?

        • http://hugogiraudel.com/ Hugo Giraudel

          No, hence the `–pre` flag. It’s a pre-release, an alpha or whatever you want to call it.

          Although Sass 3.3 is due anytime soon.

          • Santosh K. Shah

            What are the new features of sass 3.3

          • http://hugogiraudel.com/ Hugo Giraudel

            I wrote a round-up for David Walsh a while back: http://davidwalsh.name/future-sass. Not 100% accurate but gives a nice overview.

  • Vinay Raghu

    Hugo! You are awesome! Keep the good work!

  • thefairystamp

    This is awesome! I have been looking for this. :)

  • http://hugogiraudel.com/ Hugo Giraudel

    I can see four reasons why building such a component is better than doing it your way, although I have to agree with you that you can keep code very simple and still have things working like a charm.

    1. You don’t have to apply both classes to the DOM element. Only the one you want (e.g. `message-error` instead of `message message-error`). Discutable, but still something I prefer.
    2. You don’t have to repeat the color 3 times for each alert type. Having to repeat the same value 3 times is 2 extra times that could have been avoided.
    3. You can have a configuration list/map that can be moved anywhere you want including another file like `config.scss`. This is a big deal if you ask me. Not having to dig into the code to set things up is a bless in my opinion.
    4. Elegance, although this is very personal at that point.

  • http://hugogiraudel.com/ Hugo Giraudel

    It is meant to be. The title mentions the language (Sass) while the content is dealing with SCSS syntax.

  • daz4126

    Nice tutorial Hugo, thanks. Just wondering what the point of the %message placeholder was. Why not just put that CSS directly into the mixin?

    • http://hugogiraudel.com/ Hugo Giraudel

      Because that would duplicate the shared styles (padding, mardin…) in all selectors. Have a look at this pen where I did what you suggest: http://codepen.io/HugoGiraudel/pen/fddcdfd3a0907eac974516b8877e2987. Click on `CSS (SCSS)` to see the CSS output and compare it to the original pen. You’ll quickly get what I mean. ;)

      • daz4126

        Oh … great, that’s very useful to know. Thanks!

  • http://www.w3cplus.com/ 大漠

    Hi,Gugo.I often read your writing tutorial.Very good tutorial, and i like Sass too. Now I have an question for Sass. I am using Sass 3.3.0.rc.3 (Maptastic Maple),but i can not use Sass –watch command. If I use the Sass –watch, prompted me:

    sass –watch test.scss:test.css

    >>> Sass is watching for changes. Press Ctrl-C to stop.

    NoMethodError: undefined method `to’ for Listen:Module

    Use –trace for backtrace.

    Can you help me. Looking forward to your answer. thx!

    • http://hugogiraudel.com/ Hugo Giraudel

      I believe there was an issue with `–watch` in rc3. Try updating to rc4 if you can.

      • http://www.w3cplus.com/ 大漠

        Thank you! I had solved the question. I had updated the Sass from rc3 to rc4.

  • Dionysaur

    I can’t help but think that everything after the “Calling the mixin” section is making things unneccessarily complex and abstract. The code in this section can easily be understood at a glance, but what follows after the “Making things DRYer” heading has to be looked at closely to understand what’s happening. For me, the advantage of being able to have an independent configuration list is clearly overshadowed by the increase in code complexity & detachment, especially if the config list is moved away from the loop that outputs the css. Sometimes I prefer to try not to be too clever. ;)

    • LouisLazaris

      Sorry for the late response on this… I’ll let Hugo answer this himself as well, but my opinion is that although the sections after “Calling the Mixin” seem to make things more complex, it’s like anything modular or object-oriented. It’s more complex when you break it down line by line, but once you have it in place, you don’t need to deal with it anymore.. You just include the mixin and Sass does the rest.

    • http://hugogiraudel.com/ Hugo Giraudel

      In some way, you’re right. If you feel like it adds too much complexity to the code, feel free to light things up to have something that suits your team’s needs.

      As far as I am concerned, I like to have things working for me. And I like it even better when I can configure everything from a config file. This is why I made it this way.

      • Dionysaur

        Thanks for the reply. I think I’d just never know where to start & where to stop “abstracting things away”. I can absolutely see this way of working as being useful if you have a long list of elements that are built the same way, but if I already know I’m only going to have 4 types of warnings, give-or-take, I don’t really see the need. I think my way of making this configurable from a config file would simply be using good old color variables (but even with those I’m careful – I don’t like “semantic” variable names for colors).

        Anyway, apart from this “philosophical” debate, you’re still presenting a couple of good techniques in your article that I’m sure many will find useful. :)

  • Sean Lamberger

    Turned a few of my preconceived notions on their heads, there. This is why Sass is so intensely interesting right now. Great stuff, really easy to follow, and doubly easy to implement. Thanks for sharing!