On Github gdila / sass-shop
Wifi Network:
Password:
alexhasnicehair.com | @alexjvasquez | alexjvas@gmail.com
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."
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.
What is Sass?
Syntactically Awesome StyleSheets
Like CSS, but AWESOME
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.
.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; }
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...
.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; // 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?
.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; // ... }
It looks like we've got a default box style
What if we could set those defaults in one place and reference it elsewhere?
.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 { // ... }
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?
.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; }
Colors (vars), Border Radius + Padding (mixin), Selectors (nesting)
Alright, so now that we've gotten a taste of it in action, let's get an official definition
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 DocumentationAny valid CSS file is a valid Sass file
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.
.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.
The Sass Workflow
$ gem install sass
(aka Compiling Sass)
Sass CSS
$ sass source.scss output.css
$ sass source_dir output_dir
So let's get a more visual representation...
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!
I'm going to get into some code to explain the style option more...
Exercise - Section 2
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.
Sass Basics
Alright, so now that we know generally what Sass is and how it works
let's get into the basics
Imports are critical for a modular and organized architecture
HTML has a clear hierarchy - elements are nested.
We can apply the same concept in Sass.
<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; } }
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...
.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.
So, there's kid of a gotchya with nesting though...
Mirroring HTML nesting is SUPER easy.
Overly verbose and overly specific.
Rule of thumb or "the Inception Rule": no more than 3 levels deep.
body { .header { .navigation { ul { li { a { // ... } } } } } }
body .header .navigation ul li a { // ... }
Work WITH the cascade, not against it
Nesting too deeply results in specificity nightmares and fragile, unmaintainable code
Sass 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 ampersand will reference the entire chain of parent selectors
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; }
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
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; }
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
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.
this is some pretty advanced stuff that you probably won't use for a while
You can also nest namespaced properties
a { border: { color: #deedee; style: solid; width: 2px; } }
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...
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
Variables
We already saw a sampling of variables when we talked about repetition, so we know that they help to
So let's see what ELSE we can use variables for
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 are defined à la 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; }
as you can see, we've set a few different types of data - there are 7 main data types that Sass accepts
$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
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; }
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
The !default flagMeans: set if it does not already have a value
$border-width: 2px; $border-width: 4px !default; a { border: $border-width solid $teal; }
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
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.
$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
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.
$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
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"; }
We'll see how this can become pretty handy later on
$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; }
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
DRY Up Your Styles
Add Variables
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
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
@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...
@import "vars"; @import "lib/compass"; @import "lib/fontawesome"; @import "utilities"; @import "grid"; @import "base";
$ sass sass/screen.scss css/screen.css
$ sass sass/ 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...
$ sass sass/ css/
// 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
sass --watch --style expanded sass/application.scss:css/application.css
Advanced Sass
Variables let you reuse single values.
Mixins let you reuse blocks of styles.
So let's look at some code...
.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; }
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...
@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; // ... }
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
@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: $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....
.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; }
It'd actually be more efficient just to group the classes together.
So what's a good use case for mixins then...
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 are great for repeated blocks of styleswhere 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; // ... }
I mentioned before that mixins can accept arguments
Dynamic VS Static
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; // ... }
Arguments are required, unless you set a default
Now let's go a level deeper here...
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; // ... }
Now what if we want to set defaults for all or some of these mixin variables?...
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; // ... }
Remembering what the arguments are and exactly what order they're in can be a pain.
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 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; }
This helps us create even more dynamic mixins
We can do this sort of interpolation all over the place, not just in mixins
Feel free to experiment and play around!
sass --watch --style expanded sass/application.scss:css/application.css
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; }
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
@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; }
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)
.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); }
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...
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 @extended 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; }
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
The best advice would be: if you need variables, use a mixin. Otherwise, extend a placeholder. There are two reasons for this:
.navlist--inline { list-style-type: none; li { display: inline-block; } a { display: block; } }
sass --watch --style expanded sass/application.scss:css/application.css
Math & Color
$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...
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:
Sass also