Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering Responsive Web Design

You're reading from   Mastering Responsive Web Design Push your HTML and CSS skills to the limit and build professional grade, responsive websites

Arrow left icon
Product type Paperback
Published in Aug 2015
Publisher
ISBN-13 9781783550234
Length 334 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Ricardo Zea Ricardo Zea
Author Profile Icon Ricardo Zea
Ricardo Zea
Arrow right icon
View More author details
Toc

Table of Contents (10) Chapters Close

Preface 1. Harness the Power of Sass for Responsive Web Design FREE CHAPTER 2. Marking Our Content with HTML5 3. Mobile-first or Desktop-first? 4. CSS Grids, CSS Frameworks, UI Kits, and Flexbox for RWD 5. Designing Small UIs Driven by Large Finger 6. Working with Images and Videos in Responsive Web Design 7. Meaningful Typography for Responsive Web Design 8. Responsive E-mails Index

The basic concepts of Sass for RWD

For starters, Sass is a programming/scripting language. I bet you didn't see that one coming. Yes, it's a programming/scripting language focused on increasing the efficiency of web designers and web developers creating CSS. In this book, we're going to focus on the simple parts of Sass that can help us write CSS more efficiently, and more importantly, we'll have fun doing it.

Implementing RWD is time consuming: coding, testing, creating assets, browser troubleshooting, and then testing some more. The more we streamline our coding processes and the less repetitive work we do, the more efficient we become and the more value we add to a project, our team, the business and eventually, our users. Sass is going to do just that—help us streamline the coding of CSS.

Let's discuss the following concepts first:

  • Sass or SCSS
  • Variables
  • Mixins
  • Arguments
  • Nesting
  • Partial files
  • @import
  • Source maps
  • Sass comments

Sass or SCSS

There are two ways we can write Sass-style CSS: the Sass syntax and the SCSS syntax.

Tip

Make no mistake; Sass is written with capital S and the rest with lower case and SCSS is all uppercase.

The Sass syntax

The Sass syntax, also known as the indented syntax, was the initial and only way to write Sass. But it looked a bit too different than regular CSS, making the learning curve steeper than it really needed to be.

This syntax didn't use any braces or semicolons. In some cases, instead of colons it used the equals sign. Unlike SCSS, indentation was very strict and mandatory. Many developers weren't too fond of these aspects of the Sass syntax.

Here's a basic example:

.selector-a
    float: left

        .selector-b
            background: orange

This compiles to the following code:

.selector-a {
    float: left;
}

.selector-a, .selector-b {
    background: orange;
}

The SCSS syntax

When SCSS was introduced with the release of version 3 of Sass, things got a lot easier for those of us who are not programmers but want to harness the power of Sass.

Note

SCSS stands for Sassy CSS.

If you already write CSS, you already write SCSS. All the things we already used while writing CSS are the same things we'll use when writing Sass with the SCSS syntax. So, the learning curve is initially nonexistent.

Then, you realize that you can also use bits of Sass that enhance what you already know, making learning Sass an awesome experience because you can get good at it quite fast. It honestly feels like you're gaining superpowers. I'm not kidding.

Here's the same example we saw before with the SCSS syntax:

.selector-a {
    float: left;
}

.selector-a, .selector-b {
    background: orange;
}

Wait a second! That's CSS! Yes, and it's also SCSS.

Let's see that same example in a different way using the SCSS syntax as well:

.selector- {
    &a {
        float: left;
     }
    &a, &b {
        background: orange;
    }
}

The ampersand symbol, &, in SCSS allows us to add the name of the parent selector to the nested selectors without having to type the whole thing, keeping us on the DRY side of things.

Note

DRY means Don't Repeat Yourself.

Both SCSS examples compile to the following code:

.selector-a {
    float: left;
}

.selector-a, .selector-b {
    background: orange;
}

Sass variables

Let's understand a few things first:

  • A variable is simply a way to store a value for later use
  • This value is usually associated with a simple user-friendly word
  • Sass variables have to start with a dollar sign ($) symbol
  • The great benefit of variables is that if we need to change the value, we would make the change in a single place rather than finding and replacing the value across the entire document

Tip

When listing more than one variable, there should be a semicolon symbol (;) at the end of each variable. If there's only one variable, there's no need for the semicolon. However, this is a good practice to always end variables with a semicolon even if it's just one.

Here's an example of a Sass variable:

$brandBlue: #416e8e;

Tip

I recommend you name variables using the camelCase style in order to differentiate them from dash-separated class names and CSS properties. This is very helpful when scanning the SCSS document, because the variables are easier to detect.

As we can see, we're storing a color value. The name we're using, brandBlue, is certainly more user friendly than #416e8e. Also, we're using the dollar sign symbol ($) and ending it with a semicolon (;) for good measure if/when we need to add more variables. Now, if we need to change the value later, all we'd need to do is change it in one location.

The variables should always be included at the top of your SCSS file so Sass knows where to go when using them. You can also include them via a partial file, but we'll talk about what partial files are later on in the chapter.

Here's an example of how to use an SCSS variable:

$brandBlue: #416e8e;
body {
    background: $brandBlue;
}

The preceding code compiles to the following:

body {
   background: #416e8e;
}

Sass mixins

Mixins are one of the most powerful features of Sass. Mixins are a group of CSS declarations (a property and value) that are stored for later use, just like a variable. So instead of typing all those CSS declarations over and over again, we just type the mixin's name.

A few things to consider about Sass mixins are as follows:

  • They start with the @mixin directive
  • A mixin is called with the @include directive
  • We can store any amount of CSS/SCSS data in a mixin
  • Try to use arguments when creating a mixin so it's more scalable

Tip

