Created by Yogesh Kumar / @yoku_2010
Why Sass / SCSS?
.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;
}
HEX Colors
Border Radius
Padding
Selectors
.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;
}
$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: $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;
}
.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;
/* ... */
}
@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;
// ...
}
.header {
/* ... */
}
.header a {
/* ... */
}
.header a:hover {
/* ... */
}
.footer {
/* ... */
}
.footer a {
/* ... */
}
.footer a:hover {
/* ... */
}
.feature a {
/* ... */
}
.feature a:hover {
/* ... */
}
.content {
/* ... */
}
.header {
// ...
a {
// ...
&:hover {
// ...
}
}
}
.footer {
// ...
a {
// ...
&:hover {
// ...
}
}
}
.feature a {
// ...
&:hover {
// ...
}
}
.content {
// ...
}
.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;
}
$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;
}
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 DocumentationCSS Extension CSS Preprocessor Sass Script Language Sass Script Interpreter
Sass CSS
$black: #000
$white: #fff
.this
color: $black
background: $white
.that
color: $white
background: $black
.this, .that
display: block
&:hover
border: 1px solid
$black: #000;
$white: #fff;
.this {
color: $black;
background: $white;
}
.that {
color: $white;
background: $black;
}
.this, .that {
display: block;
&:hover {
border: 1px solid;
}
}
The Workflow
OS X? Lucky you, it's preinstalled!
Windows? Try RubyInstaller
Linux? You know what to do.
Sass$ gem install sass
Sass CSS
$ sass source.scss output.css
$ sass source_dir output_dir
$ sass --watch source.sass:output.css
This is the best thing EVER.
$ sass source.scss output.css
Compile source.scss to output.css. Will fail if output directory 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.
See Example
Sass Basics
<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>
.navigation {
float: right;
li {
display: inline-block;
list-style-type: none;
margin-left: 1.5em;
}
a {
display: block;
text-decoration: none;
}
}
.navigation {
float: right;
li {
display: inline-block;
list-style-type: none;
margin-left: 1.5em;
}
a {
display: block;
text-decoration: none;
}
}
.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.
Mirroring HTML nesting is SUPER easy.
body {
.header {
.navigation {
ul {
li {
a {
// ...
}
}
}
}
}
}
body .header .navigation ul li a {
/* ... */
}
allows us to reference the current parent selector(s) via the ampersand character:
a {
color: #beedee;
&:hover {
color: #cbbebb;
}
&.btn {
background: #deede6;
}
.btn {
display: block;
}
}
a {
color: #beedee;
}
a:hover {
color: #cbbebb;
}
a.btn {
background: #deede6;
}
a .btn {
display: block;
}
The &
selector can follow other selectors. This will override the parent element's (&
) styles when it exists within the preceding selector.
a {
.footer & {
text-decoration: none;
span {
opacity: .5;
}
}
span {
.navigation & {
display: block;
}
}
}
.footer a {
text-decoration: none;
}
.footer a span {
opacity: .5;
}
.navigation a span {
display: block;
}
The &
selector can also be combined with strings.
PERFECT for BEM, child elements, states, and modifications.
.module {
&__child {
margin-bottom: 1em;
}
&--modifier {
display: inline;
}
}
.module__child {
margin-bottom: 1em;
}
.module--modifier {
display: inline;
}
The &
contents can also be accessed as a string/list
and used in SassScript.
.thing.thang {
.thung {
content: &;
content: &--mod;
content: selector-append(&, '--mod');
&--mod { content: 'here'; }
}
}
.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.
You can also nest namespaced properties
a {
border: {
color: #deedee;
style: solid;
width: 2px;
}
}
a {
border-color: #deedee;
border-style: solid;
border-width: 2px;
}
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.
@import "vars";
@import "compass";
@import "fontawesome";
@import "utilities";
@import "grid";
@import "base";
@import "modules/all";
@import "pages/all";
@import
takes a path to a Sass resource, the file extension is optional.
These @import
s 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";
@import "vars";
@import "lib/compass";
@import "lib/fontawesome";
@import "utilities";
@import "grid";
@import "base";
$ sass sass/application.scss css/application.css
$ sass sass/ css/
$ sass sass/ css/
.css
on their own, they must be @import
ed_vars.scss
is a separate sheet for all your variables and settingslib
is a separate folder for other librariesmodules
is a separate folder for various modulespages
is a separate folder for all pages css_all.scss
is often used to import collections of similar imports// 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";
You can DRY up @import
s by grouping them together with comma separation.
// Variables
@import "vars";
// Libraries
@import "lib/compass",
"lib/fontawesome";
// Application
@import "base/all",
"modules/all",
"pages/all";
Variables
Variables are defined as CSS prop/val pairs: $property: value;
Variables are then referenced by their $
-prefixed names.
$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; }
a {
color: #095169;
padding: 1em;
}
a:hover {
color: rgba(0,0,0,.5);
background: #095169;
}
p {
padding-bottom: 1em;
}
$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);
You can redeclare variables to override previous values
$border-width: 2px;
$border-width: 4px;
a {
border: $border-width solid $teal;
}
a {
border: 4px solid #095169;
}
$border-width: 4px; // Global
a {
$color: orange; // Local
border: $border-width solid $color;
}
p {
border: $border-width solid $color;
// ERROR!! Undefined variable "$color"
}
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.
Variables can be injected into selectors,
property names and values, and strings via #{$variable}
$side: left;
.box-#{$side} {
border-#{$side}: 1px solid #ccc;
&:before {
content: "It's on the #{$side} side";
}
}
.box-left {
border-left: 1px solid #ccc;
}
.box-left:before {
content: "It's on the left side";
}
$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;
}
// 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;
}
Math & Color
+
addition-
subtraction*
multiplication/
division%
modulus* Sass attempts to operate on mismatched units, but will throw an error if incompatible
Good: 20px * 2
| Bad: 20px + 4em
$title: "yokutalks";
$base-font-size: 16px;
$padding-default: 2em;
.header {
padding: $padding-default / 2;
font-size: $base-font-size * 2;
&:before {
content: "Welcome to " + $title;
}
}
This includes operations on numbers with units (px, em, pt, rem, etc.)*
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 ways to trigger division:
$padding / 2
(350 / .25)
2 + 3 / 10
Sass also comes with a set of math functions:
abs($num)
- absolute valueceil($num)
- round up to closest whole numberfloor($num)
- round down to closest whole numberpercentage($num)
- convert to percentageround($num)
- round to closest whole number max($list)
- maximum list value min($list)
- minimum list valueWe can also use math to manipulate colors. Math operations on colors work on pieces (r, g, b).
.addition {
color: #555555 + #112233; // => #667788
}
.subtraction {
color: #555555 - #112233; // => #443322
}
.multiplication {
color: #555555 * 2; // => #aaaaaa
}
.division {
color: (#555555 / 2); // => #2a2a2a
}
Sass comes with a set of color functions.
rgba($hex, $alpha)
lighten($color, $percent)
darken($color, $percent)
saturate($color, $percent)
desaturate($color, $percent)
mix($color1, $color2)
grayscale($color)
invert($color)
complement($color)
Here's a tool to help color output.
Sass Advanced
Variables let you reuse single values.
Mixins let you reuse blocks of styles.
.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;
}
@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;
}
@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;
// ...
}
@mixin
directive.@include
directive.$header-color: #455667;
@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;
}
.header {
border-radius: 5px;
padding: 5px 20px;
color: #455667;
}
.footer {
border-radius: 5px;
padding: 5px 20px;
}
.feature a {
border-radius: 5px;
padding: 5px 20px;
}
.content {
border-radius: 5px;
padding: 5px 20px;
}
Mixins are great for repeated blocks of styles
where the values differ from case to case.
@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);
// ...
}
.header {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
/* ... */
}
.footer {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
/* ... */
}
You can also set an argument's default value,
making it optional to pass one in.
@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);
// ...
}
.header {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
/* ... */
}
.footer {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
/* ... */
}
Comma separated, order matters.
@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);
// ...
}
.header {
border-radius: 5px;
padding: 20px;
/* ... */
}
.footer {
border-radius: 20px;
padding: 40px;
/* ... */
}
Optional arguments (ones with defaults) must be last in the set.
@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);
// ...
}
.header {
border-radius: 5px;
padding: 20px;
color: #aaa;
font-size: 24px;
/* ... */
}
.footer {
border-radius: 20px;
padding: 40px;
color: #ccc;
font-size: 12px;
/* ... */
}
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);
}
@mixin toolbar-border($side, $width: 2px) {
border-#{$side}: $width solid $toolbar-border;
}
.sidebar--left {
@include toolbar-border("right");
}
.sidebar--right {
@include toolbar-border("left");
}
.sidebar--left {
border-right: 2px solid #213213;
}
.sidebar--right {
border-left: 2px solid #213213;
}
@mixin margin--horz($left, $right: $left) {
margin-left: $left;
margin-right: $right;
}
@mixin margin--vert($top, $bottom: $top) {
margin-bottom: $bottom;
margin-top: $top;
}
.module { @include margin--vert(1em, 3em); }
Inheritance
.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;
/* ... */
}
.header,
.footer,
.feature a,
.content {
border-radius: 5px;
padding: 5px 20px;
}
@extend
let's us group selectors together!
.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);
}
.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;
}
.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);
}
@extend
directive.
If we don't need to apply both .message
AND .message-alert
to an element, then why do we even need .message
anymore?!
.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);
}
.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;
}
Placeholders are a special type of selector denoted by a %
. They can be @extend
ed but will never compile to the CSS on their own.
%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);
}
.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;
}
%btn {
// ...
}
%btn--primary {
background: $btn--primary--bg;
border-color: $btn--primary--border;
color: $btn--primary--color;
}
// ...
@mixin button-setup($type) {
@extend %btn;
@extend %btn--#{$type};
&:focus { @extend %btn--#{$type}; }
&:hover { @extend %btn--#{type}--hover; }
&.disabled {
@extend %disabled;
&:hover { @extend %btn--#{$type}; }
}
}
.btn--primary { @include button-setup("primary"); }
.btn--secondary { @include button-setup("secondary"); }
.btn--tertiary { @include button-setup("tertiary"); }
// background: $btn--#{$type}--bg; => Undefined variable: "$btn--"
so when do I use these...?
Are mixins without arguments bad?
Since they duplicate code, on both sides?
@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;
}
.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;
}
this better?
%rounded-box {
border-radius: 5px;
padding: 5px 20px;
}
.header {
@extend %rounded-box;
}
.footer {
@extend %rounded-box;
}
.feature a {
@extend %rounded-box;
}
.content {
@extend %rounded-box;
}
.header,
.footer,
.feature a,
.content {
border-radius: 5px;
padding: 5px 20px;
}
Is this better?
.header, .footer, .feature header a, .content, #taco ul a, .hipster dl,
[class="btn--"], .comment .comment__body .comment__quote, .card__header,
.card--standard, .card--transFooter, .card--featured, .card--scroller,
.card--static, .card--ebook, .card--transFooter .card__content
.container .wrapper, .link--fancy, #badthing, .nope.probably a.not span.good,
article header, .article .header, [class*='rabbit'], .party .at .codemash,
#hashtag, .dot, [class*="hooligans"], [class*='making'].up.classes.is-hard,
.julie + .rocks, #made.up, .bourbon, a div i span, [id="where-the-party"],
.this .could [class*="actually-happen"], #actually.it .happens.alot,
#seriously [class*="this"].is a.problem, .it .can.get #really .out-of-hand {
border-radius: 5px;
padding: 5px 20px;
}
Directives
Sass let's us define
custom functions.
@function fluidize($target, $context) {
@return ($target / $context) * 100%;
}
.sidebar {
width: fluidize(350px, 1000px);
// => width: 35%;
}
@function
directive.@return
directive.
Sass let's us set
conditions.
$theme: light;
body {
@if $theme == dark {
background: #000;
} @else if $theme == dark-mid {
background: #4f4f4f;
} @else if $theme == light-mid {
background: #afafaf;
} @else {
background: #fff;
}
}
@if
directive, then give it a comparison to evaluate@else if
for additional comparisons@else
as a fallback if all prior comparisons evaluate to null
or false
Comparators include:
* only compare numbers
==
equal to>
greater than>=
greater than or equal to!=
not equal to<
less than<=
less than or equal to
Sass let's us
loop through lists.
$themes: dark dark-mid light-mid light;
@each $theme in $themes {
.theme-#{$theme} {
@include theme-colors($theme);
}
}
// .theme-dark {
// background: #000;
// color: #fff;
// }
// .theme-dark-mid {
// background: #444;
// color: #eee;
// }
// ...
@each
directive takes the form of:
@each $var in <list>
$var
can be any variable name<list>
could be a list, or a variable storing one
Sass lets us
loop through # ranges.
@for $i from 1 through 12 {
.grid-col-#{$i} {
width: $grid-col-width * $i;
}
}
// .grid-col-1 {
// width: 60px;
// }
// .grid-col-2 {
// width: 120px;
// }
@for
loops;
@for $var from <start> through <end>
@for $var from <start> to <end>
$var
can be any variable name<start>
and <end>
can be an integer, or a variable storing one
Sass lets us
loop conditionally.
$i: 1;
@while $i <= 12 {
.grid-col-#{$i} {
width: $grid-col-width * $i;
}
$i: $i + 1;
}
// .grid-col-1 {
// width: 60px;
// }
// .grid-col-2 {
// width: 120px;
// }
// ...
@while
directives take the form of:
@while <comparison>
false
<comparison>
variable will often be an integer that you increment, but it could be any data type that you modify as you goMaps
Maps give us key-value pairings.
$mymap: (
key1: value1,
key2: value2,
key3: value3
);
map
functions.$eye_color: (
jeremy: #0989cb,
beth: #8666ae,
sarah: #02bba7
);
$font: (
jeremy: Helvetica,
beth: Verdana,
sarah: Times
);
@each $key, $value in $eye_color {
.#{$key} {
background: $value;
font-family: map-get($font, $key);
}
}
.jeremy {
background: #0989cb;
font-family: Helvetica;
}
.beth {
background: #8666ae;
font-family: Verdana;
}
.sarah {
background: #02bba7;
font-family: Times;
}
map-get($map, $key)
map-merge($map1, $map2)
map-remove($map, $keys...)
map-keys($map)
map-values($map)
map-has-key($map, $key)
Putting it all together.
$icons: (
checkmark: "\e600",
plus: "\e601",
minus: "\e602"
);
@each $name, $value in $icons {
.icon--#{$name} {
&:before { content: $value; }
}
}
$messages: (
error: (#d82d2d, #666),
success: (#52bf4a, #fff),
warning: (#c23435, #fff)
);
@each $name, $colors in $messages {
$bg: nth($colors, 1);
$color: nth($colors, 2);
.message--#{$name} {
background-color: $bg;
color: $color;
}
}
$layers: (
bottom: 1,
middle: 5,
top: 10
);
@mixin layer($name) {
z-index: map-get($layers, $name);
};
.overlay {
@include layer(middle);
}
.lightbox {
@include layer(top);
}
$font--sizes: (
( base, $base-font-size, $base-line-height ),
( small, $base-font-size*.75, $base-line-height*.75 ),
( large, $base-font-size*1.5, $base-line-height*1.5 )
);
@mixin typeset($level) {
@each $item in $font--sizes {
@if $level == nth($item, 1) {
font-size: nth($item, 2);
line-height: nth($item, 3);
}
}
}
@each $set in $font--sizes {
$size: nth($set, 1);
#{"%size--" + $size} {
@include typeset($size);
}
}
$themes: (
gray: (
button-bg: #ccc,
button-color: #f2f2f2
),
brown: (
button-bg: #ab906b,
button-color: #ecdac3
)
);
@function setStyle($theme, $property) {
@return map-get(map-get($themes, $theme), $property);
}
.btn {
@each $key, $value in $themes {
.theme--#{$key} & {
background: setStyle($key, button-bg);
color: setStyle($key, button-color);
}
}
}
Media Queries
@media screen and (max-width: 500px) {
.sidebar {
float: none;
width: 100%;
}
}
Media queries allow you to conditionally load styles based on things like page width, orientation, and even environmental lighting.
Responsive Web Design!
You nest declarations within media queries.
.sidebar {
float: left;
width: 35%;
@media screen and (max-width: 800px) {
width: 25%;
}
@media screen and (max-width: 500px) {
float: none;
width: 100%;
a { display: block; }
}
}
In Sass, you can nest your media queries under any declaration.
OMG THIS IS SO AWESOME.
It becomes easy to see exactly how the module is morphing through breakpoints.
Media Queries "bubble up" beyond their containing declarations.
.sidebar {
float: left;
width: 35%;
@media screen and (max-width: 800px) {
width: 25%;
}
@media screen and (max-width: 500px) {
float: none;
width: 100%;
a { display: block; }
}
}
.sidebar {
float: left;
width: 35%;
}
@media screen and (max-width: 800px) {
.sidebar {
width: 25%;
}
}
@media screen and (max-width: 500px) {
.sidebar {
float: none;
width: 100%;
}
.sidebar a { display: block; }
}
$break-large: 800px;
$break-small: 500px;
.sidebar {
float: left;
width: 35%;
@media screen and (max-width: $break-large) {
width: 25%;
}
@media screen and (max-width: $break-small) {
float: none;
width: 100%;
a { display: block; }
}
}
Breakpoints are often obscure numbers, and we repeat them all over the place.
Of course, we should make them variables!
$mobile-med: "screen and (min-width: 480px)";
$tablet-port: "screen and (min-width: 768px)";
.sidebar {
float: left;
width: 35%;
@media #{$tablet-port} {
width: 25%;
}
@media #{$mobile-med} {
float: none;
width: 100%;
a { display: block; }
}
}
Why not make the entire media query a variable?
We have to interpolate#{}
our variables so that Sass compiles them.
@mixin respond-to($breakpoint) {
@if $breakpoint == tablet-large {
@media only screen and (max-width: $width-large) {
@content;
}
} @else if $breakpoint == mobile-large {
@media only screen and (max-width: $width-small) {
@content;
}
}
}
.sidebar {
width: 35%;
@include respond-to(tablet-large) {
width: 25%;
}
@include respond-to(mobile-large) {
width: 100%;
a { display: block; }
}
}
The @content
directive allows us to pass entire blocks of styles to a mixin, which then outputs that content back into the declaration that called the mixin.
WAT?
A Short & Lovely Demo
Wrap Up
"Compass is an open-source CSS Authoring Framework." ~ Compass
"A simple and lightweight mixin library for Sass." ~ Bourbon
"Responsive grids for Compass." ~ Susy
I'm here to help