Nesting, Extend, Placeholders, and Mixins

Exclusive offer: get 50% off this eBook here
Sass and Compass for Designers

Sass and Compass for Designers — Save 50%

Produce and maintain cross-browser CSS files easier than ever before with the Sass CSS preprocessor and its companion authoring framework, Compass with this book and ebook

$26.99    $13.50
by Ben Frain | June 2013 | Web Development

In this article by Ben Frain from the book Sass and Compass for Designers, we will look at the capabilities of Sass and Compass when it comes to actually writing styles. These are the core capabilities likely to be employed when working with Sass and Compass day-to-day. In this article, we will learn:

  • What nesting is and how it allows styles to be modularized

  • How the @extend directive allows us to extend existing rules

  • To use placeholder selectors to extend styles only when needed

  • What mixins are and how we can use them to easily produce oft-needed code

  • How to write a mixin for our own purposes

(For more resources related to this topic, see here.)

Styling a site with Sass and Compass

Personally, while abstract examples are fine, I find it difficult to fully understand concepts until I put them into practice. With that in mind, at this point I'm going to amend the markup in our project's index.html file, so we have some markup to flex our growing Sass and Compass muscles on.

We're going to build up a basic home page for this book. Hopefully, the basic layout and structure will be common enough to be of help. If you want to see how things turn out, you can point your browser at http://sassandcompass.com, as that's what we'll be building.

