Create a Themable Button Set with Sass

css

If you have yet to give Sass a try, don’t worry, this is a good place to start. And if you haven’t already read Andrew’s primer on Sass, give it a read for a better understanding of what we’ll be covering and how to get setup with Sass.

In this article, we’ll start with one of the simplest design elements on a page –– a button. In an earlier post, the talented Mat Helme designed a vector UI button pack, which I’ve recreated in plain CSS. We’ll need to make it themable by creating different color schemes using Sass variables, mixins and functions. Let’s get started!

Button Pack

The buttons and color themes we’ll be creating

What We’ll Cover

We’ll be refactoring the CSS using the SCSS (Sassy CSS) syntax, which is closer to the pure CSS syntax we’re all used to. To start things off, our file structure should look something like this:

project/
   index.html
   css/style.css
   scss/style.scss

The “style.scss” file will compile into “style.css”, so that’s the only file we’ll need to link to in our HTML. In this demo, we’ll be learning about the following Sass features:

  • nesting
  • variables
  • mixins
  • color functions
  • partials

Starting with the CSS

Currently, our CSS is straightforward. Check it out in Codepen.

button {
   display: inline-block; 
   padding: .938em 1.875em;
   border: .094em solid #743EA5; 
   border-radius: .625em;
   background-color: #9A68C7;
   box-shadow: 0 .375em .313em -0.313em rgba(0,0,0,.8), inset 0 .063em rgba(255,255,255,.4), inset 0 -0.188em rgba(0,0,0,.15);
   color: #FFF;
   text-decoration: none;
   text-transform: uppercase;
   text-shadow: 0 .063em #000;
   cursor:pointer;
   font: bold 1.8rem sans-serif;
}
button:hover {
   background-color: #8A58B7;
   box-shadow: 0 .125em rgba(255,255,255,.4), inset 0 .063em rgba(255,255, 255,.4), inset 0 -0.188em #804FAD;
}
button:active {
   box-shadow: inset 0 0 1.094em #472566, inset 0 .063em #390668, inset 0 -0.188em #682CA0, 0 .063em rgba(255,255,255,.4); 
}

All padding and border pixel units have been converted to em units so they scale relative to the button’s font size, which makes our button modular.

The CSS rules are not modular, however, because they apply to button elements only. Instead, we’ll need to change the button selector to a class.

.btn {
...
}
.btn:hover {
...
}
.btn:active {
...
}

In the HTML, we’ll add the .btn class to the element. So far we have one button element to get started with –– this can just as well be an anchor element.

<button class="btn">
   Button
</button>

Getting Started with Sass

First, we’ll create a variable for each color theme:

$purple: #9A68C7;
$blue: #3BA9E4;
$green: #75B343;
$orange: #FF6A42;

Next, we’ll need to abstract several color properties from the .btn rule into a Sass mixin since we’ll be reusing most of them for each button theme. We’re only concerned with the theme colors at this point, so let’s create a new mixin that will contain any property that describes a color we might change in a theme.

From our .btn rule, we’ll abstract the background-color and border-color declarations into a mixin called btn-theme:

@mixin btn-theme {
   background-color: #9A68C7;
   border-color: #743EA5;
}

We’ll keep the other styles in the .btn rule, which sets the global theme and structure of our buttons.

Nesting Selectors

Since the :hover and :active states are necessary for each button, we can also nest them in our btn-theme mixin. We’ll need to replace the .btn class selector with an &, which will reference the parent selector in their respective rules, while the context still carries through.

