Get Setup! – Alex Vasquez – Let's meet you!



Get Setup! – Alex Vasquez – Let's meet you!

0 0


sass-shop

Repository for intro Sass Class

On Github gdila / sass-shop

Get Setup!

Wifi Network:

Password:

Post Class Survey: Post Class Survey
WiFi SSID/Password: Opodz Members / opodz888
Recommended Tools:

Sublime Text

Terminal or Command Prompt / Git Bash

Google Chrome

LivePage

Alex Vasquez

alexhasnicehair.com   |   @alexjvasquez   |   alexjvas@gmail.com

  • Working Remote
  • SlickQuiz
  • Full Time Sass for 1 year

Let's meet you!

What is your name?

What is your 140 character bio?

What is your fave dev tool / plugin / blog / etc.?

Well you all rule because I love all cookies, my nickname as a child was "the cookie monster."

Getting Sassy with CSS

What is Sass The Sass Workflow Sass Basics Advanced Sass Media Queries Modular Architecture Libraries & Tools Wrap-Up

The Project...

Client: Kittens "R" Us

Description: A local adoption listing website for kitties in need of homes.

Framework: HTML5 & CSS3

Slides + Project: http://gdila.github.io/sass-shop

Nothing too special, just something to play around with - but feel free to go all out!

I HIGHLY recommend that you DL these slides and refer back to them as we're going through exercises

You're welcome to follow the examples exactly, or customize things as we go.

And Feel free to try things out as I'm presenting, I don't want you to feel like you need to wait for the exercise to experiment.

Project Setup Let's develop it!

Download the slides.http://gdila.github.io/sass-shop Open the exercises directory in your text editor of choice.The exercises/kittens directory is where we'll be doing our work. Navigate to the exercises/kittens directory via the command line.Run sass -v to verify that Sass is installed. Open exercises/kittens/index.html in your browser.Yay, kittens!

Section I

What is Sass?

WHY The Trouble with CSS

  • Websites are becoming increasingly complex.
  • CSS is getting harder to maintain.
  • Writing styles is often tedious and repetitive.
  • CSS can only do so much for us...
  • bigger, more modular, componentized
  • our needs for organization are increasing
  • repetition - think vendor prefixes, think linear gradients
  • CSS was designed to be a simple language - advanced features were left out in favor of adoptability

Syntactically Awesome StyleSheets

Like CSS, but AWESOME

Sass Origins

Sass Trifecta of Awesome

Tools like Sass, Less and Stylus have live-tested features and impelemnations that will likely inspire features in future CSS specifications.

So let's get a taste of what Sass can do for us by digging into one of CSSs pain-points: repetition.

Repetition

.header {
  background-color: #531946;
  border-radius: 5px;
  padding: 5px 20px;
}
.header a {
  color: #fff;
}
.header a:hover {
  color: #095169;
}

.footer {
  background-color: #30162B;
  color: #fff;
  border-radius: 5px;
  padding: 5px 20px;
}
.footer a {
  color: #095169;
}
.footer a:hover {
  color: #fff;
}

.feature a {
  background-color: #30162B;
  color: #fff;
  border-radius: 5px;
  padding: 5px 20px;
}
.feature a:hover {
  color: #531946;
}

.content {
  background-color: #fff;
  color: #222;
  border-radius: 5px;
  padding: 5px 20px;
}

DRY

Don't Repeat Yourself

HEX Colors

Border Radius + Padding

Selectors

development principle aimed at reducing repetition

HINT: the syntax highlighting might give you a few ideas

Colors >> Padding >> Selectors

So let's see what Sass can do for us in these scenarios, starting with colors...

Repetition Colors

CSS

.header {
  background-color: #531946;
}
.header a {
  color: #fff;
}
.header a:hover {
  color: #095169;
}

.footer {
  background-color: #30162B;
  color: #fff;
}
.footer a {
  color: #095169;
}
.footer a:hover {
  color: #fff;
}

.feature a {
  background-color: #30162B;
  color: #fff;
}

.feature a:hover {
  color: #531946;
}

.content {
  background-color: #fff;
  color: #222;
}

Sass Variables

$white: #ffffff;
$black: #222222; // NOT! ;)
$eggplant: #531946;
$eggplantDark: #30162B;
$teal: #095169;

.header {
  background-color: $eggplant;
}
.header a {
  color: $white;
}
.header a:hover {
  color: $teal;
}

.footer {
  background-color: $eggplantDark;
  color: $white;
}
.footer a {
  color: $teal;
}
.footer a:hover {
  color: $white;
}

.feature a {
  background-color: $eggplantDark;
  color: $white;
}

.feature a:hover {
  color: $eggplant;
}

.content {
  background-color: $white;
  color: $black;
}

No one wants to remember #531946

Wouldn't it be nice if we had a way to store and reference our colors?

Repetition Border Radius + Padding

CSS

.header {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

Sass Mixins

@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @include rounded-box;
  // ...
}