We haven't seen what arguments are yet, but it's important to mention the word now so you can start getting familiar with different Sass terminology. We'll cover Sass arguments in the next section.

Let see an example of a mixin:

$brandBlue: #416e8e;
$supportGray: #ccc;
@mixin genericContainer {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: $supportGray;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

We call a mixin in our SCSS file as follows:

.selector-a {
    @include genericContainer;
}

When compiled, it looks like this in the CSS:

.selector-a {
    padding: 10px;
    border: #416e8e 1px solid;
    background: #cccccc;
    box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
}

Let's recap what we did in the mixin.

We used the @mixin directive:

$brandBlue: #416e8e;
$supportGray: #ccc;
@mixin genericContainer {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: $supportGray;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

We used the camelCase naming convention to differentiate the mixin's name from dash-separated class names and CSS properties:

$brandBlue: #416e8e;$supportGray: #ccc;
@mixin genericContainer {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: $supportGray;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

We used Sass variables within the mixin:

$brandBlue: #416e8e;$supportGray: #ccc;
@mixin genericContainer {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: $supportGray;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

We used the keyword black in the box-shadow color property instead of using the hex #000 or rgb (0, 0, 0) values:

$brandBlue: #416e8e;$supportGray: #ccc;
@mixin genericContainer {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: $supportGray;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

For that matter, we could've also used our variable name like this:

$brandBlue: #416e8e;$supportGray: #ccc;
@mixin genericContainer {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: $supportGray;
    box-shadow: 1px 1px 1px rgba($brandBlue, .3);
}

We also omitted the 0 in the alpha value (.3). This is actually not a Sass feature; this is a CSS feature:

$brandBlue: #416e8e;$supportGray: #ccc;
@mixin genericContainer {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: $supportGray;
    box-shadow: 1px 1px 1px rgba($brandBlue, .3);
}

Tip

On decimal values that start with a zero, the zero can be omitted.

Again, the preceding mixin compiles to the following CSS:

.selector-a {
    padding: 10px;
    border: #416e8e 1px solid;
    background: #cccccc;
    box-shadow: 1px 1px 1px rgba(65, 110, 142, 0.3);
}

Sass arguments

In our first mixin example, we didn't have any arguments. This is really not ideal because it doesn't allow us to use different values in the same properties. In reality, not using any arguments in a mixin isn't really any different than typing the same properties and values every time we need them. We are not really doing any DRY.

Arguments are the part(s) of a mixin in which you can put your own values depending on your needs. Arguments make a mixin worth creating.

In the mixin example mentioned earlier, let's add an argument:

$brandBlue: #416e8e;$supportGray: #ccc;
@mixin genericContainer($padding) {
    padding: $padding;
    border: $brandBlue 1px solid;
    background: $supportGray;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

The argument for padding allows us to set any value we want. We are not forced to have the padding as 10px every time.

This is how we set the value of the argument:

.selector-a {
    @include genericContainer(10px);
}

This compiles to the following:

.selector-a {
    padding: 10px;
    border: #416e8e 1px solid;
    background: #cccccc;
    box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
}

However, there's a potential problem with the argument; if we don't set a value for the padding, we're going to get an error when compiling.

So the solution here is to set a default value; if we don't define a value for padding for some reason, Sass is going to take that default value and use it when compiling without throwing an error.

Here's how we set a default value of an argument:

$brandBlue: #416e8e;$supportGray: #ccc;
@mixin genericContainer($padding: 8px) {
    padding: $padding;
    border: $brandBlue 1px solid;
    background: $supportGray;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

This is how we call the mixin, without declaring any padding value:

.selector-a {
    @include genericContainer;
}

The compiled CSS is as follows:

.selector-a {
    padding: 8px;
    border: #416e8e 1px solid;
    background: #cccccc;
    box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
}

How to use several arguments in the same mixin

Building on the preceding mixin, let's add a few more arguments to make it more robust and scalable:

@mixin genericContainer ($padding, $bdColor, $bgColor, $boxShdColor) {
    padding: $padding;
    border: $bdColor 1px solid;
    background: $bgColor;
    box-shadow: 1px 1px 1px $boxShdColor;
}

This is how we declare the arguments when including our mixin:

.selector-a {
    @include genericContainer(2%, $brandBlue, #ccc, black);
}

We can use the same mixin and obtain different styles without having to type all the properties repeatedly.

The preceding mixin and its arguments compile to the following code:

.selector-a {
    padding: 2%;
    border: #416e8e 1px solid;
    background: #cccccc;
    box-shadow: 1px 1px 1px #000000;
}

Setting default values in multiple arguments

Sometimes, we need to define some default values in case we only need to declare one or a few arguments. In other words, by declaring default values in our arguments, we'll always be sure that a value is created and we don't get any errors when compiling our SCSS file.

Here's how we set default values in our arguments:

@mixin genericContainer ($padding: 5px, $bdColor: orange, $bgColor: #999, $boxShdColor: #333) {
    padding: $padding;
    border: $bdColor 1px solid;
    background: $bgColor;
    box-shadow: 1px 1px 1px $boxShdColor;
}

If we need to declare only the first property, padding, we can do this:

.selector-a {
    @include genericContainer(25px);
}

This compiles to the following:

.selector-a {
    padding: 25px;
    border: orange 1px solid;
    background: #999999;
    box-shadow: 1px 1px 1px #333333;
}

Tip

Some Sass compilers will turn a shorthand color hex value, #333, to a longhand value, #333333.

As we can see, only the first argument, padding, was declared. Other arguments used their default values and compiled successfully.

But let's say we still want to declare only one argument but not the padding, which is the first in the list of arguments. Let's say we want to declare the background color!

In this case, we need to declare the value by typing the name of the variable:

.selector-a { @include genericContainer($bgColor: $brandBlue); }

Tip

If we want to declare only a single argument that is different from the first one, we need to declare the whole argument name.

There are more advanced ways to declare arguments, but this is sufficient for the scope of this book.

Nesting in Sass

Nesting in Sass is a perfect way to make our SCSS more readable. Just like in HTML where tags get nested based on their parent elements, Sass uses exactly the same structure.

Here's an example of two-level selector nesting for a navigation bar:

$brandBlue: #416e8e;nav {
    ul {
        display: flex;
        margin: 0;
        padding: 0;
        list-style: none;
    }

    li {
        margin: 5px;
        background: #000;
    }
    a {
        display: block;
        padding: 5px 15px;
        text-decoration: none;
        color: $brandBlue;
    }
}

Tip

Beware of deep nesting! Best practices recommend nesting a maximum of three levels. Otherwise, we will run into selector specificity and maintainability issues down the road.

Did you notice that I used the $brandBlue color variable again? The preceding SCSS for the navigation bar compiles to the following CSS:

nav ul {
    display: flex;
    margin: 0;
    padding: 0;
    list-style: none;
}
nav li {
    margin: 5px;
    background: #000;
}
nav a {
    display: block;
    padding: 5px 15px;
    text-decoration: none;
    color: #416e8e;
}

Partial files (partials) in Sass

Partial files are SCSS files we create to house SCSS snippets. Partials allow us to modularize our files, for example, _variables.scss. Partials start with the underscore symbol (_) and end with the extension .scss. The underscore symbol tells the compiler that this file and its contents do not need to be compiled into a separate CSS file.

Partials are called using the @import directive, just like it is done in CSS. The main differences are that there's no need to specify the underscore symbol and the file extension.

Let's create a partial file and put these color variables in it. We're going to call this partial file, _variables.scss. The variables (snippets) in the _variables.scss partial are as follows:

$brandBlue: #416e8e;
$brandRed: #c03;
$brandYellow: #c90;

Let's then say that our main SCSS file is named styles.scss. We now have two files: styles.scss and _variables.scss.

Tip

The main SCSS file of a project does not start with an underscore symbol.

We call _variables.scss into styles.scss using the @import directive:

@import "variables";

Notice that the underscore symbol and file extension are not needed when referencing a partial; they can be omitted. However, if you want to add them, that's fine too. Omitting them keeps the code cleaner.

The Sass extend/inherit feature

Many professionals say extend or inherit is one of the most useful features of Sass. Others actually recommend staying away from it. This book's recommendation is: just use Sass as much as possible and experiment with different features so you can create your own opinions. When you have enough experience, you can decide which side you want to join.

Extending in Sass means that we can use a selector's properties in another selector without having to type all those properties again. This is called inheriting. We use the @extend directive for this.

For example, consider the following selector:

$brandBlue: #416e8e; .generic-container {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: #ccc;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

Suppose we want to inherit all the properties of this selector on a different selector. We're also going to modify one property, since they are almost identical, using the @extend directive to reuse the styles of the first selector in the second one:

.box-customer-service {
    @extend .generic-container;
    padding: 25px;
}

This compiles to the following:

.generic-container, .box-customer-service {
    padding: 10px;
    border: #416e8e 1px solid;
    background: #cccccc;
    box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
}

.box-customer-service {
    padding: 25px;
}

Notice that .generic-container and .box-customer-service are in the same rule; this means that .box-customer-service is inheriting all the properties and values of .generic-container. Then, there's a separate rule for .box-customer-service, where only the padding property is declared since it's the only difference between the two containers.

Sass comments

Since we know that a CSS document is a valid SCSS document, using the CSS comment syntax is also valid:

/* This is a traditional CSS comment */

In Sass, there's another way. We can comment using double slashes (//) at the beginning:

// This is a Sass-style comment

The difference between the two styles is that the traditional CSS comment using /**/ syntax gets added to the compiled file, whereas the comments with Sass using // does not get added.

The comments with the Sass syntax are very helpful to document our SCSS files without having to worry about all those comments getting compiled and bloating our final CSS file. The Sass comment in the following example doesn't get compiled:

$brandBlue: #416e8e; //Mixin for generic container across the app
.generic-container {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: #ccc;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

However, the traditional CSS comment does get compiled:

$brandBlue: #416e8e;
/* Mixin for generic container across the app */
.generic-container {
    padding: 10px;
    border: $brandBlue 1px solid;
    background: #ccc;
    box-shadow: 1px 1px 1px rgba(black, .3);
}

Tip

Now, depending on the options set on the compiler, the final CSS can be minimized. Thus, the traditional CSS comments will get stripped out in order to optimize file size.

Vendor prefixing

Vendor prefixing is basically adding a specific tag to a CSS3 property or value that hasn't been widely used by the web development industry and communities or finalized and included in the CSS3 specification.

The vendor part refers to the abbreviation tags that represent the names of the companies that create the browsers: Mozilla, Opera, and Microsoft.

There's one exception though, Apple. Although Apple created Safari, the vendor prefix is based on the layout engine of the browser rather than the company name.

  • Mozilla: -moz-
  • Opera: -o-
  • Microsoft: -ms-
  • Webkit (Apple): -webkit-

The prefix part refers to the description of adding the vendor tags before the CSS property or CSS value. Each vendor prefix only works in its own browser, so for the preceding list, here are the browsers they belong to:

  • Mozilla: This prefix -moz- works in Firefox
  • Opera: This prefix -o- works in Opera
  • Microsoft: This prefix -ms- works in Internet Explorer
  • Webkit (Apple): This prefix -webkit- works in Safari

If you're wondering where Google Chrome is in all this, there's a simple explanation.

Although Google created Chrome, there is no specific prefix for Chrome. In the beginning, Chrome was using the same layout engine as Safari: Webkit. Thus, the Webkit-based prefixes not only affected Safari, but also affected Chrome and other Chromium-based products.

However, Google Chrome no longer uses Webkit; it now uses its own layout engine called Blink. However, in order to maintain compatibility and avoid fragmenting the Web even more, Chrome still supports the -webkit- prefix.

Opera had a similar story where they had their own layout engine, Presto, and then switched to Webkit. It now uses Blink. There are other browser vendors in addition to the ones mentioned before and they use their own prefixes as well, such as the Konqueror browser with its prefix, -k-.

Here's an example of a vendor-prefixed CSS property:

-moz-box-sizing: border-box;

And, here's an example of a prefixed CSS value:

background-image: -webkit-linear-gradient(red, blue);

The order of vendor prefixing

The reality is that the order in which we can list the vendor prefixes doesn't matter; what matters is that we always place the nonvendor prefixed version at the end.

Staying with the example of the linear-gradient property, we should do it like this:

*, *:before, *:after {
    background-image: -webkit-linear-gradient(red, blue);
    background-image: -moz-linear-gradient(red, blue);
    background-image: -ms-linear-gradient(red, blue);
    background-image: -o-linear-gradient(red, blue);
    background-image: linear-gradient(red, blue);
}

Tip

You can also use background: linear-gradient(red, blue); if you like.

The reason the nonvendor-prefixed declaration should always be last is, if the browser vendor modifies its prefix or drops the support for it, the last line will always override anything above it because of the cascade. This makes the whole CSS rule more future-proof. Plus, we won't have to rewrite our style sheets every time a vendor changes something.

Now, many CSS3 properties and values do not need all vendor prefixes. Most of the time, they only need a couple of vendor prefixes, and other times the nonvendor-prefixed - properties or values is enough.

But how do we know which CSS3 properties and values can be prefixed or not so that we can create styles that are supported by certain legacy browsers without having to memorize so much information?

The answer is automating the vendor prefixing process.

Automating vendor prefixing

There are several problems that come with vendor prefixing, and we can't get away from these if we want some of our CSS3 properties to work in current browsers and/or certain legacy ones. Vendor prefixing is dirty work and we don't have to do it.

So how do we automate the process of vendor prefixing while keeping our work as DRY as possible? There are several ways.

Using Compass

Compass is a framework for Sass that helps us write CSS more efficiently. Compass has a massive library of mixins that we can use to leverage dealing with vendor prefixes.

The installation of Compass is outside the scope of this book, so we're going to focus on the basic usage to deal with vendor prefixes and will assume that it is already installed on your machines. Refer to the Compass site for detailed instructions on how to install it (http://compass-style.org/).

Once we have Compass installed, we need to import the specific module that contains the mixins we need.

Staying with the linear gradient example we used before, let's import Compass' images module into our SCSS file. Place this at the top of your main SCSS file:

@import "compass/css3/images";

Then, we can use the corresponding mixin:

header {
    @include background-image(linear-gradient(red, blue));
}

This will compile to the following:

header {
    background-image: url('data:image/svg+xml;base64,…');
    background-size: 100%;
    background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, red), color-stop(100%, blue));
    background-image: -moz-linear-gradient(red, blue);
    background-image: -webkit-linear-gradient(red, blue);
    background-image: linear-gradient(red, blue);
}

There are a few new things here.

The first declaration uses a base64 embedded SVG file. This is because legacy IEs and old versions of Opera have issues rendering gradients so an SVG is their fallback. Dealing with these types of issues is completely unnecessary by today's standards:

header {
    background-image: url('data:image/svg+xml;base64,…');
    background-size: 100%;
    background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, red), color-stop(100%, blue));
    background-image: -moz-linear-gradient(red, blue);
    background-image: -webkit-linear-gradient(red, blue);
    background-image: linear-gradient(red, blue);
}

The background-size: 100%; parameter is used so that the embedded SVG covers the whole container. Again, dealing with something like this is just a waste of time. Moreover, our code keeps getting bloated trying to support old technology. Consider the next block of code:

header {
    background-image: url('data:image/svg+xml;base64,…');
    background-size: 100%;
    background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, red), color-stop(100%, blue));
    background-image: -moz-linear-gradient(red, blue);
    background-image: -webkit-linear-gradient(red, blue);
    background-image: linear-gradient(red, blue);
}

The third declaration is the old CSS linear gradient syntax that was supported only by Webkit browsers; more unnecessary code bloating in our file:

header {
    background-image: url('data:image/svg+xml;base64,…');
    background-size: 100%;
    background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, red), color-stop(100%, blue));
    background-image: -moz-linear-gradient(red, blue);
    background-image: -webkit-linear-gradient(red, blue);
    background-image: linear-gradient(red, blue);
}