The markup for the home page is fairly simple. It consists of a header with links, navigation made up of list items, images, and content and a footer area. Pasting the home page markup here will span a few pages (and be extremely dull to read. Don't get too hung up on the specifics of the markup.

Let me be clear. The actual code, selectors used, and the finished webpage that we'll create are not important. The Sass and Compass techniques and tools we use to create them are. You can download the code from the book's page at http://packtpub.com and also from http://sassandcompass.com

You can download the code from the book's page at http://packtpub.com and also from http://sassandcompass.com

At this point, here's how the page looks in the browser:

Wow, what a looker! Thankfully, with Sass and Compass we're going to knock this into shape in no time at all.

Notice that in the source code there are semantically named classes in the markup. Some people dislike this practice, but I have found that it makes it easier to create more modular and maintainable code.

A full discussion on the reasoning behind using classes against styling elements themselves is a little beyond the scope of this book. However, a good book on this topic is SMACSS by Jonathan Snook (http:// smacss.com). It's not essential to adhere slavishly to the conventions he describes, but it's a great start in thinking about how to structure and write style sheets in general.

First, let's open the _normalize.scss partial file and amend the default styles for links (changing the default text-underline to a dotted bottom border) and remove the padding and margin for the ul tags.

Now I think about this, before we get knee-deep in code, a little more organization is called for.

Separating the layout from visuals

Before getting into nesting, @extend, placeholders, and mixins, it makes sense to create some partial files for organizing the styles.

Rather than create a partial Sass file for each structural area (the header, footer, and navigation), and lump all the visual styles relevant inside, we can structure the code in a slightly more abstract manner.

There is no right or wrong way to split up Sass files. However, it's worth looking at mature and respected projects such as Twitter Bootstrap (https://github.com/twitter/bootstrap) and Foundation from Zurb (https://github.com/zurb/foundation) to see how they organize their code.

We'll create a partial file called _base.scss that will contain some base styles:

body {
font-size: 1em;
line-height: 1.4;
}
::-moz-selection {
background: $color1;
text-shadow: none;
}
::selection {
background: $color1;
text-shadow: none;
}

Then a partial file called _layout.scss. That will only contain rules pertaining to visual layout and positioning of the main page areas (the previously mentioned header, footer, aside, section, and navigation). Here are the initial styles being added into the _layout.scss partial file:

* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body {
max-width: 1200px;
margin: auto;
}
header[role="banner"],footer[role="contentinfo"] {
width: 100%;
display: block;
}
nav[role="navigation"] {
width: 25%;
float: left;
}
.main-content {
width: 70%;
float: right;
}
footer[role="contentinfo"] {
clear: both;
}

There is nothing particular to Sass there, it's all standard CSS.

Debug help in the browser

Thanks to the popularity of Sass there are now experimental features in browsers to make debugging Sass even easier. When inspecting an element with developer tools, the source file and line number is provided, making it easier to find the offending selector. For Chrome, here's a step-by-step explanation: http://benfra.in/1z1 Alternatively, if using Firefox, check out the FireSass extension: https://addons.mozilla.org/en-us/firefox/addon/ firesass-for-firebug/

Let's create another partial file called _modules.scss. This will contain all the modular pieces of code. This means, should we need to move the .testimonial section (which should be a modular section) in the source code, it's not necessary to move it from one partial file to another (which would be the case if the partial files were named according to their existing layout).

The _module.scss file will probably end up being the largest file in the Sass project, as it will contain all the aesthetics for the items on the page. However, the hope is that these modular pieces of code will be flexible enough to look good, regardless of the structural constraints defined in the _layout.scss partial file.

If working on a very large project, it may be worth splitting the modules into sub-folders. Just create a sub-folder and import the file. For example, if there was a partial called _callouts.scss in a sub-folder called modules, it could be imported using the following code:

@import "partials/modules/callouts";

Here is the contents of the amended styles.scss file:

@import "compass";
@import "partials/variables";
@import "partials/normalize";
@import "partials/base";
@import "partials/layout";
@import "partials/modules";

A quick look at the HTML in the browser shows the basic layout styles applied:

With that done, let's look at how Sass's ability to nest styles can help us make modules of code.

What nesting is and how it facilitates modules of code

Nesting provides the ability to nest styles within one another. This provides a handy way to write mini blocks of modular code.

Nesting syntax

With a normal CSS style declaration, there is a selector, then an opening curly brace, and then any number of property and value pairs, followed by a closing curly brace. For example:

.css {
display: block;
}

Where Sass differs is that before the closing curly brace, you can nest another rule within. What do I mean by that? Consider this example:

a {
color: $color7;
&:hover,&:focus {
color: $color5;
}
&:visited,&:active {
color: $color4;
}
}

In the previous code, a color has been set for the link tag using a variable. Then the hover and focus state have been nested within the main anchor style with a different color set. Furthermore, styles for the visited and active state have been nested with an alternate color defined.

To reference a variable, simply write the dollar sign ( $) and then the name of the variable, for example, $variable.

When compiled, this produces the following CSS:

a {
color: blue;
}
a:hover, a:focus {
color: #007fff;
}
a:visited, a:active {
color: chartreuse;
}

Notice that Sass is also smart enough to know that the hex value #7FFF00 is actually the color called chartreuse, and when it has generated the CSS it has converted it to the CSS color name.

How can this be used practically? Let's look at the markup for the list of navigation links on the home page. Each currently looks like this:

<nav role="navigation">
<ul class="chapter-list">
<li class="chapter-summary">
<a href="chapter1.html">
<b>Chapter 1</b>
<span>Getting started with Sass and Compass</span>
</a>
</li>

I've omitted the additional list items and closing tags in the previous code for the sake of brevity. From a structure point of view, each list item contains an anchor link with a <b> tag and a <span> tag within. Here's the initial Sass nested styles that have been added into the _modules.scss partial to control that section:

.chapter-summary {
a {
display: block;
padding: .5em;
color: $color10;
opacity: .7;
border: none;
&:hover {
opacity: 1;
}
&:visited {
opacity: .9;
}
b {
display: block;
}
span {
display: block;
font-size: .8em;
}
}
}

Notice that the rules are being nested inside the class .chapter-summary. That's because it then limits the scope of the nested styles to only apply to elements within a list item with a class of .chapter-summary. However, remember that if the styles can be re-used elsewhere, it isn't necessarily the best practice to nest them, as they may become too specific.

The nesting of the selectors in this manner partially mirrors the structure of the HTML, so it's easy to see that the styles nested within only apply to those that are similarly structured in the markup.

We're starting with the outermost element that needs to be styled (the <li class=”chapter-summary”>) and then nesting the first element within that. In this instance, it's the anchor tag. Then further styles have been nested for the hover and visited states along with the <b> and <span> tags.

I tend to add focus and active states at the end of a project, but that's a personal thing. If you're likely to forget them, by all means add them at the same time you add hover.

Here's the generated CSS from that block:

.chapter-summary a {
display: block;
padding: .5em;
color: black;
opacity: .7;
border: none;
}
.chapter-summary a:hover {
opacity: 1;
}
.chapter-summary a:visited {
opacity: .9;
}
.chapter-summary a b {
display: block;
}
.chapter-summary a span {
display: block;
font-size: .8em;
}

The nested styles are generated with a degree of specificity that limits their scope; they will only apply to elements within a <li class=”chapter-summary”>.

It's possible to nest all manner of styles within one another. Classes, IDs, pseudo classes; Sass doesn't much care. For example, let's suppose the <li> elements need to have a dotted border, except for the last one. Let's take advantage of the last-child CSS pseudo class in combination with nesting and add this section:

.chapter-summary {
border-bottom: 2px dotted;
&:last-child {
border: none;
}
/* other styles */

That will generate the following CSS:

.chapter-summary {
border-bottom: 2px dotted;
}
.chapter-summary:last-child {
border: none;
}

The parent selector

Notice that any pseudo selector that needs to be nested in Sass is prefixed with the ampersand symbol (&), then a colon (:). The ampersand symbol has a special meaning when nesting. It always references the parent selector. It's perfect for defining pseudo classes as it effectively says 'the parent plus this pseudo element'. However, there are other ways it can work too, for example, nesting a few related selectors and expressing different relationships between them:

.main {
.content {
width: 70%;
}
.content & {
width: 100%;
}
.content & {
.two & {
color: pink;
}
}
}

This actually results in the following CSS:

.main .content {
width: 70%;
}
.content .main {
width: 100%;
}
.two .content .main {
color: pink;
}

We have effectively reversed the selectors while nesting by using the & parent selector.

Chaining selectors

It's also possible to create chained selectors using the parent selector. Consider this:

.selector-one {
&.selector-two {
color: green;
}
}

That will compile to this:

.selector-one.selector-two {
color: green;
}

That will only select an element that has both HTML classes, namely selector-one and selector-two.

The parent selector is perfect for pseudo selectors and at odd times its necessary to chain selectors, but beyond that I couldn't find much practical use for it, until I saw this set of slides by Sass guru Brandon Mathis http://speakerdeck.com/u/imathis/p/sass-compass-the-future-of-stylesheets-now. In this, he illustrates how to use the parent selector for nesting a Modernizr relevant rule.

Sass and Compass for Designers Produce and maintain cross-browser CSS files easier than ever before with the Sass CSS preprocessor and its companion authoring framework, Compass with this book and ebook
Published: April 2013
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

Easy Modernizr styles with the parent selector

Modernizr provides the perfect situation in which to utilize the parent selector. When a fork is needed in CSS, Modernizr can save the day. If forking code sounds alien, fear not, this will make more sense shortly. This is a bit of a tangent but I think it's worthwhile.

Let's download Modernizr (http://modernizr.com) and save it into the js folder. Then add a reference to it in the section of the web page:

<script src = "js/modernizr.2.6.2.min.js"></script>

If you have no idea what Modernizr is or how to use it, I'd recommend starting with this blog post: http://benfra.in/1y2

Let's use the font called Sansation by Bernt Montag as the main body text font for the site. There's an @font-face version of the font available free from Font Squirrel (http://www.fontsquirrel.com/fonts/Sansation):

The font files have been copied into a folder called fonts inside the css folder. Here's the hierarchy of the css folder in the OS X Finder:

Make a partial file for fonts

We'll create another partial file called _fonts.scss. Inside that file will be references to any web fonts needed. Before that, let's import the partial file into the main styles.scss file:

@import "compass";
@import "partials/variables";
@import "partials/fonts";
@import "partials/normalize";
@import "partials/base";
@import "partials/layout";
@import "partials/modules";

Now, we need to set up the font files in the _fonts.scss partial file. To help matters, the downloaded Font Squirrel font includes a CSS file (stylesheet.css) with the relevant font files referenced. However, it needs amending before pasting it into the _fonts.scss partial file.

First we're going to keep each font used in a sub-folder, just to keep things tidy. Furthermore, we'll use a Compass URL helper to reference the fonts. So instead of:

src: url

In the downloaded code, we will write:

src: font-url

The Compass font-url helper is worth using as it allows us to save the font files in the fonts sub-folder of the css folder. Then, because we added a fonts_dir directory in the config.rb file, Sass and Compass know that they need to look for the fonts in that location.

Changing the font with Modernizr and the parent selector

Now, with that web font set up it's time to finally use that parent selector to fork the CSS styles with the help of Modernizr. In the _body.scss partial file, the first rule looks like this:

body {
font-size: 1em;
line-height: 1.4;
font-family: "SansationRegular","HelveticaNeue-Light","Helvetica
Neue", Helvetica, Arial, sans-serif;
// Modernizr fallback for when there is no fontface support
.no-fontface & {
font-size: 1.05em;
}
}

The font-family property has been added with the value of “SansationRegular” first, then a number of secondary fonts (using a standard font stack).

Sansation looks fine at 1em size, but if the browser needs to use one of the backup fonts (if the device doesn't support @font-face), the other fonts in the stack look a little too big. In this eventuality, it would be good if the font size could be slightly less. Modernizr can help us create this fork.

When @font-face support is missing, Modernizr adds a class of .no-font-face to the HTML. In that instance, the nested rule gets applied (thanks to it being more specific and later in the cascade) amending the font-size slightly. Our nested rule actually produces the following CSS:

body {
font-size: 1em;
line-height: 1.4;
font-family: "SansationRegular", "HelveticaNeue-Light", "Helvetica
Neue", Helvetica, Arial, sans-serif;
}
.no-fontface body {
font-size: 1.05em;
}

Lovely! By using this nesting method along with the parent selector, all these related styles are grouped together in the Sass files. Also, thanks to Modernizr, browsers that support @font-face and those that don't get a relevant font-size.

Remember that the parent selector isn't needed for nesting inline elements (<span>, <i>, <b> and likewise), classes, or IDs. Just nest them normally.

Dangers of excessive nesting

It's possible to nest styles many levels deep. Here's an example of nesting using IDs, classes, and pseudo selectors:

.nesting {
.class {
width: 100%;
}
#id {
width: 100%;
}
&:hover {
color: $color7;
}
.multi-nesting {
.class-within {
width: 90%;
#id_within {
width: 90%;
&:hover {
color: $color4;
}
}
}
}
}

However, when I see chunks of code like that, I start to get a little concerned. There is a real danger that nesting this many levels deep will create CSS rules that are too specific. For example, here is the generated CSS from that little block:

.nesting .class {
width: 100%;
}
.nesting #id {
width: 100%;
}
.nesting:hover {
color: blue;
}
.nesting .multi-nesting .class-within {
width: 90%;
}
.nesting .multi-nesting .class-within #id_within {
width: 90%;
}
.nesting .multi-nesting .class-within #id_within:hover {
color: chartreuse;
}