.footer {
  @include rounded-box;
  // ...
}

.feature a {
  @include rounded-box;
  // ...
}

.content {
  @include rounded-box;
  // ...
}

It looks like we've got a default box style

What if we could set those defaults in one place and reference it elsewhere?

Repetition Selectors

CSS

.header {
  /* ... */
}
.header a {
  /* ... */
}
.header a:hover {
  /* ... */
}

.footer {
  /* ... */
}
.footer a {
  /* ... */
}
.footer a:hover {
  /* ... */
}

.feature a {
  /* ... */
}
.feature a:hover {
  /* ... */
}

.content {
  /* ... */
}

Sass Nesting

.header {
  // ...

  a {
    // ...

    &:hover {
      // ...
    }
  }
}

.footer {
  // ...

  a {
    // ...

    &:hover {
      // ...
    }
  }
}

.feature a {
  // ...

  &:hover {
    // ...
  }
}

.content {
  // ...
}

What if I want to change .header to .banner? I have to edit it everywhere

What if we had a way of only referencing these repeated selectors once?

What if we could nest our selectors just like we can in our HTML?

RECAP Repetition

CSS

.header {
  background-color: #531946;
  border-radius: 5px;
  padding: 5px 20px;
}
.header a {
  color: #fff;
}
.header a:hover {
  color: #095169;
}

.footer {
  background-color: #30162B;
  color: #fff;
  border-radius: 5px;
  padding: 5px 20px;
}
.footer a {
  color: #095169;
}
.footer a:hover {
  color: #fff;
}

.feature a {
  background-color: #30162B;
  color: #fff;
  border-radius: 5px;
  padding: 5px 20px;
}
.feature a:hover {
  color: #531946;
}

.content {
  background-color: #fff;
  color: #222;
  border-radius: 5px;
  padding: 5px 20px;
}

Sass

$white:        #ffffff;
$grey:         #222222;
$eggplant:     #531946;
$eggplantDark: #30162B;
$teal:         #095169;

// Mixins
@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

// Site Stylez
.header {
  @include rounded-box;
  background-color: $eggplant;

  a {
    color: $white;
    &:hover { color: $teal; }
  }
}

.footer {
  @include rounded-box;
  background-color: $eggplantDark;
  color: $white;

  a {
    color: $teal;
    &:hover { color: $white; }
  }
}

.feature a {
  @include rounded-box;
  background-color: $eggplantDark;
  color: $white;

  &:hover { color: $eggplant; }
}

.content {
  @include rounded-box;
  background-color: $white;
  color: $grey;
}

Colors (vars), Border Radius + Padding (mixin), Selectors (nesting)

RECAP Why Sass?

  • Reduced complexity.
  • Increased maintainability.
  • Minimized repetition.
  • Supercharged CSS!

Alright, so now that we've gotten a taste of it in action, let's get an official definition

What is Sass?

Sass is an extension of CSS that adds power and elegance to the basic language. It allows you to use variables, nested rules, mixins, inline imports, and more, all with a fully CSS-compatible syntax. Sass helps keep large stylesheets well-organized, and get small stylesheets up and running quickly...

~ Sass Documentation

Any valid CSS file is a valid Sass file

What is Sass?

CSS Extension

SassScript Language

CSS Preprocessor

SassScript Interpreter

Sass CSS

Sass is an extension of CSS, but we can't load Sass in the browser like we can CSS

May seem like 2 separate tools, but they're really just one, and more often then not, you'll hear them referred to as a singluar tool.

Two SassScript Syntaxes

.scss (Sassy CSS)Default syntax; Valid CSS == Valid SCSS

$black: #000;
$white: #fff;

.this {
  color: $black;
  background: $white;
}

.that {
  color: $white;
  background: $black;
}

.this, .that {
  display: block;

  &:hover {
    border: 1px solid;
  }
}

.sass (Indented)Original syntax, still supported; Haml-esque

$black: #000
$white: #fff

.this
  color: $black
  background: $white

.that
  color: $white
  background: $black

.this, .that
  display: block
  &:hover
    border: 1px solid

Because valid CSS is also valid SCSS, getting started with Sass is as easy as changing the file extension.

Start slow, add in features as you learn / get more comfortable.

Section II

The Sass Workflow

Sass Installation

Ruby

OS X? Lucky you, it's preinstalled!

Windows? Try RubyInstaller.

Sass

$ gem install sass

Running Sass

(aka Compiling Sass)

Sass CSS

$ sass source.scss output.css

$ sass source_dir output_dir

So let's get a more visual representation...

Running Sass

  • kittens
    • index.html
    • sass
      • application.scss
    • css
      • application.css
$ sass sass/screen.scss css/screen.css

At this point you might be thinking

Well gosh, do I need to run this command EVERY single time I make a change?

And the answer is of course not! That's what watching is for!

Sass Is Watching You...