The fourth and fifth declarations are basically for old Firefox, Chrome, and Safari versions:

header {
    background-image: url('data:image/svg+xml;base64,…');
    background-size: 100%;
    background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, red), color-stop(100%, blue));
    background-image: -moz-linear-gradient(red, blue);
    background-image: -webkit-linear-gradient(red, blue);
    background-image: linear-gradient(red, blue);
}

The last declaration is the proposed syntax without any vendor prefixes:

header {
    background-image: url('data:image/svg+xml;base64,…');
    background-size: 100%;
    background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, red), color-stop(100%, blue));
    background-image: -moz-linear-gradient(red, blue);
    background-image: -webkit-linear-gradient(red, blue);
    background-image: linear-gradient(red, blue);
}

As we can see, Compass is a very handy tool and it allows us to customize the output. However, this may end up being more work than necessary.

A few things to consider before concluding whether Compass is the best solution for us:

  • Compass needs to be installed. This is usually done via the command line.
  • Once Compass is installed, we don't have to use the command line anymore to use its mixins.
  • Compass has a massive library of mixins that can help deal with vendor prefixing and many other things.
  • Each time we need to work with a specific CSS3 property or value, we have to import the corresponding module in our main SCSS file with the @import directive. This means that we have to spend a lot of time finding the modules we need and learn to use them.
  • The learning curve of using Compass is medium, we need to be a bit knowledgeable in other technical aspects to get to use Compass even at its most basic.
  • Compass has great documentation and is a project in constant development.
  • There's a similar, well-known mixin library called Bourbon: http://bourbon.io/.