As you can see, the further into the nesting we get, the more specific the outputted CSS selector becomes. In the final rule there, we are selecting a hover state on an ID selector that will only be relevant if it's within a class of class-within, that is also a child of a class multi-nesting that is also a child of a class nesting. To cut a long story short, you should probably just use the following (not nested within anything else):

#id_within {
width: 90%;
&:hover {
color: $color4;
}
}

That would output the following CSS:

#id_within {
width: 90%;
}
#id_within:hover {
color: chartreuse;
}

This means that the element with an ID of id_within can be moved anywhere else in the markup and still get the styles applied. Here's a simple rule I try and abide by: only make rules as specific as they need to be, and if nesting, try not to go more than three levels deep.

Are ID selectors bad?

There's a growing sentiment in the web developer community that if possible, when choosing selectors in CSS, IDs are a bad choice. As ever in web development, I think it depends.

The genesis of the thinking stems from the fact that ID selectors are limited by nature (a page is invalid if a single ID exists more than once on any page) and therefore, it makes rules bound to ID selectors limiting (as any styles can't be re-used elsewhere). In addition, ID selectors are more specific than a class style, and that makes it difficult to override those declarations later on.

Those are valid concerns. However, there may be times where the same ID appears on every page and you are confident you won't need to override it. In that case, don't get hung up on using an ID as a styling hook. If the option for using a class name exists, take it, but don't worry about using an ID if necessary. For a little more info on the subject, you might want to take a look at the following blog post: http://benfra.in/1yq

It's also worth knowing that as long as support for IE6 isn't necessary, it's possible to use an attribute selector to style an ID that will hook the style without the massive specificity that ordinarily comes from using an ID selector. For example:

[id="id-name"] {}

Instead of using:

#id-name {}

Nesting namespaces

Sass also lets you nest namespaced CSS properties. That's any CSS property that has a namespace reserved. For example, border has border-left, border-right, border-top, and border-bottom. Font has font-weight, font-family, and font-size. Here's an example of nesting the namespaced border property:

.nesting-namespace-properties {
border: {
top: 1px dashed $color7;
right: 1px dotted $color5;
bottom: 2px solid $color8;
left: 1px solid $color4;
}
}

That would compile to the following CSS:

.nesting-namespace-properties {
border-top: 1px dashed blue;
border-right: 1px dotted #007fff;
border-bottom: 2px solid #7f00ff;
border-left: 1px solid chartreuse;
}

With Sass, it's possible to define the namespaced part of the property and then nest the possible variants within it. The same thing could be done with the margin and padding property (where there are variants such as margin-left and margin right). Personally, I find it easier to rely on the standard CSS shorthand syntax in those instances.

For the sake of clarity, using the standard CSS shorthand syntax for a margin, to remove the margin on all sides of an element except the bottom, write:

.margin {
margin: 0 0 1em 0;
}

When writing this CSS shorthand (which is applicable to the padding property too) remember that the values defined left to right in the code, relate clockwise starting at the top (for example, first top, then right, then bottom, and finally left). Also, be aware that when a value is zero, there is no need to declare a unit of measure (such as em or px).

When writing Sass, nesting namespaced properties isn't something I do very often. I prefer the clarity of having the full property listed. However, it's a preference thing, so be aware that nesting can be used in this manner.

While we have acknowledged that nesting should be used considerately, it is incredibly handy for defining modular sections of code. For example, here are some basic nested styles to make a module for the <aside class=”testimonial”> area:

.testimonial {
background-color: #eee;
border-top: 2px solid #ddd;
border-bottom: 2px solid #ddd;
padding: 1em 2em;
> img {
display: inline-block;
width: 17%;
}
blockquote {
margin: 0 0 0 3%;
padding: 0 .5em;
width: 76%;
font-family: $blockquote;
font-size: 2.4em;
font-style:italic;
display: inline-block;
vertical-align: top;
footer {
font-size: .6em;
border-top: 2px dotted #ddd;
margin: 20px 0 0 0;
padding: 10px 0 0 0;
}
}
blockquote.small {
font-size: .9em;
}
}

Notice here that at the bottom of the module we have added a style for the <blockquote> tag if it also has a class of small added. This is so that if the testimonial needed to be moved into an area with constricted space such as a sidebar the font size isn't too big. For example:

It may be preferable to add an entirely different class to cater for these different visual permutations. So instead of a .blockquote. small class (that will get applied when both blockquote and small HTML classes are present on the HTML element), we might use .blockquote--small and add that HTML class to the element to denote the small variant of the original block instead.

We've also defined colors as hex values here. When using Sass and Compass there is little reason to do that.

Finally, notice how a variable has been used for the font-family of the blockquote. The variable itself is just a font-stack. Here's that variable in the _variables.scss partial file:

$blockquote: Constantia, "Lucida Bright", Lucidabright,
"Lucida Serif", Lucida, "DejaVu Serif", "Bitstream Vera Serif",
"Liberation Serif", Georgia, serif;

With those styles added, this is how our testimonial area renders:

Using the @extend directive to extend existing rules

The @extend directive is used to extend another style. It allows any style to inherit the properties and values defined in another. Suppose there are a few elements to style that share some characteristics; they are a prime candidate for the @extend directive. Let's try an abstract example. We need to create a few boxes. A standard box, a success box, an information box, and finally a warning box. Consider this code:

// Box
.box {
padding: 2em;
color: $color10;
background-color: $color11;
}
// Warning Box
.warning-box {
@extend .box;
border: 2px dotted $color1;
}
// Success Box
.success-box {
@extend .box;
border: 2px dotted $color4;
}
// Information Box
.info-box {
@extend .box;
border: 2px dotted $color7;
}

First there is a style for the basic box, then each variation extends the box but has it's own different color border. This is the CSS code it generates:

.box, .warning-box, .success-box, .info-box {
padding: 2em;
color: black;
background-color: white;
}
.warning-box {
border: 2px dotted red;
}
.success-box {
border: 2px dotted chartreuse;
}
.info-box {
border: 2px dotted blue;
}

Sass is smart enough to group the shared styles under a single combined selector. Using the @extend directive in this manner prevents endless repetition of code for similar elements.

Now, notice in this example, our first rule for .box class wouldn't actually be used. It's being declared for the sole purpose of extending. That may seem a little wasteful and, thankfully, the smart people working on Sass have already got a solution. In situations where we want to define rules purely to extend them elsewhere, we can use placeholder selectors. Let's look at how they work.

Using placeholder selectors to extend styles only when needed

We've just looked at how the @extend directive can extend an existing rule. However, in situations when a rule is being created purely to extend it, use a placeholder selector instead. Here's our prior example written with a placeholder selector on the first rule instead:

// Box
%box {
padding: 2em;
color: $color10;
background-color: $color11;
}
// Warning Box
.warning-box {
@extend %box;
border: 2px dotted $color1;
}
// Success Box
.success-box {
@extend %box;
border: 2px dotted $color4;
}
// Information Box
.info-box {
@extend %box;
border: 2px dotted $color7;
}

Instead of the normal selector (a period for a class or hash/pound for an ID selector), use a percentage symbol (%) instead. Then use the @extend directive to extend it. Here is the code that compiles to:

.warning-box, .success-box, .info-box {
padding: 2em;
color: black;
background-color: white;
}
.warning-box {
border: 2px dotted red;
}
.success-box {
border: 2px dotted chartreuse;
}
.info-box {
border: 2px dotted blue;
}

By using the placeholder selector instead, it prevents surplus rules being generated unless they have been extended elsewhere. We'll use placeholder and @extend selectors frequently to build the styles for the homepage of http://sassandcompass.com as they are particularly handy when working with mixins.

What mixins are and how we can use them to easily produce oft-needed code

Nesting @extend and placeholder selectors are very convenient but they don't actually produce extra code. Mixins on the other hand do. Those readers who have been unfortunate enough to use Microsoft Word or Excel may have used macros. If so, think of mixins like macros.

Typically, a mixin is defined once, then included elsewhere in the Sass file and passed any optional arguments. Then, on compilation, it generates the relevant code.

That sounds pretty complicated and "programmer-ish". If such talk makes your palms go a little sweaty or your eyes glaze over, don't worry.

Compass has literally hundreds of ready-made mixins that address every conceivable CSS need. Don't want to dabble in writing mixins? Just use the ones that Compass provides; enjoy cross-browser compatibility that makes you feel heroic and thank the Compass team with a donation to the Compass's charityware cause: http://umdf.org/compass

However, for the curious, let's look at making a mixin and we'll soon get the hang of things.

Remember back when we added some content into our _layout.scss file, the first rule was this:

* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}