$ sass --watch source.scss:output.css
This is the best thing EVER.
Gotchya: Colon vs. Space
  • works with single files and entire directories
  • ...let's look at some more commands

More Sass Options

$ sass source.scss output.css
Compile source.scss to output.css. Gotchya: will fail if output directory doesn't exist.
$ sass --update source.scss:output.css
Compile source.scss to output.css. Will create directory if it doesn't exist.
$ sass --watch source.scss:output.css
Watch source.scss for changes. Will create directory if it doesn't exist.
$ sass --style expanded source.scss:output.css
Adjusts output format. Options: nested, expanded, compact, compressed

I'm going to get into some code to explain the style option more...

Demo Sass Workflow

Exercise - Section 2

  • sass sass/screen.scss css/screen.css
  • sass --update sass/screen.scss:css/screen.css
  • sass --watch sass/screen.scss:css/screen.css
  • sass --style expanded sass/screen.scss:css/screen.css
  • sass --style compact sass/screen.scss:css/screen.css
  • sass --style compressed sass/screen.scss:css/screen.css

Sass Sourcemaps

Sourcemaps tell browsers where the Sass that generated the CSS is.You must enable sourcemaps in the browser to use this feature.

LET'S ALL DO THIS TOGETHER!

"Auto reload generated CSS" is a bit beyond our scope for today, but it will let you make CSS changes in the browser and have them saved back to your Sass code.

Workflow Let's develop it!

Open up your kittens project Open index.html in the broswerOptionally enable LivePage** Copy css/application.css to sass/application.scssmkdir sass && cp css/application.css sass/application.scss Remove application.css rm css/application.css Run Sass (on one line): sass --watch --style expanded sass/application.scss:css/application.css Checkout your page in the browser to see your new sassified stylez!
  • kittens
    • index.html
    • css
      • application.css
    • sass
      • application.scss
** You will need to enable "Allow access to file URLs" for LivePage in chrome://extensions

Section III

Sass Basics

Alright, so now that we know generally what Sass is and how it works

let's get into the basics

Sass Basics

Nesting Variables Imports & Organization

Imports are critical for a modular and organized architecture

Sass Basics Nesting

HTML has a clear hierarchy - elements are nested.

We can apply the same concept in Sass.

HTML

<nav class="navigation">
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#about">About</a></li>
    <li><a href="#contact">Contact</a></li>
  </ul>
</nav>

Sass

.navigation {
  float: right;

  li {
    display: inline-block;
    list-style-type: none;
    margin-left: 1.5em;
  }

  a {
    display: block;
    text-decoration: none;
  }
}

THIS IS MY FAVORITE THING.

It's the one thing that I instantly miss when writing vanila CSS.

I do it by habit and intuition now.

Let's look at the output of that...

Nesting Output

Sass

.navigation {
  float: right;

  li {
    display: inline-block;
    list-style-type: none;
    margin-left: 1.5em;
  }

  a {
    display: block;
    text-decoration: none;
  }
}

CSS Output

.navigation {
  float: right;
}

.navigation li {
  display: inline-block;
  list-style-type: none;
  margin-left: 1.5em;
}

.navigation a {
  display: block;
  text-decoration: none;
}

Sass gives us organization.

Sass reduces repetition.

So, there's kid of a gotchya with nesting though...

Nesting Gotchya

Mirroring HTML nesting is SUPER easy.

Overly verbose and overly specific.

Rule of thumb or "the Inception Rule": no more than 3 levels deep.

Sass

body {
  .header {
    .navigation {
      ul {
        li {
          a {
            // ...
          }
        }
      }
    }
  }
}

CSS Output

body .header .navigation ul li a {
  // ...
}

Work WITH the cascade, not against it

Nesting too deeply results in specificity nightmares and fragile, unmaintainable code

Nesting Parent Selectors

Sass allows us to reference the current parent selector(s) via the ampersand character:

Sass

a {
  color: #beedee;

  &:hover {
    color: #cbbebb;
  }

  &.btn {
    background: #deede6;
  }

  .btn {
    display: block;
  }
}

CSS Output

a {
  color: #beedee;
}

a:hover {
  color: #cbbebb;
}

a.btn {
  background: #deede6;
}

a .btn {
  display: block;
}

The ampersand will reference the entire chain of parent selectors

Nesting Parent Selectors

The & selector can follow other selectors. This will override the parent element's (&) styles when it exists within the preceding selector.

Sass

a {
  .footer & {
    text-decoration: none;

    span {
      opacity: .5;
    }
  }

  span {
    .navigation & {
      display: block;
    }
  }
}

CSS Output

.footer a {
  text-decoration: none;
}

.footer a span {
  opacity: .5;
}

.navigation a span {
  display: block;
}

So this can be really really helpful, especially if you're familiar with the concept of modifiers as they relate to the concepts of OOCSS and BEM.

What you're essentially doing is modifying the parent selector

We'll jump quickly into OOCSS and BEM later, but you'll see hints of it throughout the shop

