//TNG The Nitty Gritty

The low down on web technology.

Category: CSS

CSS Masks – How To Use Masking In CSS Now

by Christian Schaefer

CSS

Almost one year ago I wrote an article that dealt with an emerging WebKit CSS technique, the CSS filter effects, and the question if we could not have/emulate them in other browsers, too. Turned out we could.

Today I want to talk about another WebKit-only feature and show you how you might be able to use it across all of the browsers: This is about…

CSS Masks

CSS masks were added to the WebKit engine by Apple quite a while ago, namely back in April 2008. Masks offer the ability to control the opacity/transparency of elements on a per-pixel basis, similar to how the alpha/transparency-channel of "24-bit"-PNGs or 32-bit-TIFFs work.

RGBA

These images consist of the usual R(ed) G(reen) and B(lue) channels that define the colors of each pixel. But on top there is a fourth channel, the alpha channel, that defines every pixel's opacity through luminance: White meaning opaque, black meaning transparent, and countless grey values defining the semi-transparent inbetweens. As you can see in the picture to the left.

Mask

With CSS masks it is an HTML element that gets this type of treatment. And instead of using an alpha channel you assign an image resource to a CSS property named -webkit-mask-image, e.g. -webkit-mask-image: url(mouse.png);. Transparency is then read from that mask image and applied to the HTML element, like the picture on the right shows.

Comments
Masking used for user avatars to style them in a certain shape.

Neat! So what could that be good for? Well, masking could be used for images to style them in shapes. Or you could have long scrollable text smoothly fade out by using a mask image with a gradient from opaque to transparent.

Scroll fade

As with the background-image property you can also use a CSS gradient instead of an actual bitmap image, as in this code example:

Note: Beware that this is the "old" syntax that will soon be replaced by linear-gradient(to bottom, rgba(0,0,0,1), rgba(0,0,0,0)) (the destination keyword changes to to bottom). Lennart Schoors has a short article on that topic.

-webkit-mask-image: -webkit-linear-gradient(top, rgba(0,0,0,1), rgba(0,0,0,0));

While Apple brought CSS masks to WebKit, they failed to specify their implementation details and file a proposal with the W3C. Which means that if other vendors would have wanted to implement masks they would have had to reverse engineer and find out about all the implementation details first. Dirty work nobody wanted to do. So it was not until a few days ago, on the 15th of November (2012), that there appeared a first public working draft by the W3C called CSS Masking. But that one will be rather different to Apple's version.

The good news: Turns out the other browsers do have different capabilities which we can use as hooks to emulate WebKit's proprietary CSS masks. Woot!

Emulating a simple -webkit-mask-image cross browser

So let's say we want to mask an HTML element to the shape of a mouse's head as seen in the picture on the right.

With WebKit's proprietary CSS masks we would have this HTML:

<div class="element">
    <p>Lorem ipsum dolor sit … amet.</p>
</div>

Mouse shape in black
The mask image mouse.png could look like this.

And define the following CSS:

.element {
    width: 400px;
    height: 300px;
    overflow: hidden;
    color: #fff;
    background: url(background.png);
    -webkit-mask-image: url(mouse.png);
}

The modern browsers

Let's start with the modern browsers.
Current HTML5-ready browsers are able to parse SVG embedded inline into HTML, like so:

<!DOCTYPE html>
<html>
<body>
    <svg width="300px" height="300px">
        <circle cx="125" cy="150" r="50" fill="pink" stroke="green" stroke-width="5" />
    </svg>
</body>
</html>

On top of that WebKit as well as Firefox and Opera are also capable of doing the opposite - embedding XHTML into SVG, thanks to SVG 1.1's extensibility feature and its <foreignObject>-element:

<?xml version="1.0" standalone="yes"?>
<svg width="400px" height="300px" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <foreignObject width="400px" height="300px">

        <!-- HTML begin -->
        <div class="element">
            <p>Lorem ipsum dolor sit … amet.</p>
        </div>
        <!-- HTML end -->

    </foreignObject>