The star selector was used to select all elements and change the box-sizing model to border-box. To get the best browser support possible, the property was repeated a number of times with vendor prefixes (one for WebKit and another for Mozilla with the final official property and value pair listed last so that it supersedes the others, if present).

In case you aren't aware of what the different box-sizing models do, the border-box model allows a width to be defined for an element and it takes into account borders, padding, and content. The size set is the size that gets painted to the screen. The alternative (and at this point more commonly used) content-box box-sizing model requires content, padding, and border to be factored-in when specifying the width/ height of an element.

Microsoft actually implemented border-box sizing way back in Internet Explorer 8, so browser support is good. As I'm not concerned about IE7 and below, I'm happy to use border-box here. To read more on the matter, head over to this excellent post by all-round web genius, Paul Irish, on the matter: http://paulirish.com/2012/boxsizing- border-box-ftw/

Let's write a little mixin here to generate this code for us. Let's create another partial file called _mixins.scss and import that into our main styles.scss. Here's what the import section looks like now:

@import "compass";
@import "partials/variables";
@import "partials/mixins";
@import "partials/fonts";
@import "partials/normalize";
@import "partials/base";
@import "partials/layout";
@import "partials/modules";

Notice, the mixins partial file has been imported after the variables partial, so any of the variables can be used in the mixins and then in turn any of the mixins can be used in the other files that come after. In the _mixins.scss partial file, we're adding this:

@mixin bs($bs-type) {
-webkit-box-sizing: $bs-type;
-moz-box-sizing: $bs-type;
box-sizing: $bs-type;
}

Then, in the _layout.scss file, the first line is being amended to this:

* {
@include bs(border-box);
}

When the Sass file is saved, the generated CSS looks as we hoped:

* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}

So how did that actually happen? Let's go back and consider our mixin code and establish the basic syntax.

Basic mixin syntax

First of all, we declare the @mixin directive and name the mixin. In this instance, it's named bs (terser than using box-shadow), but it could have been called bananas (go ahead, I don't judge):

@mixin bs($bs-type) {

Then, immediately after the name, there is an opening parenthesis and what looks like a variable placed inside before a closing parenthesis.

The variable name here is acting as an argument. Think of arguments as optional parameters or settings that can be passed when including a mixin. In this instance, it will typically be either content-box or border-box.

After the opening curly brace is the code the mixin will actually generate, followed by the closing curly brace. Here's the complete mixin again:

@mixin bs($bs-type) {
-webkit-box-sizing: $bs-type;
-moz-box-sizing: $bs-type;
box-sizing: $bs-type;
}

By placing the identical variable used as an argument at various places in the generated code, the mixin knows where to place the value.

I'm concerned that may sound more complex than it actually is, so let's do something silly to illustrate. Let's change the value of the argument being passed in the _layout.scss file to one-that-works:

* {
@include bs(one-that-works);
}

Hopefully, you'll know what that is going to be generated in the CSS:

* {
-webkit-box-sizing: one-that-works;
-moz-box-sizing: one-that-works;
box-sizing: one-that-works;
}

Whatever is passed as an argument to the mixin when it's included gets output into the generated code on compile.

Sass will check for syntax errors on compile (missing semi-colons and the like) and display a suitable error indicating where the error is. While it can syntax check the code, it can't sanity check it. Sass doesn't know that one-that-works isn't a valid value for the boxsizing property so it will happily generate that for you in the CSS.

How to write mixins with defaults

Mixins can also be set with a default value. This means that you can include them without passing an argument and they will generate with a default value. Here's how:

@mixin bs($bs-type: border-box) {
-webkit-box-sizing: $bs-type;
-moz-box-sizing: $bs-type;
box-sizing: $bs-type;
}

Can you see what changed? After the initial variable name, there is a colon, and then the value to be used as the default (border-box in this instance). Now, the mixin can be included like this:

* {
@include bs;
}

And it will still generate this:

* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}