Nesting Parent Selectors

The & selector can also be combined with strings.PERFECT for BEM, child elements, states, and modifications.

Sass

.module {
  &__child {
    margin-bottom: 1em;
  }

  &--modifier {
    display: inline;
  }
}

CSS Output

.module__child {
  margin-bottom: 1em;
}

.module--modifier {
  display: inline;
}

AGAIN this can be really really helpful, especially if you're familiar with the concept of modifiers as they relate to the concepts of OOCSS and BEM.

What you're essentially doing is modifying the parent selector

We'll jump quickly into OOCSS and BEM later, but you'll see hints of it throughout the shop

Nesting Parent Selectors

The & contents can also be accessed as a string/list and used in SassScript.

Sass

.thing.thang {
  .thung {
    content: &;
    content: &--mod;
    content: selector-append(&, '--mod');

    &--mod { content: 'here'; }
  }
}

CSS Output

.thing.thang .thung {
  content: .thing.thang .thung;
  content: .thing.thang .thung --mod;
  content: .thing.thang .thung--mod;
}
.thing.thang .thung--mod {
  content: 'here';
}

There are a handful of additional selector methods.

this is some pretty advanced stuff that you probably won't use for a while

Nesting Properties

You can also nest namespaced properties

Sass

a {
  border: {
    color: #deedee;
    style: solid;
    width: 2px;
  }
}

CSS Output

a {
  border-color: #deedee;
  border-style: solid;
  border-width: 2px;
}

Not only can you nest selectors

ALRIGHT, so that was nesting, let's move on to the next basic...

Nesting Let's develop it!

NEST ALL THE THINGS!!

BUT Don't nest too deeply!

And just kidding...You don't need to nest everything.

P.S. Don't ForgetThe parent & selector.

Oh! And feel free to rename things!