</svg>

Internet Explorer 9 and 10 are, the only modern browsers that lack support for <foreignObject>. We will turn to the IEs later.

What inline-SVG and <foreignObject> enable us to do is to enclose certain parts of our page's HTML in SVG wrappers, in this case the HTML blocks we want to mask:

Inception

Inception!!!

<!DOCTYPE html>
<html>
<head>
    <style>
        .element {
            width: 400px;
            height: 300px;
            overflow: hidden;
            color: #fff;
            background: url(background.png);
            -webkit-mask-image: url(mouse.png);
        }
    </style>
</head>
<body>

    <!-- SVG wrapper begins -->
    <svg>
        <foreignObject width="400px" height="300px">

            <!-- inner HTML begins -->
            <div class="element">
                <p>Lorem ipsum dolor sit … amet.</p>
            </div>
            <!-- inner HTML ends -->

        </foreignObject>
    </svg>
    <!-- SVG wrapper ends -->

</body>
</html>

Next step is to define an SVG-mask inside our inlined SVG that we can feed a mask image, and then apply that via style="mask:[mask id]" to our foreignObject/embedded HTML:

<!DOCTYPE html>
<html>
<body>

    <!-- SVG begins -->
    <svg>

        <!-- Definition of a mask begins -->
        <defs>
            <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">
                <image width="400px" height="300px" xlink:href="mouse.png"></image>
            </mask>
        </defs>
        <!-- Definition of a mask ends -->

        <foreignObject width="400px" height="300px" style="mask: url(#mask);">

            <!-- HTML begins -->
            <div class="element">
                <p>Lorem ipsum dolor sit … amet.</p>
            </div>
            <!-- HTML ends -->

        </foreignObject>
    </svg>
    <!-- SVG ends -->

</body>
</html>

White Mouse

And finally we need to have a proper mask image. We cannot simply use the image from WebKit's proprietary CSS mask, since SVG masks do not look at transparency values but at luminance values. So what we need to do is turn all opaque image pixels into shades of white.

In Photoshop that's super easy:

And KABOOOM! Masking of HTML content is up and running in WebKit, Firefox and Opera! Nice.

The Internet Explorers

Internet Explorers <= 8 do not understand any of the SVG markup above. They will just treat those tags as unknown elements. They will render the page as if it had this HTML code:

<!DOCTYPE html>
<html>
<body>
    <svg></svg>
    <defs></defs>
    <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse"></mask>
    <image width="400px" height="300px" xlink:href="mouse.png"/></image>
    </mask><//mask>
    </defs><//defs>
    <foreignObject width="400px" height="300px" style="mask: url(#mask);"></foreignObject>

    <div class="element">
        <p>Lorem ipsum dolor sit … amet.</p>
    </div>

    </foreignObject><//foreignObject>
    </svg><//svg>
</body>
</html>

This is cool, since this automatically degrades gracefully.

Where we have a problem is with IE9 and IE10. Both of them know SVG but they do not know the <foreignObject>-element. They render the SVG but consider the part that is enclosed into <foreignObject> was invalid SVG markup. So they discard this part of the SVG altogether. Meaning: our content is lost to our readers. Not good.

We could think about hiding the SVG parts for IEs using conditional comments but Microsoft decided for IE10 that they remove CCs altogether. So no solution yet.

The only solution we have is a) to test the client for the support of SVG extensibility / <foreignObject> and b) have JavaScript render the SVG snippets when SVG extensibility is supported. This is the JavaScript we need, and that we put at the head of our page:

function head () {
    if (window.SVGForeignObjectElement) {
        document.write('\
            <svg width="400px" height="300px">\
                <defs>\
                    <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">\
                        <image width="400px" height="300px" xlink:href="mouse.png"/>\
                    </mask>\
                </defs>\
                <foreignObject width="100%" height="100%" style="mask: url(#mask);">\
        ');
    }
}
function foot () {
    if (window.SVGForeignObjectElement) {
        document.write('\
                </foreignObject>\
            </svg>\
        ');
    }
}