However, if needed, an argument can still be passed to it. For example:

* {
@include bs(content-box);
}

And it would generate this:

* {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}

If a mixin is needed that will be on lots of future projects, it might be preferable to set the mixin up so that it takes a global variable as the default value for an argument. That way, the default value will only be used if a value isn't specified in a global variable elsewhere.

This can be done by using the !default flag. Consider this example:

$defined-bs-type: border-box;
$defined-bs-type: sausages !default;
@mixin bs($bs-type: $defined-bs-type) {
-webkit-box-sizing: $bs-type;
-moz-box-sizing: $bs-type;
box-sizing: $bs-type;
}

First, the variable $defined-bs-type has been assigned the value of border-box. On the next line, the same variable has been set a value of sausages, with the !default flag before the closing semi-colon. The rest of the mixin is as before. Then the mixin is being included in the _layouts.scss file like this:

* {
@include bs;
}

Ordinarily, it might be expected that the value generated on compile would be sausages, as that is the last value assigned to the variable. However, the !default flag is telling Sass to only use this value if a different value hasn't been assigned elsewhere. Because a value has been assigned elsewhere (in the line above), it doesn't use the default. Instead, here's what is generated:

* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}

However, if the first value assignment of the variable is omitted:

$defined-bs-type: sausages !default;
@mixin bs($bs-type: $defined-bs-type) {
-webkit-box-sizing: $bs-type;
-moz-box-sizing: $bs-type;
box-sizing: $bs-type;
}