@mixin btn-theme {
   background-color: #9A68C7;
   border-color: #743EA5;
   &:hover {
      background-color: #8A58B7;
      box-shadow: 0 .125em rgba(255,255,255,.4), inset 0 .063em   rgba(255,255,255,.4), inset 0 -0.188em #804FAD;
   }
   &:active {
      box-shadow: inset 0 0 1.094em #472566, inset 0 .063em #390668, inset 0 -0.188em #682CA0, 0 .063em rgba(255,255,255,.4);  
   }

We can also nest properties with matching namespaces. It’s not as common — or as beneficial — as nesting selectors, especially when you can use shorthand properties most of the time. Since there isn’t a “text” shorthand property in CSS, we’ll nest the text properties in our .btn rule into one rule:

.btn {
   ... 
   text: {
      transform: uppercase;
      decoration: none;
      shadow: 0 .063em rgba(0,0,0,.3);
   }
}

I’ll usually check my compiled CSS at this point to make sure things aren’t getting out of hand. That way if I see any red flags (like repeated rules or specificity issues), I can take care of it right away. So far, so good.

Color Values

With Sass we can simplify RGBa values by using a color keyword instead of each RGB value. For example,

rgba(0,0,0,.8);
rgba(255,255,255,.4);

can be rewritten as:

rgba(black,.8);
rgba(white,.4);

We can also use a hex value in place of the color keywords, as it will work the same way. Go ahead and try it with the remaining rgba values in the stylesheet.

While we’re replacing color values, notice how rgba(white,.4) is repeated many times throughout the stylesheet. Let’s create a variable for it – that way we’ll only need to declare and maintain it in a single instance.

$off-wht: rgba(white,.4);

Now we can replace the repeating values with our new variable.

box-shadow: 0 .125em $off-wht, inset 0 .063em $off-wht, ...

Color Functions

Sass color functions is where the real theming magic happens. We’ll use the darken and lighten functions to modify the shades of our base theme colors. For example,

...
&:hover {
   background-color: #8A58B7;
   box-shadow: ... ,inset 0 -0.188em #804FAD;
}

can be defined simply as:

...
&:hover {
   background-color: darken(#9A68C7, 6%);
   box-shadow: ... ,inset 0 -.188em lighten(#9A68C7, 2%);
}

Both functions return colors with a darker or lighter shade based on the amount we set between 0% and 100%.

Since we are declaring every themeable color property only once, we’ll need to pass an argument in our btn-theme mixin that will dynamically assign the theme color value to each property, then darken or lighten it as specified –– this will also dynamically set the different color shades we need in our themes.

@mixin btn-theme($btn-color) {

The $btn-color variable can now be placed anywhere a lighter or darker color is being described in the mixin.

border-color: darken($btn-color, 20%);
background-color: $btn-color;
&:hover {
   background-color: darken($btn-color, 6%);
   box-shadow: 0 .125em $off-wht, inset 0 .063em $off-wht, inset 0 -.188em lighten($btn-color, 2%);
}
&:active {
   box-shadow: 0 .063em $off-wht, inset 0 0 1.094em darken($btn-color, 40%), inset 0 .063em darken($btn-color, 20%),inset 0 -0.188em darken($btn-color, 20%); 
}

Once we define the base colors for our buttons, we no longer need to worry about the other shades –– the color functions handle it for us.

Multiple Arguments

Let’s add a transition for the :active and :hover states. The transition property is supported in most browsers, but we still need to use the vendor prefixes for Chrome, Safari, and older versions of Firefox. Instead of having to write each prefixed declaration every time we want to use a transition, we can create a mixin with the necessary vendor prefixes.

@mixin trans($val...) {
   -webkit-transition: $val;
   -moz-transition: $val; 
   -o-transition: $val; 
   transition: $val; 
}

But sometimes a mixin can have an unknown number of arguments. For example, our mixin above might take any number of transition values as arguments. For this, Sass supports “variable arguments,” which are arguments that get passed as a list of arguments. To create one we need to add “…” after the variable in the argument.

Now our trans mixin can be reused anywhere in the stylesheet while accepting multiple values, so in our .btn rule, we’ll include the mixin with the transition values we want to use.

.btn {
   ...  /* other properties */ 
   @include trans(0.2s ease-in-out);
}

Creating a Partial

Finally, let’s convert our file into a “partial” by saving it as “_buttons.scss” in our scss folder. The file becomes a chunk (or partial) of SCSS code that can be imported into “style.scss”, but will not compile and output as a separate CSS file. When importing the partial we can leave out the file extension and underscore.

@import 'buttons';

Finishing Up

Now we’re ready to create the color theme rules. Instead of declaring each new color value in every rule, we can simply include the btn-theme mixin we created earlier and pass the appropriate color variable as its argument.

.purple {
   @include btn-theme($purple);
}
.blue {
   @include btn-theme($blue);
}
.green {
   @include btn-theme($green);
}
.orange {
   @include btn-theme($orange);
}

If we need to change a button’s color theme, we simply replace the element’s class name. To add a new color theme, all we need to do is create the variable and its rule in the partial file.

<button class="purple btn">
   Button
</button>
<button class="blue btn">
   Button
</button>
<button class="green btn">
   Button
</button>
<button class="orange btn">
   Button
</button>

Hopefully now you have a better understanding of how Sass makes our CSS smarter, cleaner, modular, and above all, fun! You can view the completed working example here.

Some of what we’ve covered here can be simplified even further with the Compass framework – more on that coming soon!

Guil Hernandez

Guil is the front-end design teacher at Treehouse. You can follow Guil on Twitter at @guilh.

Comments

One comment on “Create a Themable Button Set with Sass