And in our HTML markup we need to replace the SVG parts with calls to those JavaScript functions:

<body>
    <script>head();</script>
    <div class="element">
        <p>Lorem ipsum dolor sit … amet.</p>
    </div>
    <script>foot();</script>
</body>

Now content will remain intact in all Internet Explorers that do not support <foreignObject>. Should IE11 support it, it will get to see it.

Note 1: The backslashes you see at the end of lines inside our strings allow for multiline strings. They are supported by every browser and were officially standardized with ECMAScript 5.

Note 2: Isn't document.write the Antichrist of JavaScript best practices? He's nuts! Why is he using it? Well, nothing is just black and white - it all depends on the context. document.write is indeed very very bad if you make use of it in external JavaScript files. document.write forces you to embed external scripts at predefined places of your HTML and prevents almost any attempts of making them load asynchronous. And that means that if these external scripts fail to load, they'll bring your page to a grinding halt. But we are not dealing with an external file here - and you should leave it that way. So there is no blocking. Plus, thanks to having JavaScript outputting the extra markup to the screen while the HTML parser is still running you don't get to witness any flash of unstyled content (FOUC) as it would be the case if you fired a script on DOMContentLoaded. Now back to topic…

We could stop here and all be happy. But how about getting CSS masks working in the IEs, too? Wouldn't that take the cake? Well then, let's go…

Internet Explorers 4 - 9 have a proprietary filter named "Chroma". What the Chroma filter does is comparable to the filmmaker's bluebox / greenscreen technique: it lets pixels of an element in a defined color vanish from the screen. The color is therefore used as a "color mask".

The following CSS code would let disappear all cyan colored parts of an element:

filter: progid:DXImageTransform.Microsoft.Chroma(color='cyan');
zoom: 1; /* Needed in IE < 8 */

Why cyan? Well it is just a suggestion. You are not bound to cyan, you are free to use any color you like as color mask. But this is probably the one color that nobody would ever use to colorize anything, right? So it cannot get mixed up with content that should not be masked.

Now, what's even more interesting with the chroma filter is the fact that the filter does not only look at the colors of the filtered element itself but also takes into account it's children. Because of this one could create some sort of 10px thick frame by applying the following styles:

.parent {
    width: 120px;
    background-color: #eee;

    filter: progid:DXImageTransform.Microsoft.Chroma(color='cyan');
    zoom: 1;
}
.child {
    height: 100px;
    margin: 10px;

    background-color: cyan;
}

to this markup:

<div class="parent">
    <div class="child"></div>
</div>

Window

Then the cyan area of the element .child would be punched out of the filtered element .parent and we could look through it.

Window

So coming back to our mouse shaped example, what we need to do is create a version of the mouse shape image, where the outer parts are cyan and the inner shape is transparent as seen on the right.

In Photoshop do the following:

Saving with just 2 colors removes the anti-aliasing from the shape's borders. The reason we need to do that is because the chroma filter can only punch out one single color.

Cyan mouse mask

Now we need to layer that image over the element we want to mask, like in the picture on the right.

A difficulty we face with that is that we need to accomplish this without using CSS's position property. Why? IE's filters disable themselves when they hit positioned elements. The best approach is to work with negative margins in order to slide the cyan mask over the element, e.g.:

<div class="element">
    <p>Lorem ipsum dolor sit … amet.</p>
</div>
<img src="mouse-ie.png" style="display: block; margin-top: -300px;">

And now you would filter the whole thing:

Mouse shape in IE
The result.

<div style="width: 400px; height: 300px; filter: progid:DXImageTransform.Microsoft.Chroma(color='#00FFFF'); zoom: 1;">
    <div class="element">
        <p>Lorem ipsum dolor sit … amet.</p>
    </div>
    <img src="mouse-ie.png" style="display: block; margin-top: -300px;">
</div>