This is the generated code:

* {
-webkit-box-sizing: sausages;
-moz-box-sizing: sausages;
box-sizing: sausages;
}

Yet this still provides the flexibility to specifically pass an argument when including the mixin:

* {
@include bs(content-box);
}

This passes the defined argument on compile to CSS:

* {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}

The benefit of this approach is that when you have a few mixins built they can be carried from project to project. Then the value that needs assigning can be defined as a variable elsewhere (such as a _variables.scss partial file). Then, altering the value of that variable will affect every instance of the mixin.

Compass has heaps of great mixins of its own that can be used in this manner.

Compass, purveyor of the finest mixins

Want to see just how funky mixins can get? Head over to the Compass project page on GitHub:https://github.com/chriseppstein/compass.Many of the mixins in Compass often include additional geekery such as functions and variable arguments.

. For example, Compass has its own version of the box-sizing mixin itself, with some extra cleverness cooked in: https://github.com/chriseppstein/compass/blob/stable/frameworks/compass/stylesheets/compass/css3/_box-sizing.scss

Or look at the amount of work that has gone into making a beautiful cross-browser mixin for text-shadows (including the spread parameter where supported): https://github.com/chriseppstein/compass/blob/stable/frameworks/compass/stylesheets/compass/css3/_text-shadow.scss

A cautionary note about generated CSS

writing bad Sass will generate bad CSS. Overuse of nesting, @extend, and mixins can lead to bloated code and over-specific selectors. Therefore, apply the same level of common sense when writing Sass as you would when writing plain vanilla CSS (when I say vanilla CSS, I just mean normal CSS with no preprocessor involved in its creation). For example, only make rules as specific as they need to be, don't nest rules too deeply and don't repeat mixins unless necessary.

Getting the hang of writing Sass well from the outset is important. Using Sass and Compass to create CSS files means you will be less inclined to look at the final outputted CSS.

However, even if Sass and Compass don't generate CSS exactly as you would have written it by hand, remember that it is only the browser that actually consumes the compiled CSS (and at that point it should be compressed and illegible to humans anyway). Therefore as no human will actually need to read the generated CSS, it doesn't concern me one bit. As long as the CSS is as efficient for the browser as it can be and my Sass files make sense to others and myself, I'm happy.

CSS file size is a micro optimization

Take a look at the following URL at HTTP Archive. It shows the different types of file that make up a typical webpage:http://httparchive.org/interesting.php#bytesperpage. As you can see, CSS is the smallest content type. Therefore, when tuning CSS for performance, be aware that there are probably far better uses of time and effort in creating a faster webpage. To exemplify; optimizing a single image may well trump any optimizations you make to the entire CSS of a page.

Summary

We've covered a lot of ground in this article:

  • How and when to use nesting

  • How we can use nesting with the parent selector to work more easily with Modernizr

  • How the @extend directive works

  • What placeholder selectors are and how to use them

  • How to use and write mixins to easily produce code on demand

As such, in this article we haven't made much of a dent in the design of http://sassandcompass.com.

However, the skills we've learnt are so useful in everything we're going to write in future; I think that's a fair trade-off.

It might take some time before you find yourself using these features day-to-day. Don't feel like you need to use them right away and at every available opportunity. If all you do for starters is nest and extend the odd style that's still progress, and it will make authoring style sheets easier than before. Once comfortable with that, when feeling feisty in the months to come (and if Compass doesn't already have a feature to solve the problem), maybe take a shot at writing a mixin or two.

Resources for Article :


Further resources on this subject:


Sass and Compass for Designers Produce and maintain cross-browser CSS files easier than ever before with the Sass CSS preprocessor and its companion authoring framework, Compass with this book and ebook
Published: April 2013
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Ben Frain

Ben Frain has been a frontend web designer and developer since 1996. He also works as a technology journalist, contributing regularly to a number of diverse publications on the Mac platform, consumer technology, website design, and the aviation industry.

Before that, he worked as an underrated (and modest) TV actor, having graduated from Salford University with a degree in Media and Performance. He has written four equally underrated (his opinion) screenplays and still harbors the (fading) belief he might sell one. Outside of work he enjoys simple pleasures; playing indoor football whilst his body (and wife) still allows it, and wrestling with his son.

Visit him online at http://www.benfrain.com and follow him on Twitter at twitter.com/benfrain.

Books From Packt


Responsive Web Design with HTML5 and CSS3
Responsive Web Design with HTML5 and CSS3

Dreamweaver CS5.5 Mobile and Web Development with HTML5, CSS3, and jQuery
Dreamweaver CS5.5 Mobile and Web Development with HTML5, CSS3, and jQuery

Instant Migration to HTML5 and CSS3 How-to [Instant]
Instant Migration to HTML5 and CSS3 How-to [Instant]

Designing Next Generation Web Projects with CSS3
Designing Next Generation Web Projects with CSS3

Instant LESS CSS Preprocessor How-to [Instant]
Instant LESS CSS Preprocessor How-to [Instant]

Dreamweaver CS6 Mobile and Web Development with HTML5, CSS3, and jQuery Mobile
Dreamweaver CS6 Mobile and Web Development with HTML5, CSS3, and jQuery Mobile

HTML5 and CSS3 Transition, Transformation and Animation
HTML5 and CSS3 Transition, Transformation and Animation

Instant SASS CSS How-to [Instant]
Instant SASS CSS How-to [Instant]


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
v
s
L
Z
x
z
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software