CSS Preprocessors – Introducing Sass to Podcastpedia.org


Octocat **Promotion** - Efficiently manage your coding bookmarks, aka #codingmarks, on www.codingmarks.org and share your hidden gems with the world. They will be published weekly on Github. Please help us build THE programming-resources location - Star


The Cascade Style Sheet (CSS) file of Podcastpedia.org had grown to over 2000 lines and it had become hard to manage. New CSS elements used to, most likely, go to the end of the file. Something had to be done… Well, CSS does have an import option that lets you split your CSS into smaller, more maintainable portions. The only MAJOR drawback is that each time you use @import in CSS it creates another HTTP request. In addition to that, this could have prevented style sheets from being downloaded concurrently. So, what to do? Ta-da, CSS preprocessors to the rescue.

Octocat Source code for this post is available on Github - podcastpedia.org is an open source project.

1. CSS Preprocessors

CSS preprocessors take code written in a preprocessed language (most popular now are Less and Sass) and then convert that code into the same old CSS we’ve been writing for years.

Some Sass vs. LESS resources

1.1. Sass

For now, I chose Sass (Syntactically Awesome Stylesheets), also called “CSS with super powers”. Sass is a scripting language that is interpreted into Cascading Style Sheets (CSS). SassScript is the scripting language itself.

1.2. SCSS

Now that I’ve decided to go with Sass, there are two different syntaxes to choose from: Sass or Sassy CSS(SCSS). I chose SCSS because it’s more alike to CSS, and thus provides a more lower barrier to entry (remember I am still earning my living as a back-end developer ):

“In version 3 of Sass, the SCSS (Sassy CSS) syntax was introduced as “the new main syntax” for Sass and builds on the existing syntax of CSS. It uses brackets and semi-colons just like CSS. It doesn’t care about indentation levels or white-space. In fact, Sass’s SCSS syntax is a superset of CSS – which means SCSS contains all the features of CSS, but has been expanded to include the features of Sass as well. In layman’s terms, any valid CSS is valid SCSS. And in the end, SCSS has the exact same features as the Sass syntax, minus the opinionated syntax.” [3]

2. Advantages of using preprocessors (Sass)

I will present in the following sections some features of Sass, and how they made my css-writing-life easier.

2.1. Partials – break the style sheet into meaningful separate sheets

You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. This is a great way to modularize your CSS and help keep things easier to maintain. A partial is simply a Sass file named with a leading underscore . You might name it something like _partial.scss. The underscore lets Sass know that the file is only a partial file and that it should not be generated into a CSS file[3]. Sass builds on top of the current CSS @import but instead of requiring an HTTP request, Sass will take the file that you want to import and combine it with the file you’re importing into so you can serve a single CSS file to the web browser.

There are many “best practices” on how to structure a Sass project with partials. If you analyze the main style sheet file podcastpedia.scss, that combines all the partials:

//first import variables that might be used throughout all the other files
@import "common/_variables";
@import "common/_mixins";

//initializing css
@import "_init";

//elements
@import "common/_icon_fonts";
@import "common/_languageSelection";
@import "common/_responsiveGrid";
@import "common/_navigation";
@import "common/_header";
@import "common/_pagination";
@import "common/_resultsList";
@import "common/_forms";
@import "common/_footer";
@import "common/_social_media_share";
@import "common/_button_links";

//pages
@import "pages/_podcastDetails";
@import "pages/_episodeDetails";
@import "pages/_allCategoriesPage";
@import "pages/_allKeywordsPage";
@import "pages/_homePage";
@import "pages/_advancedSearchForm";

// what's left from the original css that I could not put in someplace reasonable
@import "_leftovers";

you can see what suits me for now:

  • common – folder that stores css snippets that might be present all over the website; _variables and _mixins are placed at the beginning, as they might be used all over
  • pages – folder in which every file contains page-specific scss code
  • _init.scss – contains css property initialization
  • _leftovers.scss – what’s left from the original css that I could not place in a someplace reasonable. I could also use it if I need to make a quick fix.

In the @import directive you don’t have to specify .scss extension of the imported files.

2.2. Variables

Variables are a way to store information that you want to reuse throughout your style sheet. You can store things like colors, breakpoints, font stacks, or any CSS value you think you’ll want to reuse. Sass uses the $ symbol to make something a variable. Here are some examples from the _variables.scss file:

$border-radius-base: 5px !default;
#podcast_metadata {
  border-radius: $border-radius-base;
  padding: 8px 8px 3px 8px;
  position: relative;
  h2 {
    font-size: 2em;
    text-transform: normal;
    font-weight: 700;
    margin-bottom: 15px;
    padding-top: 8px;
    @include until-mq($break-point-normal){
      font-size:1.9em;
    }
    @include until-mq($break-point-smaller){
      font-size:1.6em;
    }
    @include until-mq($break-point-small){
      font-size: 1.3em;
      margin-bottom:0px;
      padding-top:0px;
    }
    @include until-mq($break-point-very-small){
      font-size: 14px;
		}
  }
  ...............
}

You can find the complete file where the snippet is extracted from, on Github – _podcastDetails.scss.

With variable defaults – !default – you can assign to variables if they aren’t already assigned by adding the !default flag to the end of the value. This means that if the variable has already been assigned to, it won’t be re-assigned, but if it doesn’t have a value yet, it will be given one.

2.3. Nesting

The nested syntax allows a cleaner method of targeting DOM elements. It prevents the need to rewrite selectors multiple times, additionally reducing the time it takes to make changes to style sheets. The inner rule then only applies within the outer rule’s selector. For example:

#nav {
  height: 38px;
  overflow: hidden;
  zoom: 1;
  margin: 0 auto;
  max-width: $page-max-width;
  min-width: $page-min-width;
  ul {
    list-style: none;
    margin: 0;
    padding: 0;
    li {
      float: left;
      width: 12em;
    }
  }
  li a {
    display: block;
    border-bottom: none;
    margin-right: 5px;
    color: #fff;
    text-align: center;
    text-decoration: none;
    font-size: 13px;
    height: 38px;
    background-color: #343435;
    border-radius: $border-radius-base;
    text-shadow: 4px 4px 3px #2C2D2E;
    padding: 5px;
    &:hover {
      background-color: #185B8B;
      color: #fff;
    }
  }
}

is compiled to :

#nav {
  height: 38px;
  overflow: hidden;
  zoom: 1;
  margin: 0 auto;
  max-width: 1060px;
  min-width: 300px;
}
#nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
#nav ul li {
  float: left;
  width: 12em;
}
#nav li a {
  display: block;
  border-bottom: none;
  margin-right: 5px;
  color: #fff;
  text-align: center;
  text-decoration: none;
  font-size: 13px;
  height: 38px;
  background-color: #343435;
  border-radius: 5px;
  text-shadow: 4px 4px 3px #2C2D2E;
  padding: 5px;
}
#nav li a:hover {
  background-color: #185B8B;
  color: #fff;
}

You can find the complete file from the example on GitHub – _navigation.scss.

With the help of the ampersand(&) you can reference the parent selector. In the example above, line 30, the ampersand is used to modify the layout of the menu items when hovering over them.

2.4. Extend/Inheritance

This should one of the most useful features of Sass, which I have not used yet :). Using @extend lets you share a set of CSS properties from one selector to another. It helps keep your Sass very DRY.

At the time of this writing the gulp-sass plugin does not support properly this feature, but the gulp-ruby-sass should.

2.5. Mixins

A mixin lets you make groups of CSS declarations that you want to reuse throughout the website. You can pass values to make the mixin more flexible. Here is an example of using mixin for media queries breakpoints:

/* media query mixin */
@mixin until-mq($device-width) {
  @media screen and (max-width: $device-width - 1) {
    @content
  }
}

You use the @mixin directive to created a mixin and give it a name. The one presented here is named until-mq. As input it receives the $device-width parameter inside the parentheses, so that  I can pass the width of the device, in pixels, until which the media query rule is valid. I use it all over the website where I need responsive design. Based on the same example used in sections 2.2. Variables, the mixin is used when setting the title of the podcast depending on the display’s width:

#podcast_metadata {
  border-radius: $border-radius-base;
  padding: 8px 8px 3px 8px;
  position: relative;
  h2 {
    font-size: 2em;
    text-transform: normal;
    font-weight: 700;
    margin-bottom: 15px;
    padding-top: 8px;
    @include until-mq($break-point-normal){
      font-size:1.9em;
    }
    @include until-mq($break-point-smaller){
      font-size:1.6em;
    }
    @include until-mq($break-point-small){
      font-size: 1.3em;
      margin-bottom:0px;
      padding-top:0px;
    }
    @include until-mq($break-point-very-small){
      font-size: 14px;
	}
  }
  .......
}

So after the mixin has been created, you can use it then as a CSS declaration starting with @include followed by the name of the mixin.

To avoid code duplication you should only use mixins if you need to pass custom parameters. If you see yourself using the same mixing multiple times passing the same values than you should create a base “type” that is inherited by other selectors. A good article on this topic is  Mixins and Selector Inheritance in SASS: When Should You Use One Or the Other?

I started working with @media queries by adding blocks of them at the bottom of your main style sheet. That works, but it leads to mental disconnect between the original styling and the responsive styles.

A good use of mixins is for vendor prefixes. But you can avoid all this tedious writing by using the gulp-autoprefixer plugin to do that for you. Check the following post on how to do that. </p> ### 2.6. Operators

Doing math in your CSS is very helpful. Sass has a handful of standard math operators like +, -, *, /, and %.

There might be some “disadvantages” in using preprocessors, like the ones mentioned in The problem with CSS pre-processors, but I for one, wouldn’t go back writing plain CSS again.

Well, those are some of the “sassy” features I’ve used so far to style Podcastpedia, but I am sure there are other goodies left to be discovered and put to use (e.g. sass-based functions …) – maybe you could give me a helping hand and leave a comment regarding this.

3. Generate the CSS

Now that I have everything set in place, it’s time to generate the CSS file. Initially I wanted to present how I did that in this one post, but since the it got pretty long and the topics can be discussed separately I’ve decided to move it to a new post. So in the post “How to use Gulp to generate CSS from Sass(scss)” (coming next week) you’ll find out how o generate the CSS file used for Podcastpedia.org.

Octocat Source code for this post is available on Github - podcastpedia.org is an open source project.

## 4. Resources ### 4.1. Web 1. Cascading Style Sheets – Wikipedia 2. Sass: Syntactically Awesome Style Sheets 3. Sass Guide  4. LESS (Leaner CSS) 5. Mixins and Selector Inheritance in SASS: When Should You Use One Or the Other? 6. CSS tricks – Sass Style Guide 7. CSS tricks – Naming Media Queries
Podcastpedia image

Adrian Matei

Creator of Podcastpedia.org and Codingpedia.org, computer science engineer, husband, father, curious and passionate about science, computers, software, education, economics, social equity, philosophy - but these are just outside labels and not that important, deep inside we are all just consciousness, right?

Parallel calls with async-await in javascript - I promise you all performance and simplicity

I was blown away about the simplicity and performance gain of making parallel calls with the new async-await feature in javascript. See the blog post to understand why. Continue reading