A sad aspect of this technique is that Microsoft decided besides conditional comments to remove all proprietary filters from IE10. They also removed them from all of the legacy modes. So this solution remains one for IE 4 to 9 only.

In order to serve this to the IEs we need to extend our JavaScript a bit:

function head () {
    if(window.SVGForeignObjectElement) {
        document.write('\
            <svg width="400px" height="300px">\
                <defs>\
                    <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">\
                        <image width="400px" height="300px" xlink:href="mouse.png"/>\
                    </mask>\
                </defs>\
                <foreignObject width="100%" height="100%" style="mask: url(#mask);">\
        ');
    } else {
        document.write('\
            <div style="width: 400px; height: 300px; filter: progid:DXImageTransform.Microsoft.Chroma(color=\'#00FFFF\'); zoom: 1;">\
        ');
    }
}
function foot () {
    if(window.SVGForeignObjectElement) {
        document.write('\
                </foreignObject>\
            </svg>\
        ');
    } else {
        document.write('\
                <!--[if lte IE 9]>\
                <img src="mouse-ie.png" style="display: block; margin-top: -300px;">\
                <![endif]-->\
            </div>\
        ');
    }
}

So if <foreignObject> is supported we wrap our element into SVG, if not we wrap it into markup that triggers IE's filters (IE <= 9). In the end this gives us a CSS mask in all browsers except one: IE10. Still pretty awesome, isn't it? Here is the final result:

Mouse shaped mask

Note that this works best when you use masks that use hard clipping along their shape edges. Should you be interested in masks with softer edges then you will lose IE support, as the chroma filter is not capable of punching out shapes with soft edges. Which is okay, too.

In any case, don't forget to check if the outcome without mask applied degrades nicely. Because there is IE10. And because JavaScript might be disabled, too.

Have I really said "all browsers browsers except one"? Ooops, I lied. This is true for desktop. Most mobile WebKit browsers still trail behind technology-wise. Not only Android but also Safari on iOS can't handle our SVG magic well. So for them we will double our SVG mask with -webkit-mask-image. We can assign that in our stylesheet:

.element {
    width: 400px;
    height: 300px;
    overflow: hidden;
    background: #36f url(background.png);
    color: #fff;
    -webkit-mask-image: url(mouse.png);
}

Finally, we are done!

Linear Gradient Masks

Remember the beginning where I told you that you could also use a gradient as mask? This is also possible in all of the above browsers, with some changes to our setup. First we need to replace the SVG's <mask>'s content either with an image of a gradient or we take the pure SVG route and define a SVG rectangle that is filled with an SVG gradient, like so:

<mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">
    <linearGradient id="g" gradientUnits="objectBoundingBox" x2="0" y2="1">
        <stop stop-color="white" stop-opacity="1" offset="0"/>
        <stop stop-color="white" stop-opacity="0" offset="1"/>
    </linearGradient>
    <rect width="400px" height="300px" fill="url(#g)"/>
</mask>

This represents a gradient that goes from top to bottom (from X1,Y1:0,0 to X2,Y2:0,1), who's first color stop is a fully opaque white and who's second stop is a fully transparent white.

For IE we don't need a cyan colored image any more since we will not use the chroma filter this time. Instead we will use the "Alpha" filter. We used to use the alpha filter to polyfill the missing opacity property in older IEs. But it is capable of much much more. You can switch it into a gradient mode where you can define start and end points as well as start and end opacities. It's a simple as this:

filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100,FinishOpacity=0,Style=1,StartX=0,FinishX=0,StartY=0,FinishY=300);

This gradient style alpha filter starts at pixels 0,0 and extends to pixels 0,300. Start opacity is 100%, end opacity is 0%.

On mobile WebKit we should normally be fine with a

-webkit-mask-image: -webkit-linear-gradient(top, rgba(0,0,0,1), rgba(0,0,0,0));