Using -prefix-free

-prefix-free is a JavaScript file created by Lea Verou. When the script is called by the browser, it detects it and then adds that browser's specific prefixes to the CSS. The -prefix-free file is intelligent enough to determine which prefixes are needed and only inject those.

Using -prefix-free is simple. Just add a call the JavaScript file. As per Lea Verou's recommendation, it's best to include this script after the style sheets in order to reduce the Flash of Unstyled Content (FOUC).

You can visit the -prefix-free project at http://leaverou.github.io/prefixfree/.

Since our HTML is so short, we can follow the tip mentioned before:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Page Title</title>
    <link href="css/styles.css" rel="stylesheet">
    <script src="js/prefixfree.min.js"></script>
</head>
<body>
    Site content...
</body>
</html>

It's certainly tempting to use this method since calling a mere JavaScript file to deal with automating vendor prefixes sounds like the best idea ever.

Let's see a short list of things to consider before deciding to use -prefix-free:

  • It's incredibly easy to use.
  • It's an additional HTTP request. The fewer requests our site/page(s) have the faster they are, hence the better UX we provide our users. It's also beneficial for SEO.
  • It's an extra file to manage. Yes, once we upload the JavaScript file we may not need to go back to it—unless we're updating it, which means we need to run extensive tests locally so that we don't break anything in production.
  • It puts a bit more strain on the user's browsers to do the heavy lifting since everything happens in the browser.
  • It doesn't work in files being called using the @import directive. This could also be seen as a good thing because if we're using @import to import files, we have a different and even bigger problem in our hands.
  • If we're serving style sheets from a different domain than our main site, -prefix-free won't work on those external CSS files.
  • Chrome and Opera have issues with allowing -prefix-free to work locally. Although this is easy to fix, it just adds another layer of complexity to our workflow.
  • If there are inline styles, some unprefixed CSS values and properties won't work in IE.