// good
.navigation {
  li {//...}
  a  {
    //...
    &:hover { //... }
  }
}

// bad
body {
  .header {
    .navigation {
      ul {
        li {
          a {
            // ...
          }
        }
      }
    }
  }
}

sass --watch --style expanded sass/application.scss:css/application.css

Sass Basics

Variables

We already saw a sampling of variables when we talked about repetition, so we know that they help to

  • Reduce repetition
  • Improve maintainability
  • Make Find & Replace! unecessary or at least easier

So let's see what ELSE we can use variables for

Sass Basics Variables

Some Uses

  • colors
  • font sizes
  • font families
  • font paths
  • padding
  • margins
  • breakpoints

Some More Uses

  • border-radius
  • content
  • gradients
  • shadows
  • SELECTORS!
  • LOGIC!
  • ALL THE THINGS!!!1!

you can put just about anything in a variable and so for that reason, it's a very very valuable tool for dealing with the repetition and tediousness of CSS

so how do we use em...

Variables Assignment & Reference

Variables are defined à la CSS prop/val pairs: $property: value;

Variables are then referenced by their $-prefixed names.

Sass

$grey: rgba(0,0,0,.5);
$teal: #095169;
$default-padding: 1em;

a {
  color: $teal;
  padding: $default-padding;
  &:hover {
    color: $grey;
    background: $teal;
  }
}

p { padding-bottom: $default-padding; }

CSS Output

a {
  color: #095169;
  padding: 1em;
}

a:hover {
  color: rgba(0,0,0,.5);
  background: #095169;
}

p {
  padding-bottom: 1em;
}

as you can see, we've set a few different types of data - there are 7 main data types that Sass accepts

Variable Data Types

Types

  • Numbers
  • Strings
  • Colors
  • Lists
  • Booleans
  • Null
  • Maps

Uses

$base-padding: 10px;
$line-height: 1.5;

$base-font: Verdana;
$content: "Loading...";

$feature-color: purple;
$feature-background: rgba(0, 255, 0, 0.5);

$base-margin: 20px 0 30px 10px;
$base-font: "Trebuchet MS", "Verdana", "Arial";

$bordered: true;
$shadowed: false;

$secondary: null;

$map: (key1: value1, key2: value2, key3: value3);

NUMBERS can be set with or without units

STRINGS can be set with or without quotes

we'll get into things like lists, booleans, and null later, but they can be super helpful

now, there are two ways to define variables, the first is Simple Assignment

Variable Simple Assignment

You can redeclare variables to override previous values

Sass

$border-width: 2px;
$border-width: 4px;

a {
  border: $border-width solid $teal;
}

CSS Output

a {
  border: 4px solid #095169;
}

simple assignment: create a variable, assign it a value

you can also override these values

This is especially helpful when theming or working with third party tools

Variable Guarded Assignment

The !default flagMeans: set if it does not already have a value

Sass

$border-width: 2px;
$border-width: 4px !default;

a {
  border: $border-width solid $teal;
}

CSS Output

a {
  border: 2px solid #095169;
}

a lot of 3rd party libraries use guarded assignment so that you can override their values before including the code

so this leads us nicely into scope

Variable Scope

Variables are only available within the level of nested selectors where they're defined.

If they're defined outside of any nested selectors, they're available everywhere.

~ Sass Documentation

Sass

$border-width: 4px; // Global

a {
  $color: orange;   // Local
  border: $border-width solid $color;
}

p {
  border: $border-width solid $color;
  // ERROR!! Undefined variable "$color"
}

This is sort of a global / local setup

Globals are a bit more flexible, let's take a look

Variable Globals

Changes to "global" variables within a selector are local to that selector.

UNLESS defined with the !global flag, in which case the change is set globally.

DEMO

Sass

$border-width: 4px;
$border-radius: 4px;

a {
  $border-width: 2px !global;
  $border-radius: 8px;

  border-width: $border-width;   //=> 2px
  border-radius: $border-radius; //=> 8px
}

p {
  border-width: $border-width;   //=> 2px
  border-radius: $border-radius; //=> 4px
}

We can change global variables anywhere IF we use the !global flag

We can only create or change local variables within that nesting level

So this brings us to the last aspect of variables - interpolation

Variable Interpolation

Variables can be injected into selectors,property names and values, and strings via #{$variable}

Sass

$side: left;

.box-#{$side} {
  border-#{$side}: 1px solid #ccc;

  &:before {
    content: "It's on the #{$side} side";
  }
}

CSS Output

.box-left {
  border-left: 1px solid #ccc;
}

.box-left:before {
  content: "It's on the left side";
}

We'll see how this can become pretty handy later on

PROTIP Modular Naming

OK Variables

$white: #ffffff;
$black: #222222;
$eggplant: #531946;
$eggplantDark: #30162B;
$teal: #095169;

.header {
  background-color: $eggplant;
}
.header a {
  color: $white;
}
.header a:hover {
  color: $teal;
}

.footer {
  background-color: $eggplant-dark;
  color: $white;
}
.footer a {
  color: $teal;
}
.footer a:hover {
  color: $white;
}

.feature a {
  background-color: $eggplant-dark;
  color: $white;
}

.feature a:hover {
  color: $eggplant;
}

.content {
  background-color: $white;
  color: $black;
}

Better Variables

// Descriptive Colors
$white:        #ffffff;
$grey:         #222222;
$eggplant:     #531946;
$eggplantDark: #30162B;
$teal:         #095169;

// Functional Colors
$header--background:          $eggplant;
$header__logo--color:         $white;
$header__logo--color--hover:  $teal;

$footer--background:          $eggplant--dark;
$footer--color:               $white;
$footer__nav--color:          $teal;
$footer__nav--color--hover:   $white;

$content--background:         $white;
$content--color:              $grey;

$feature__link--background:   $eggplant--dark;
$feature__link--color:        $white;
$feature__link--color--hover: $eggplant;

.header {
  background-color: $header--background;
}
.header a {
  color: $header__logo--color;
}
.header a:hover {
  color: $header__logo--color--hover;
}

.footer {
  background-color: $footer--background;
  color: $footer--color;
}
.footer a {
  color: $footer__nav--color;
}
.footer a:hover {
  color: $footer__nav--color--hover;
}

.feature a {
  background-color: $feature__link--background;
  color: $feature__link--color;
}

.feature a:hover {
  color: $eggplant;
}

.content {
  background-color: $content--background;
  color: $content--color;
}

You want to be crafty with naming, but also don't spend too much time worrying about them, they're easy enough to update later once patterns become more apparent

Variables Let's develop it!

DRY Up Your Styles

Add Variables

  • colors values
  • font family
  • border width
  • border radius

Repetitious values.

"Arbitrary" values.

sass --watch --style expanded sass/application.scss:css/application.css

So we're not going to focus too much on globals or overrides or interpolation at this stage, let's just get comfortable with setting and using variables

Sass Basics

Imports & Organization

Sass Basics Imports & Organization

CSS @import has always meant an extra file download.

Sass modifies @import to instead include the resource during compilation, rather than on the client side.

Organization OMGZZ!

@import "vars";

@import "compass";
@import "fontawesome";

@import "utilities";

@import "grid";
@import "base";

@import "modules/all";
@import "pages/all";

What does this mean?

We can now organize our styles in a modular fashion

Organization Imports

@import takes a path to a Sass resource, the file extension is optional.

These @imports look for resources within the main Sass file's parent directory.

@import "vars";

@import "compass";
@import "fontawesome";

@import "utilities";

@import "grid";
@import "base";

@import "modules/all";
@import "pages/all";

Now when I say MAIN SASS FILE we're starting to get into file organization here...

Imports File Structure

application.scss

@import "vars";
@import "lib/compass";
@import "lib/fontawesome";
@import "utilities";
@import "grid";
@import "base";

$ sass sass/screen.scss css/screen.css

  • project_awesome
    • sass
      • lib
        • compass.scss
        • fontawesome.scss
      • base.scss
      • grid.scss
      • screen.scss
      • utilities.scss
      • vars.scss
    • css
      • screen.css
  • application.scss is our "main" sass file, where we import and organize our project
  • the @import paths reference files in the same directory or nested below
  • so if we were to run this sass command, we'd end up with application.css
  • Now there's sort of a gotchya here...

Imports Compiling Directories

$ sass sass/ css/

  • sass
    • lib
      • compass.scss
      • fontawesome.scss
    • base.scss
    • grid.scss
    • screen.scss
    • utilities.scss
    • vars.scss

  • css
    • lib
      • compass.css
      • fontawesome.css
    • base.css
    • grid.css
    • screen.css
    • utilities.css
    • vars.css

if we compile the whole directory, we get output for every file

running sass on directories will compile all Sass files regardless of whether or not they've been included elsewhere

how do we fix that? what if we wanted to compile a screen and a print stylesheet and didn't want to run multiple sass commands...

Imports Partials

$ sass sass/ css/

  • sass
    • lib
      • _compass.scss
      • _fontawesome.scss
    • _base.scss
    • _grid.scss
    • print.scss
    • screen.scss
    • _utilities.scss
    • _vars.scss

  • css
    • print.css
    • screen.css
  • An _underscore creates a partial
  • Partials will not compile to .css on their own, they must be @imported
  • Partials allow us to break up our code into more modular, maintainable chunks!

Imports Organization

Common Practices

  • _vars.scss is a separate sheet for all your variables
  • _vars.scss is added first so that it's variables can override later !defaulted ones
  • Variables > Libraries > Base > Modules > PagesOOCSS, BEM, SMACSS, Atomic Design
  • Modular Architecture

application.scss

// Variables
@import "vars";

// Libraries
@import "lib/compass";
@import "lib/fontawesome";

// Base Styles, Utility Classes, etc.
@import "base/all";

// Individual Components
@import "modules/all";

// Page Styles
@import "pages/all";

Ultimately, how you organize your code is up to you

Imports Let's develop it!

  • Update your Sass structure to look something like the one on the right.
  • Move ALL styles from application.scss to more modular / organized locations.
  • Update application.scss to @import your new partials.
  • kittens
    • sass
      • base
        • _vars.scss
        • _base.scss
      • modules
        • _header.scss
        • _footer.scss
        • _kittens.scss
        • _info.scss
      • application.scss

sass --watch --style expanded sass/application.scss:css/application.css

Section IV

Advanced Sass

Advanced Sass

Mixins (@include) Inheritance (@extend) Math & Color Directives (Overview)

Advanced Sass Mixins

Variables let you reuse single values.

Mixins let you reuse blocks of styles.

So let's look at some code...

Mixins Use

CSS

.header {
  border-radius: 5px;
  padding: 5px 20px;
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
}

Sass Mixins

@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @include rounded-box;
}

.footer {
  @include rounded-box;
}

.feature a {
  @include rounded-box;
}

.content {
  @include rounded-box;
}

Earlier we saw this border-radius / padding combination repeated

They're sort of default settings, if you will

We can make this more maintainable, by pulling these out into one location

let's dig into this code a bit more...

Mixins Setup

@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @include rounded-box;
  color: $header-color;
  // ...
}

.footer {
  @include rounded-box;
  // ...
}

.feature a {
  @include rounded-box;
  // ...
}

.content {
  @include rounded-box;
  // ...
}
  • We define a mixin with the @mixin directive.
  • We reference a mixin with the @include directive.
  • Mixins must be defined before they're referenced.
  • Mixins accept optional arguments.
  • Mixins can be used with any other style rules.
  • You can nest within mixins just like you can elsewhere.

Now, let's look at what's actually happening here before we move on

defined before referenced -- partials / imports

So let's see what this actually outputs

Mixins Output

Sass

@mixin rounded-box {
  border-radius: 5px;
  padding: 5px 20px;
}

.header {
  @include rounded-box;
  color: $header-color;
  // ...
}

.footer {
  @include rounded-box;
  // ...
}

.feature a {
  @include rounded-box;
  // ...
}

.content {
  @include rounded-box;
  // ...
}

CSS Output

.header {
  border-radius: 5px;
  padding: 5px 20px;
  color: $header-color;
  /* ... */
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

We're still just repeating properties here....

Mixins Efficiency

Mixin Output

.header {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

CSS Grouping

.header,
.footer,
.feature a,
.content {
  border-radius: 5px;
  padding: 5px 20px;
}

It'd actually be more efficient just to group the classes together.

So what's a good use case for mixins then...

Mixins CSS3

Vendor Prefixes?!

@mixin rounded-corners {
  -webkit-border-radius: 10px;
     -moz-border-radius: 10px;
          border-radius: 10px;
}

.header {
  @include rounded-corners;
  // ...
}

.footer {
  @include rounded-corners;
  // ...
}

But... we're still really just copying the same properties and values all over the place.

How about anything with vendor prefixes?

Those things get repetitive, it'd be nice to have a one liner right?

But..

alright, so when the hell are mixins useful then?...

Mixins Arguments

Mixins are great for repeated blocks of styleswhere the values differ from case to case.

Sass

@mixin rounded-corners($radius) {
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
          border-radius: $radius;
}

.header {
  @include rounded-corners(5px);
  // ...
}

.footer {
  @include rounded-corners(10px);
  // ...
}

CSS Output

.header {
  -webkit-border-radius: 5px;
     -moz-border-radius: 5px;
          border-radius: 5px;
  // ...
}

.footer {
  -webkit-border-radius: 10px;
     -moz-border-radius: 10px;
          border-radius: 10px;
  // ...
}

I mentioned before that mixins can accept arguments

Dynamic VS Static

Mixins Argument Defaults

You can also set an argument's default value,making it optional to pass one in.

Sass

@mixin rounded-corners($radius: 5px) {
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
          border-radius: $radius;
}

.header {
  @include rounded-corners;
  // ...
}

.footer {
  @include rounded-corners(10px);
  // ...
}

CSS Output

.header {
  -webkit-border-radius: 5px;
     -moz-border-radius: 5px;
          border-radius: 5px;
  // ...
}

.footer {
  -webkit-border-radius: 10px;
     -moz-border-radius: 10px;
          border-radius: 10px;
  // ...
}

Arguments are required, unless you set a default

Now let's go a level deeper here...

Mixins Multiple Arguments

Comma separated, order matters.

Sass

@mixin rounded-box($radius, $padding) {
  border-radius: $radius;
  padding: $padding;
}

.header {
  @include rounded-box(5px, 20px);
  color: $header-color;
  // ...
}

.footer {
  @include rounded-box(20px, 40px);
  // ...
}

CSS Output

.header {
  border-radius: 5px;
  padding: 20px;
  // ...
}

.footer {
  border-radius: 20px;
  padding: 40px;
  // ...
}

Now what if we want to set defaults for all or some of these mixin variables?...

Mixins Optional Arguments

Optional arguments (ones with defaults) must be last in the set.

Sass

@mixin rounded-box($radius: 5px, $padding: 20px) {
  border-radius: $radius;
  padding: $padding;
}

@mixin content($color, $font-size: 12px) {
  color: $color;
  font-size: $font-size;
}

.header {
  @include rounded-box;
  @include content(#aaa, 24px);
  // ...
}

.footer {
  @include rounded-box(20px, 40px);
  @include content(#ccc);
  // ...
}

CSS Output

.header {
  border-radius: 5px;
  padding: 20px;
  color: #aaa;
  font-size: 24px;
  // ...
}

.footer {
  border-radius: 20px;
  padding: 40px;
  color: #ccc;
  font-size: 12px;
  // ...
}

Remembering what the arguments are and exactly what order they're in can be a pain.

Mixins Keyword Arguments

Order doesn't matter!

@mixin rounded-box($radius: 5px, $padding: 20px) {
  border-radius: $radius;
  padding: $padding;
}

.header {
  @include rounded-box($padding: 10px, $radius: 10px);
}

.footer {
  @include rounded-box($padding: 40px);
}

Of course, arguments without defaults must still be passed in.

One last thing...

Mixin Variable Interpolation

Sass

@mixin toolbar-border($side, $width: 2px) {
  border-#{$side}: $width solid $toolbar-border;
}

.sidebar--left {
  @include toolbar-border("right");
}

.sidebar--right {
  @include toolbar-border("left");
}

CSS Output

.sidebar--left {
  border-right: 2px solid #213213;
}

.sidebar--right {
  border-left: 2px solid #213213;
}

This helps us create even more dynamic mixins

We can do this sort of interpolation all over the place, not just in mixins

Mixins Let's develop it!

  • Create a mixins partial in your base directory and @import it in your main .scss file.
  • Create a border-radius @mixin with a required radius argument. Include common vendor prefixes.
  • Create a similar @mixin for scaled transformations.ie. transform: scale(1.1);
  • @include these mixins wherever they can be applied.

Feel free to experiment and play around!

sass --watch --style expanded sass/application.scss:css/application.css

Advanced Sass

Inheritance

Mixin Efficiency

Mixin Output

.header {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.footer {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.feature a {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

.content {
  border-radius: 5px;
  padding: 5px 20px;
  /* ... */
}

Grouping Optimiztion

.header,
.footer,
.feature a,
.content {
  border-radius: 5px;
  padding: 5px 20px;
}

We kept running into a problem with mixins in that they weren't good for including styles that were exactly the same

Dynamic VS Static

We ended up with output like this

When really it'd be more efficent to just group these selectors together

Well of course Sass has tool to address this need

Advanced Sass Inheritance

@extend let's us group selectors together!

Sass

.message {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  @extend .message;
  @include message-colors($yellow);
}

.message-error {
  @extend .message;
  @include message-colors($red);
}

.message-notice {
  @extend .message;
  @include message-colors($green);
}

CSS Output

.message,
.message-alert,
.message-error,
.message-notice {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  border-color: goldenrod;
  color: goldenrod;
}

.message-error {
  border-color: darkred;
  color: darkred;
}

.message-notice {
  border-color: green;
  color: green;
}

When you @extend a class, it basically just adds that class to the group of the class you're extending

@extend will then add a second declaration for additional prop-vals (message-alert)

  • this is pretty huge, esp for modular architectures where you have base classes that get modified
  • typically what we've done in the past is chain selectors together "message message-alert"
  • with extensions, we can get back to more semantic classes rather than presentational ones.
  • your presentational classes come in via extensions - classitis in css vs html

Inheritance Setup

.message {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  @extend .message;
  @include message-colors($yellow);
}

.message-error {
  @extend .message;
  @include message-colors($red);
}

.message-notice {
  @extend .message;
  @include message-colors($green);
}
  • Any CSS class can be extended.
  • We reference a class to extend with the @extend directive.
  • Extended classes DO NOT need to be defined before they're referenced.
  • Extensions can be used with any other style rules.
  • You can nest within extended classes just like you can elsewhere.

It's possible to extend, I believe, any CSS selector, but I'm not sure why you'd want to

So let's look at that output one again...

Inheritance Output

If we don't need to apply both .message AND .message-alert to an element, then why do we even need .message anymore?!

Sass

.message {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  @extend .message;
  @include message-colors($yellow);
}

.message-error {
  @extend .message;
  @include message-colors($red);
}

.message-notice {
  @extend .message;
  @include message-colors($green);
}

CSS Output

.message,
.message-alert,
.message-error,
.message-notice {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  border-color: goldenrod;
  color: goldenrod;
}

.message-error {
  border-color: darkred;
  color: darkred;
}

.message-notice {
  border-color: green;
  color: green;
}

Inheritance Placeholders

Placeholders are a special type of selector denoted by a %. They can be @extended but will never compile to the CSS on their own.

Sass

%message {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  @extend %message;
  @include message-colors($yellow);
}

.message-error {
  @extend %message;
  @include message-colors($red);
}

.message-notice {
  @extend %message;
  @include message-colors($green);
}

CSS Output

.message-alert,
.message-error,
.message-notice, {
  border: 2px solid;
  margin-bottom: 1em;
  padding: 1em;
  text-align: center;
}

.message-alert {
  border-color: goldenrod;
  color: goldenrod;
}

.message-error {
  border-color: darkred;
  color: darkred;
}

.message-notice {
  border-color: green;
  color: green;
}

Placeholders are realy great for modular OOCSS frameworks where your styles are very abstract and tend to build on each other

.message, .message-list, .message-large

Placeholders or Mixins? Which to use?

The best advice would be: if you need variables, use a mixin. Otherwise, extend a placeholder. There are two reasons for this:

  • First, you can’t use variables in a placeholder. Actually you can but you cannot pass variables to your placeholders.
  • Second, how Sass handles mixins makes them very inconvenient when you don’t use them with contextual variables. To put it simply: Sass will duplicate the output of the mixin every time you use it.

@extend Let's develop it!

  • Create a placeholder partial in your base directory and @import it in your main .scss file.
  • Create a placeholder for %clearfix and @extend it on the appropriate selectors.Also remove the .clearfix class from the markup.
  • Create a .navlist--inline class like the one on the right.
  • @extend that class on elements that match the pattern.Hint: checkout the header and footer styles.
Let's get modular!
.navlist--inline {
  list-style-type: none;

  li {
    display: inline-block;
  }

  a {
    display: block;
  }
}

sass --watch --style expanded sass/application.scss:css/application.css

Advanced Sass

Math & Color

Advanced Sass Math Operators

  • Sass allows us to do basic math operations*, like:
    • + addition
    • - subtraction
    • * multiplication
    • / division
    • % modulus(remainder from division)
  • AND string concatenation
$title: "Girl Develop It";
$base-font-size: 16px;
$padding-default: 2em;

.header {
  padding: $padding-default / 2;
  font-size: $base-font-size * 2;

  &:before {
    content: "Welcome to " + $title;
  }
}

* Sass attempts to operate on mismatched units, but will throw an error if incompatible

Good: 20px * 2   |   Bad: 20px + 4em

This includes operations on numbers with units (px, em, pt, rem, etc.)*

We have a gotchya when it comes to division...

Math Division

CSS allows / to be used for separating values.

font: normal 1.5em/1.25 Tahoma, Arial, sans-serif;

SassScript maintains this support.There are three alternative ways to trigger division:

  • If any part of the equation is a variable: $padding / 2
  • If the equation is surrounded by parentheses: (350 / .25)
  • If the equation involves another expression: 2 + 3 / 10

Math Utilities

Sass also