but it turns out that Android 2.x does not support gradients as mask image. We have no choice but to point to a PNG of a gradient, that starts opaque at the top and fades out into transparency to the bottom. Since -webkit-mask behaves like background it repeats images that are smaller than the area to cover. Therefore it is sufficient to use an image with a 1px width and 300px height. Finally to save on HTTP requests we embed the image as data URI with the help of duri.me. So this is the assigment we make in out stylesheet:

-webkit-mask-image: url(data:image/png;base64,iVBORw…[shortedned a bit]…FTkSuQmCC);

And the following are the changes to our JavaScript:

function head () {
    if (window.SVGForeignObjectElement) {
        document.write('\
            <svg width="400px" height="300px">\
                <defs>\
                    <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">\
                        <linearGradient id="g" gradientUnits="objectBoundingBox" x2="0" y2="1">\
                            <stop stop-color="white" stop-opacity="1" offset="0"/>\
                            <stop stop-color="white" stop-opacity="0" offset="1"/>\
                        </linearGradient>\
                        <rect width="400px" height="300px" fill="url(#g)"/>\
                    </mask>\
                </defs>\
                <foreignObject width="100%" height="100%" style="mask: url(#mask);">\
        ');
    } else {
        document.write('\
            <div style="width: 400px; height: 300px; filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100,FinishOpacity=0,Style=1,StartX=0,FinishX=0,StartY=0,FinishY=300); zoom:1;">\
        ');
    }
}

Gradient masked element
Look at the result.

function foot () {
    if (window.SVGForeignObjectElement){
        document.write('\
                </foreignObject>\
            </svg>\
        ');
    } else {
        document.write('\
            </div>\
        ');
    }
}

Radial Gradient Masks

Radial gradients are possible as well. Let's say we wanted to mask an image of 400px × 400px:

<body>
    <script>head();</script>
    <img src="photo.jpg" width="400" height="400" alt="Dude">
    <script>foot();</script>
</body>

Then we would need to change our SVG mask to this:

<mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">
    <linearGradient id="g" gradientUnits="objectBoundingBox" x2="0" y2="1">
        <stop stop-color="white" stop-opacity="1" offset="0"/>
        <stop stop-color="white" stop-opacity="0" offset="1"/>
    </linearGradient>
    <rect width="400px" height="400px" fill="url(#g)"/>
</mask>

And switch the alpha filter to style=2, the "2" standing for radial shape:

filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100,FinishOpacity=0,Style=2);

Translated to our script, this is how it would look like:

function head () {
    if (window.SVGForeignObjectElement) {
        document.write('\
            <svg width="400px" height="400px">\
                <defs>\
                    <mask id="mask" maskUnits="userSpaceOnUse" maskContentUnits="userSpaceOnUse">\
                        <radialGradient id="g" gradientUnits="objectBoundingBox" cx="0.5" cy="0.5" r="0.5" fx="0.5" fy="0.5">\
                            <stop stop-color="white" stop-opacity="1" offset="0"/>\
                            <stop stop-color="white" stop-opacity="0" offset="1"/>\
                        </radialGradient>\
                        <rect width="400px" height="400px" fill="url(#g)"/>\
                    </mask>\
                </defs>\
                <foreignObject width="100%" height="100%" style="mask: url(#mask);">\
        ');
    } else {
        document.write('\
            <div style="width: 400px; height: 400px; filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100,FinishOpacity=0,Style=2); zoom: 1;">\
        ');
    }
}

Radial gradient masked element
And here is the final result (Code). Radial gradients are great to let images softly fade into the background!

function foot () {
    if (window.SVGForeignObjectElement) {
        document.write('\
                </foreignObject>\
            </svg>\
        ');
    } else {
        document.write('\
            </div>\
        ');
    }
}

For mobile WebKits we again create a bitmap of a radial gradient. To save a little on bytesize it is sufficient to use an image with the dimensions 50px x 50px. To have that mask stretch over our 400px × 400px object we need to also set -webkit-mask-size: cover.

img {
    -webkit-mask-size: cover;
    -webkit-mask-image: url(data:image/png;base64,iVBORw0…[shortened a bit]…lFTkSuQmCC);
}