With this list, we are now in a better position to make a more informed decision that will benefit the project, ourselves and our users.

Using Autoprefixer

Autoprefixer is a CSS postprocessor that uses the CanIUse.com database to append vendor prefixes to an already compiled CSS file.

The term postprocessor means that it processes the CSS after (post) it has been created. In other words, if we have an SCSS file called styles.scss, this file gets compiled into styles.css after we save it. At that moment, Autoprefixer takes that generated styles.css file, opens it, adds all the necessary vendor prefixes to each property and value, saves the file, and closes it. In addition, you can configure it to create a new separate file as well. Once this is done, we can use this file in our website/app.

The major advantage that this method has over any other automated vendor prefixing method is that it uses the CanIUse.com database; this means that as soon as a browser vendor no longer requires its prefix for a CSS property or value, all we need to do is run our CSS files through Autoprefixer and it will be up to date in seconds.

The major disadvantage of Autoprefixer is that it has so many ways to use it that it could be a bit overwhelming for some. To name a few, we can use it via the command line but we'd need to have Node.js installed first:

npm install --global autoprefixer
autoprefixer *.css

We can also use Autoprefixer with Compass, but we need to have Ruby installed first:

gem install autoprefixer-rails

We can use it with CodeKit on Mac and with Prepros or Koala App on Windows/Mac/Linux. We can also install plugins for Sublime Text, Brackets, or Atom Editor. There are Grunt and Gulp plugins as well.

Let's see a short list of things to consider before deciding to use Autoprefixer:

  • The fact that it uses the CanIUse.com database is by far the best feature and advantage over any other automated vendor prefixing application, because we can always be sure that our CSS files have the latest prefixes, or none if the browser vendor has dropped any of them.
  • It can be integrated into many applications.
  • It can be a bit daunting to install for new web designers or developers.
  • Autoprefixer comes preinstalled in other applications, so all we need to do is run those applications and we're automatically using Autoprefixer without having to set anything up.

Autoprefixer can be downloaded from https://github.com/postcss/autoprefixer.

Using Pleeease

Yes, it's Pleeease with three e. Pleeease is also a CSS postprocessor like Autoprefixer and it also depends on having Node.js installed. It only runs via the command line, but it's actually quite simple. Pleeease uses Autoprefixer, which means that it uses the CanIUse.com database as well to define which CSS properties and/or values need prefixing.

Once Pleeease is installed, we need to create a configuration file (a JSON file) in which the most important thing we need to define is the source CSS file and the destination CSS file:

{
    "in": "style.css",
    "out": "styles.fixed.css"
}

Once we have that configuration file set, we run this in the command line:

pleeease compile

Pleeease takes the style.css file, adds all necessary vendor prefixes, and creates styles.fixed.css, which is the file we use in production.

There are other important things that Pleeease does at this point:

  • Compiles the same media queries into one @media block
  • Inlines @import style sheets (this is great because we end up with one single CSS file for production)
  • Minifies/compresses the final file