Final Words

I admit it wasn't the shortest of all articles but I hope I got you interested in playing around with masks on the web. So if you happen to create some decent stuff with the aforementioned techniques please leave a link under this post or drop us a note on Twitter. Also if you have any further questions regarding masks, don't hesitate to give us a shout.

Decouple Your CSS From HTML With Reusable Modules

by Hans Christian Reinl

CSS Sass

Sass 3.2 has a wonderful method to define reusable modules called placeholders which enable us to decouple CSS from HTML while using unambiguous, semantic class names.

Oh and by the way… We've got a raffle to give a way a book. See more below.

A few weeks ago Ian Storm Taylor had a great article on how to find the best way to CSS using Object Oriented CSS and the CSS preprocessor Sass.

The OOCSS view of thing is that you define modules to work with and in order to change these modules - to build variants of them - you apply classes to an HTML element that change its styles accordingly.

Bootstrap's Buttons
Differently styled buttons based on the OOCSS-technique in Bootstrap.

For instance here is an easy example of a button that changes its appearance when applying classes on it.

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

<button class="btn btn-large" type="button">
    Large Button
</button>

<button class="btn btn-large btn-primary" type="button">
    Large Primary Button
</button>

Does this seem familiar to you? Well actualy this example is from Bootstrap. Bootstrap uses the approach of OOCSS to define modules and extends styles to define variants of these modules.

Since I am not a huge fan of abbreviations because of the confusion it may cost when working in a team let us assume btn is named button for further examples.

To me it seams like Bootstrap made the approach of modular CSS well known throughout developers that were not sure on how to design naming patterns for their HTML elements' classes.

The Concept of Modules

Modules are also known in other approaches that are kind of related to the Object Oriented CSS idea. For example in SMACSS modularizing your CSS plays a big role. SMACSS is a concept of designing consistent CSS to maintain flexibility throughout projects and within a team.

Please read the section on modules in SMACSS for a better understanding of how to build modules effectively.

Furthermore Nicolas Gallagher has an approach on how he defines class names and some more naming conventions which are somewhat related to the BEM approach developed by Yandex. These conventions help you to develop your own naming style for your modules.

To come back to Ian Sorm Taylor's article let us look at the way he provides to define class names on HTML elements more semanically while decoupleing HTML from CSS.

First off we want to look at an example of how to define the above buttons using OOSass as Ian describes it. Your HTML would look something like this:

<button class="button" type="button">Button</button>
<button class="button-large" type="button">Large Button</button>
<button class="button-large-primary" type="button">Large Primary Button</button>

The styles for these buttons can be defined as follows in Sass:

.button {
    // Styles for a button
}

.button-large {
    @extend .button;
    // More styles for large buttons
}

.button-large-primary {
    @extend .button-large;
    // More styles for a large primary button
}

Writing Sass this way ensures that we do not need to touch the HTML when we want to change the appearance of a large primary button for example. You can do it in styles only - decoupled.

In a lot of cases you want to change your large primary button to a normal large button which would need a class name change in your HTML. We don't want to do this. We do not like to change classes in our HTML as this might require a change within a part of the app of which we are not necessarily the boss of. Styling is our domain!

Those classes sprinkled all over your HTML are going to change, and that’s not gonna be fun.

OOCSS + Sass = The best way to CSS, Ian Storm Taylor

This is the major reason why you should keep your CSS names away from the things it intends to do. A large primary may become a normal primary button or a button may become a primary large button. You cannot be sure about what the intend of the element might be – except the sematical meaning of the element on the page.

Creating semanic class names decouples the CSS from your HTML. Semanic class names do not need to change just because the styling changes since the job of an element remains as is.

This is exactly the point Ian tries to make with his approach to OOSass. He gives examples of modules that you can define withouth a meaning, semanic-less, and reuse them when it is appropriate.

Building a module

So let's go on and build a module for the button we just created. Modules are especially useful for reuse. You can define modules once and use them on multiple websites with different design but the same intention.

In Sass 3.2 some interesting features landed. One of them are placeholders that work exactly like any other rule you define in Sass with the exeption that they are not actually printed within the compiled CSS when you don't use them. Generally you prefix placeholders with % followed by the placeholder's name. You can then apply them by using @extend.

So with this knowledge in mind let us define a button module that we can use whenever appropriate by sticking to the idea that Ian described.

The module's code
This is how the code of our module looks in CSS including the call in .download-whitepaper.

We define some styles for a default button:

%button {
    background: #111;
    color: #fff;
    border: 0;
    padding: 0.5em 1em;
}

A large button basically has the same styling as this button but it needs to be a bit bigger:

%button-large {
    @extend %button;
    font-size: 1.3em;
}

Since we defined padding using em we do not need to do anything to increase the padding of the button.

Now when we are dealing with a primary Call-to-Action button all that should change compared to a "normal" button is the background color:

%button-primary {
    @extend %button;
    background: #27aae2;
}

For a primaty large button we just need to merge both the large style button and the primary style.

%button-primary-large {
    @extend %button-primary;
    @extend %button-large;
}

Let us use the button-module for a Call-To-Action button on a home page that asks the user to download a white-paper. It could be named (semantic class name) dowload-whitepaper. In Sass you are now able to apply the styles from your button modules while using a simple @extend call:

.download-whitepaper {
    @extend %button-primary-large;
}

See the full example module in this gist.

The CSS

Here is the output of the compiled CSS:

.download-whitepaper {
  background: #111;
  color: #fff;
  border: 0;
  padding: 0.5em 1em;
}

.download-whitepaper {
  font-size: 1.3em;
}

.download-whitepaper {
  background: #27aae2;
}

The output can be found in the aforementioned gist, too.

The compiled buttons
This is how the different buttons look, labeld with the according module-parts.

This is not the best you can get out of CSS, since you could easily combine all rules into one without the repeated selecor. But there is more to it.

We just created a whole module with four different variations of a button that is easily reusable. We are not chained to a specific structure in HTML and we do not need to include a bunch of classes on an element just to change the appearance. We are not dependend on any other component of our app other than styles. We have decoupled our HTML fully from CSS.

And as mentioned before another advantage of Sass' placeholders is the fact that they are only compiled into CSS when they are effectivly used. So every module you don't need in your site is not in your CSS if you compile your styles correctly.

Conclusion

Decoupling components of your website or app are essential to be able to work independent from HTML and JavaScript.

With Sass 3.2's placeholders it is straightforward to define modules that you can reuse on every element by simply extending the module's variant to the element's class.

This can be especially handy for huge websites that reuse a lot of code in different variations and in teams where you build upon existing code.

Site note: This technique not new. There have been others noticing how easy you can decoulpe CSS using Sass. Harry Roberts for example uses this style of writing modules in his CSS framework inuit.css in the arrow-module. Also Joshua Johnson wrote about placeholders in Sass and their value when dealing with grids. And as pointed out Ian Storm Taylor wrote a great article on how to use placeholders in Sass.

SMACSS by Jonathan Snook

Raffle

Since we want to encourage you to learn more about modularization and decoupling CSS we give away one of Jonathan Snook's SMACSS book. It is signed by Jonathan Snook himself.

All you need to do to take part in the raffle is to share this post via Twitter, Google+ or Facebook (mention and follow us to be save wink). If you want to you can also comment on this post and outline your opinion on the topic of decoupling CSS.

Please send an email to info@thenittygritty.co with the link to your share or mention us on Twitter. The raffle ends on Sunday 23:59h (all timezones, so you can still take part on monday afternoon if you are in New Zealand or something).

Update

The raffle is over and we want to thank everyone who participated. Congratulations to Alejandro García who won the book. If you didn't win the book you can still buy it from Jonathan's page.

Just to be sure: Any recourse to courts of law is excluded!
Image of SMACSS Book by courtesy of Jonathan Snook.