If you're comfortable using the command line and JSON files, Pleeease can be a very useful part of your arsenal. If you prefer to stay away from the command line, that's fine too; there are other friendlier ways to automate vendor prefixing.

Here are a few things to consider before deciding if Pleeease is the way to go to automate vendor prefixing:

  • It requires the use of the command line to install and use, but the commands are quite simple.
  • It uses a JSON file to configure its settings.
  • It uses Autoprefixer, which means it uses the CanIUse.com database as well. This makes it incredibly powerful when it comes to knowing which properties and/or values need or don't need to be prefixed.
  • It makes several other improvements to the final CSS file, such as packing the same media queries in a single @media rule, minifying the result, and so on.
  • It can be integrated with the Grunt, Gulp, Brunch, and Node.js workflows.

You can download Pleeease from http://pleeease.io/.

Using Emmet

Emmet allows us to write CSS and HTML faster. It's a plugin for text editors such as Sublime Text, Coda, TextMate, and even Dreamweaver.

Emmet also helps us with vendor prefixing our CSS3 properties and values, which is what we're going to focus on in the following examples.

Tip

Emmet used to be called Zen Coding.

Once the Emmet plugin is installed in our favorite text editor, we type this in our SCSS file:

.selector-a {
    -trf
}

Tip

-trf is the abbreviation of the CSS3 property transform.

Then we press Tab on our keyboard and the code automatically gets changed to this:

.selector-a {
    -webkit-transform:;
    -ms-transform:;
    -o-transform:;
    transform:;
}

All we need to do to add vendor prefixes is start our abbreviation with a dash (-). This tells Emmet that it needs to add the necessary vendor prefixes when hitting the key Tab.

Tip

The transform values were not defined in the previous example because we want to show the result from using Emmet. Obviously, we'd have to add those values in the end.

Here are a few things to consider before deciding to use Emmet to automate vendor prefixing:

  • It's up to us to define what gets prefixed and what doesn't, so we may end up prefixing properties and values that no longer need to be prefixed. Thus, we end up bloating our CSS files.
  • If we forget to add a dash at the beginning of a property/value, it won't be prefixed and maybe that property/value does need prefixed. Thus, we'll spend more time troubleshooting.
  • Emmet works with the most popular text editors out there, so chances are we'll be able to use it.
  • The learning curve to use Emmet is incredibly low.
  • Emmet does not depend on the use of the command line.
  • Emmet has great documentation and it's in constant development.

You can download Emmet from http://emmet.io/.

Using a third-party application

As we have seen, the previous methods for automating vendor prefixing are all over the place, from methods that are used via the command line and methods that make you find a specific module to import before being able to use to JavaScript solutions.

The most important of all the features mentioned is that Autoprefixer uses the CanIUse.com database. This is pretty much what we want to use, since all we need to do is write the CSS3 properties and values and forget about vendor prefixing altogether, leaving it to Autoprefixer and CanIUse.com to add them for us.

Fortunately, there are third-party applications out there that already come with Autoprefixer installed. This means we don't have to set anything via the command line, or install a plugin, or anything like that. Just install the app, activate the Autoprefixer checkbox, and off we go!

We mentioned several applications before: CodeKit, Prepros, and the Koala app. They all do basically the same things, but they excel in two things:

  • They can watch our SCSS files and compile them for us.
  • They can automatically add vendor prefixes via Autoprefixer.

These two features have a huge impact on our workflow, allowing us to focus our energies on the important stuff, such as RWD and a better user experience.

However, there are a few things to consider before deciding if a third-party application is the best solution for vendor prefixing:

  • Prepros and CodeKit are paid apps. Koala is free but supporting the author with a small donation shows appreciation for his work. However, they are not expensive by any means; the benefits are worth tens of times over when we compile a file for the first time.
  • They are extremely easy to set up.
  • They have great documentation, communities and are in constant development by the authors.
  • For many non-frontend developers who work with CSS and HTML, these applications allow them to focus on other important things such as user experience, design, usability, and SEO—without worrying about JSON files, command line, plugins, and so on.

The recommended vendor prefixing method

This book recommends that you use CodeKit, Prepros, or Koala apps to deal with vendor prefixes. These applications not only compile the SCSS files, but also automatically run them through Autoprefixer when saving those SCSS files.

So let's take a look at Prepros, which can run on the most popular operating systems such as Windows, Linux, and Mac.

Using a third-party program to compile

Using the command line to compile our SCSS files is really not that difficult:

--sass watch scss:css

That's all we need to do in the command line to have Sass watch over the SCSS files in the /scss folder and compile them into the /css folder. It really is that simple.

The problem with the previous situation is that we need to run this command every single time we have to work on a different project. Although we can automate this in many different ways, some find the use of the command line either daunting or just unnecessary.

The Prepros app

Prepros is a tool for web designers and developers that deals with many parts of a regular workflow: compiling, CSS prefixing, live refresh, JavaScript concatenation, file minification, optimizing images, browser testing synchronization, source maps creation for compiled files, built-in server, FTP, and so on.

For the scope of this book, we're going to focus on how it can help us compile our SCSS files while adding vendor prefixes automatically.

You can download it from https://prepros.io/. Prepros is a paid application. However, spending $29 is not going to break the bank. I assure you that right after the first compilation, this app will have paid itself.

There is also a way to use Prepros for free and enjoy all the features of the app. However, this comes at the expense of having to keep closing the buy the app pop-up window about every 5 minutes.

This is the current welcome screen of Prepros (it may have changed by now):

The Prepros app

Remember the steps in the installation of Sass where we created a /Demo folder and created two subfolders, /scss and /css, within it? We are going to drag and drop the /Demo folder onto the Prepros interface:

The Prepros app

A sad face appears, letting us know that the project is empty. This is true since we haven't added any files to the /scss folder:

The Prepros app

So, let's create a .scss file in the /scss folder:

The Prepros app

Prepros will automatically detect the new styles.scss file and compile it to create the styles.css file, which is saved in the /css folder.

The Prepros app

Clicking on the styles.scss file will bring out the file's default settings:

The Prepros app

Let's modify some of these settings so Prepros can automatically perform the following operations:

  • Add vendor prefixes.
  • Create source maps.
  • Not compress our compiled CSS (at least yet).

Tip

The source map is a file with the .map extension that gets generated together with our CSS file. This map file contains the necessary information that links each line of our CSS file to their corresponding line in our SCSS files and partials. This is crucial when we need to inspect the styles of an element via the DevTools of any modern web browser.

In the OUTPUT STYLE section, we're going to leave the setting as Expanded.

The Prepros app

The differences between the four styles of output are simple:

Expanded output

This is the traditional CSS styling where each selector, property, and value is in a separate line:

header {
    background: blue;
}
header .logo {
    float: left;
}
.container {
    float: right;
}

Nested output

You can see that the second rule is indented, which means it belongs to the header selector:

header {
    background: blue;
}
    header .logo {
       float: left;
  }
.container {
    float: right;
}

Compact output

All rules reside in a single line, as shown here:

header { background: blue; }
header .logo { float: left; }
.container { float: right; }

Compressed output

This is the minified version, which is the version we should use in production:

header{background:blue;}header .logo{float:left;}.container{float:right;}

That's it. We now leave Prepros running. It will add all vendor prefixes and compile the SCSS files every time we save it. Let's see this in action.

Add some CSS and let the Prepros app do the rest!

Every time we hit Save, Prepros will show either one of the following dialog boxes at the bottom-right corner of our screen.

Success will give us the following output:

Add some CSS and let the Prepros app do the rest!

Error will give us the following output:

Add some CSS and let the Prepros app do the rest!

Let's take our styles.scss file and let's add a simple CSS rule that requires some vendor prefixing.

Add some CSS and let the Prepros app do the rest!

When we save the styles.scss file, Prepros shows the green/success dialog box and compiles our SCSS file to styles.css.

This is what the compiled file looks like with all the prefixes added automatically:

Add some CSS and let the Prepros app do the rest!

Defining how many legacy browser versions to support for prefixing

As browsers evolve, CSS3 properties and values are standardized and less of them require vendor prefixing. Our CSS files should reflect that so we don't fill our style sheets with unnecessary prefixes.

Prepros allows us to define how many legacy browser versions we want to support when applying prefixes. The steps are as follows:

  1. Click on the MORE OPTIONS menu at the top:
    Defining how many legacy browser versions to support for prefixing
  2. Click on Project Options from the drop-down menu:
    Defining how many legacy browser versions to support for prefixing
  3. Click on the CSS menu option:
    Defining how many legacy browser versions to support for prefixing
  4. Scroll all the way to the bottom and type the number 2 in the AutoPrefixer field:
    Defining how many legacy browser versions to support for prefixing
  5. Once this is done, save the styles.scss file. We'll see that the CSS3 linear gradient property doesn't really need to be prefixed after Prepros compiles the CSS file:
    Defining how many legacy browser versions to support for prefixing

Tip

If you are not able to see the linear gradient property prefixed in the beginning, try changing the value to something very high, such as 40 so that it reads last 40 versions. Save your SCSS document and check your CSS file again.

That's all there is to it.

One compiler only

One very important note before we continue. So far, we've talked about using the command line via the --watch flag and using Prepros to compile our SCSS files. Note that only one compiler needs to run at any given time. Having both the CMD and Prepros compiling the same SCSS file is not necessary.

Sass mixins to house our media queries

There are many ways to create a Sass mixin to house media queries: mixins with variables only, mixins with the No Queries fallback for older browsers that don't support media queries, and plugins (for Compass) such as Breakpoint. There are other techniques too, such as Named Media Queries. Another technique is a simple three-line mixin that will work for anything we want.

They're all fine and very powerful. However, for the scope of this book, we're going to focus on two simple methods that will allow us to be efficient, keep things simple, and harness the power of mixins.

All that you have learned about Sass so far, especially the part about mixins, culminates in the creation of a partial file that will house our media queries for RWD.

Remember that partial files are SCSS files we create to house SCSS snippets. Their file name starts with an underscore symbol and ends with the .scss extension.

Media queries mixin methods

There are as many methods to name media queries and breakpoints as there are web designers and frontend developers. Everyone has their own way and style.

Regardless of the method you use, the important thing is to start using a Sass mixin to automate this process. As we build sites or apps and become better web designers / frontend developers, we'll find that other solutions may work better.

There are several ways to name your media queries mixins:

  • Let the content define the breakpoints. In other words, when you resize your browser window during testing and you see that the content breaks or doesn't display in an ideal, legible way—bam! create a breakpoint (this is the recommended method).
  • Name media queries using abstract names such as small, medium, and large, or s, m, and l.
  • Use device-specific names (I do not recommend this method).

In this book we're going to focus only on the first and second methods mentioned in preceding list.

Let the content define the breakpoints

Since we don't know where our content is going to break and we need an initial mixin that we can add values to as we build our responsive site/app, we're going to start with a few known, width-specific values. Understand that these values may very well change and many other values will be added to this mixin.

We're going to name this file _mediaqueries.scss. The media queries mixin looks like this:

//Mobile-first
@mixin minw($point) {
    @if $point == 320 {
      @media (min-width:  20em) { @content; }
    }
    @else if $point == 640 {
      @media (min-width:  40em) { @content; }
    }
    @else if $point == 768 {
      @media (min-width:  47.5em) { @content; }
    }
}

This is how we use the mixin in our main SCSS file:

header {
    width: 50%; //Properties for small screens
    background: red;
      @include minw(640) {
          width: 100%; //Properties for large screens
          background: blue;
  }
}

This is what the mixin compiles to:

header {
    width: 50%;
    background: red;
}
@media (min-width: 40em) {
    header {
      width: 100%;
      background: blue;
    }
}

In the media queries examples of this book, we're going to declare the width values in em units rather than pixels. This is because using em helps scale all values better, independent of the screen densities. Let's see what's happening here.

Mixin

First, we see the Sass-style comment describing that this mixin is for a mobile-first approach:

//Mobile-first

Then, we have the opening @mixin directive. This directive contains the name of the mixin, minw, which is the abbreviation of minimum-width. We're going to keep this name simple because we're going to type it a lot, so it's faster to type minw than minimum-width while still maintaining a meaningful term.

In parenthesis, we have the ($point) argument that will store the value we specify when defining which breakpoint we're going to be using:

@mixin minw($point)

Then, we have an opening @if statement. Remember we said that Sass was a programming/scripting language? What best represents a programming language than if-else statements?

The @if statement is followed by the $point variable that equals (==) 320 pixels width. The two equals signs (==) mean that it is absolutely equal to the value, that is, 320:

@if $point == 320

After that, we have the CSS @media directive that we've seen many times before. Within this directive, we specify the width in em, in this first case, 20em.

@media (min-width:  20em)

Then, we have the @content directive that allows us to put any content in between the brackets:

@media (min-width:  20em) { @content; }

This is followed by the @else statement with the $point variable, the two equals (==) signs, and the value of 640. If the defined value is 640 instead of 320, then the mixin can go ahead and use this specific media query for 640 pixels width.

@else if $point == 640

This means that 640 pixels is 40em:

@media (min-width:  40em) { @content; }

Finally, we have the same media query structure for 768 pixels width. 768 pixels is the same as 47.5em.

Consider the following points before choosing the method of letting content define the breakpoints:

  • The great thing about using specific width values (remember, these values are content-based) as media queries names (320, 640, or 768) is that when we use the mixin, we truly know what specific width we're targeting.
  • This means that no matter how many breakpoints we have, we will always know which width we're targeting.
  • We can have as many breakpoints as we need, and we'll never have to go back to the mixin to remind us which name belongs to which width.

Named media queries

This is the favorite of many frontend developers. This mixin is almost the same as the one we just saw; the difference is that instead of using specific widths and knowing that those widths will change and others will be added, this mixin uses abstract names for device-specific widths and usually there's an already defined list of breakpoints.

Here's what this mixin looks like:

//Mobile-first
@mixin breakpoint($point) {
    @if $point == small {
        @media (min-width:  20em) { @content; }
    }
    @else if $point == medium {
        @media (min-width:  40em) { @content; }
    }
    @else if $point == large {
        @media (min-width:  48em) { @content; }
    }
}

This is how we use it:

header {
    width: 50%; //Properties for small screens
    background: red;
    @include breakpoint(medium) {
        width: 100%; //Properties for large screens
        background: blue;
    }
}

And this is how it looks compiled:

header {
    width: 50%;
    background: red;
}
@media (min-width: 40em) {
    header {
        width: 100%;
        background: blue;
    }
}

Consider the following points before choosing the Named Media Queries method:

  • The use of abstract names can be confusing if you have many breakpoints.
  • At some point, you're either going to run out of abstract names, or have so many of them that you can't really remember which name belongs to which width.

The basic mixin

This is the recommended mixin to use when working with media queries, and it has the following advantages:

  • It allows us to keep thinking in pixels when defining our widths, but the output is in relative units (em).
  • It's quite simple to understand and to scale.
  • If we're using the desktop-first approach, all we need to do is change the mixin name from mobileFirst to desktopFirst, and change the min-width keyword to max-width.
  • If we want to use pixel-based width, we just need to remove 16 from the division: /16+em.
  • Since it doesn't use named variables to represent different widths, there is no need to remember which named variable corresponds to which width.
  • We'll never run out of named variables since it doesn't use them.

Now, considering that our recommendation is to let the content define the breakpoints, here's the mixin:

@mixin mobileFirst($media) {
    @media (min-width: $media/16+em) { @content; }
}

That's it—a mere three-line mixin. This is how we use it:

header {
    width: 50%; //Properties for small screensbackground: red;
    @include mobileFirst(640) {
        width: 100%; //Properties for large screensbackground: blue;
   }
}

This is what it compiles to:

header {
    width: 50%;background: red;
}
@media (min-width: 40em) {
    header {
      width: 100%;background: blue;
  }
}

Now, you might be asking yourselves, "where did the em values come from?"

It's simple. We divide the desired width by 16. The reason we're dividing by 16 is because 16px is the default font size of all browsers. By doing this, we get our values in em units.

Consider the following examples if you want to use 16px as your default font size:

  • 320px/16px = 20em
  • 640px/16px = 40em
  • 768px/16px = 47.5em

If you decide that your default font size is not going to be 16px but rather 18px, then the same process applies. Divide the desired width by 18px:

  • 320px/18px = 17.77em
  • 640px/18px = 35.55em
  • 768px/18px = 42.66em

The choice is yours.

Tip

All our examples are going to be based on a 16px default font size.

You have been reading a chapter from
Mastering Responsive Web Design
Published in: Aug 2015
Publisher:
ISBN-13: 9781783550234
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime