a few
others...
Two primary implementations of the Sass compiler:
*LibSass has wrappers for Go, Java, JavaScript, Lua, .Net, Node, Perl, PHP, Python, Scala, and even Ruby.
npm install node-sass
(npmjs.com)
node-sass input.scss output.css
node-sass --watch input.scss output.css
node-sass --watch sass/ --output stylesheets/
.sass
$font-stack: Helvetica, sans-serif
$primary-color: #333
body
font: 100% $font-stack
color: $primary-color
.scss
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}
| string | "Hello world" , kittens |
| number | 42 , 1337px |
| color | #CF649A , pink , rgb(1, 33, 7) |
| list | (a, b, c) , a b c |
| map | (a: 1, b: 2) |
| bool | true or false |
| null | null |
$padding: 10px;
.module {
$padding: 20px;
padding: $padding; // 20px
}
.foo {
padding: $padding; // 10px
}
$padding: 10px;
.module {
$padding: 20px !global;
padding: $padding; // 20px
}
.foo {
padding: $padding; // 20px
}
Use the !global flag to override a global variable
$margin: 30px;
$margin: 40px !default;
.module {
margin: $margin; // 30px
}
.foo {
margin: $margin; // 30px
}
Use the !default flag to assign a variable if it doesn’t have a value yet
#{}
$name: 'world';
.foo:before { content: 'Hello ' + $name + '!'; /* Hello world! */}
.bar:before { content: 'Hello #{$name}!'; /* Hello world! */}
.main {
$sidebar-width: 300px;
width: calc(100% - $sidebar-width); // calc(100% - $sidebar-width)
}
.main {
$sidebar-width: 300px;
width: calc(100% - #{$sidebar-width}); // calc(100% - 300px)
}
$section: 'home';
.section-#{$section} {
background: transparent;
}
!global, !default
mix($color1, $color2, [$weight]), lighten($color,
$amount), darken($color, $amount), invert($color), transparentize($color, $amount),
quote($string), str-length($string), str-slice($string,
$start-at, [$end-at]), to-upper-case($string),
round($number), ceil($number), floor($number), random([$limit]), length($list),
nth($list, $n), append($list1, $val, [$separator]), index($list, $value),
map-get($map, $key), map-values($map), keywords($args),
selector-nest($selectors…), selector-parse($selector), type-of($value),
variable-exists($name), function-exists($name), unit($number),
call($name, $args…), unique-id()
and many more ...
// `$a` is mandatory and `$b` is optional (default value being 2)
@function multiply($a, $b: 2) {
@return ($a * $b);
}
// CDN URL where all assets are served from
$base-url: 'http://cdn.example.com/assets/';
// Native `url(..)` function wrapper
@function asset($base, $type, $path) {
@return url($base + $type + $path);
}
// Returns URL to an image based on its path
@function image($path, $base: $base-url) {
@return asset($base, 'images/', $path);
}
.foo {
background-image: image('kittens.png');
}
.foo {
background-image:
url('http://cdn.example.com/assets/images/kittens.png');
}
A mixin is a function that can output
code rather than return a result.
/// Sizing mixin from width and height
/// If height is omitted, same as width
@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
// Usage
.foo {
@include size(100%, 42px);
}
.bar {
@include size(100px);
}
.foo {
width: 100%;
height: 42px;
}
.bar {
width: 100px;
height: 100px;
}
@content directive
@mixin size($width, $height: $width) {
width: $width;
height: $height;
@content;
}
.foo {
@include size(100%, 42px) {
font-size: 2rem;
}
}
.foo {
width: 100%;
height: 42px;
font-size: 2rem;
}
@content to pass styles to a mixin
@if $condition {
// Then do something
} @else {
// Do something else
}
@if $condition-a {
// Then do something
} @else if $condition-b {
// Then do something else
} @else {
// Do something else
}
$foo: true;
$bar: false;
@if $foo and $bar {
// Statement doesn't match
}
@if $foo or $bar {
// Statement does match
}
$foo: if($error, red, green);
@for $i from 1 through 5 {
// Code to execute 5 times, where `$i` equals: 1, 2, 3, 4, 5
}
@for directivefromthrough (end
index inclusive) or the keyword to (end index exclusive)
$start: 2;
$list: (20em, 17em, 15em, 12em);
@for $index from $start to length($list) {
// Code to execute 2 times, where `$index` equals: 2, 3
}
$collection: (a b c d e f g);
@each $item in $collection {
// Do something with `$item`
}
@each directivein
$preprocessors: (sass, #C6538C),
(less, #1D365D),
(stylus, #333333);
@each $preprocessor, $color in $preprocessors {
.preprocessor-#{$preprocessor} {
color: $color;
}
}
$number: 4;
@while ($number > 0) {
// Do something with `$number`
$number: $number - 1;
}
@while directive
.container {
margin: 0 auto;
max-width: 42em;
padding: 0 1em;
}
.container p,
.container li {
text-indent: 1em;
}
.container {
margin: 0 auto;
max-width: 42em;
padding: 0 1em;
p, li {
text-indent: 1em;
}
}
&
.foo {
margin: 1em;
.bar { margin: 0 auto; }
}
.foo { margin: 1em; }
.foo .bar {
margin: 0 auto;
}
.foo {
margin: 1em;
&.bar { margin: 0 auto; }
}
.foo { margin: 1em; }
.foo.bar {
margin: 0 auto;
}
a {
color: deeppink;
&:hover { color: hotpink; }
&:before { content: '42 '; }
}
.navigation li {
display: block;
}
@media screen and (min-width: 42em) {
.navigation li {
display: inline-block;
}
}
.navigation li {
display: block;
@media screen and (min-width: 42em) {
display: inline-block;
}
}
.navigation {
display: block;
@supports (display: flex) {
display: flex;
}
}
@media and @supports)
@extend Directive@extend
@extend is the most powerful, dangerous and
controversial feature in Sass.
.message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
@extend .message;
border-color: green;
}
.error {
@extend .message;
border-color: red;
}
.message, .success, .error {
border: 1px solid #cccccc;
padding: 10px;
color: #333;
}
.success {
border-color: green;
}
.error {
border-color: red;
}
%message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
@extend %message;
border-color: green;
}
.error {
@extend %message;
border-color: red;
}
.success, .error {
border: 1px solid #cccccc;
padding: 10px;
color: #333;
}
.success {
border-color: green;
}
.error {
border-color: red;
}
.hoverlink {
@extend a:hover;
}
a {
&[href*='http://'] {
&:hover {
text-decoration: underline;
}
}
}
a[href*='http://']:hover,
[href*='http://'].hoverlink {
text-decoration: underline;
}
Don’t try this at home!
Specificity
%large { font-size: 4rem; }
%small { font-size: 0.75rem; }
.message { @extend %small; }
.important { @extend %large; }
.important { font-size: 4rem; }
.message { font-size: 0.75rem; }
Media Query Madness
@extend fails to work at all across media queries. Selectors inside one media query cannot extend
selectors outside that same query (and vice versa).
Don’t try this at home!
Hard-to-Read Output
.typography {
.bold { font-weight: bold; }
}
.widget-warning strong { @extend .bold; }
.widget-info strong { @extend .bold; }
.alert-error .important { @extend .bold; }
.typography .bold,
.typography .widget-warning strong,
.widget-warning .typography strong,
.typography .widget-info strong,
.widget-info .typography strong,
.typography .alert-error .important,
.alert-error .typography .important {
font-weight: bold;
}
@extend"With great power comes great responsibility"
@extend just in an encapsulated environment
@extend, use a mixin, it will do the
job
sass/
|
|– config/
| |– _colors.scss
| …
|
|– layout/
| |– _navigation.scss
| …
|
|– modules/
| |– _calendar.scss
| |– _contact.scss
| …
|
|– patterns/
| |– _buttons.scss
| …
|
|- main.scss
// main.scss
@import 'config/_colors.scss';
@import 'patterns/_buttons';
@import 'layout/navigation';
@import 'modules/calendar',
'modules/contact';
Scalable and Modular Architecture for CSS
SMACSS uses five categories for organizing CSS:
Use a prefix to differentiate between Layout, State, and Module rules.
l- or layout-
is- as in is-hidden or
is-collapsed for state rules
module- for every module would be needlessly verbose, so no
prefixes for modules
Object Oriented CSS
.primary-header) instead of tags (h1), you have more flexibility.
Inverted Triangle CSS
CSS Specificity
Block, Element, Modifier
Blocks are components of any size, and can be nested inside each other. Blocks are reusable and independent.
Block class names may consist of letters, digits and dashes.
...
.block {
color: hotpink;
}
Elements are the constituent parts that belong to a specific block.
Element classes are formed as block name plus two underscores (__) plus element name.
...
...
...
.block {
color: hotpink;
}
.block__elem {
color: deeppink;
}
.block {
color: hotpink;
&__elem {
color: deeppink;
}
}
Modifiers are flags on blocks or elements that change their appearance, behavior or state.
Modifier class names are formed as block name plus two dashes (--) plus modifier name or element name plus two dashes plus modifier name.
...
...
...
...
.block { ... }
.block--mod { ... }
.block__foo { ... }
.block__foo--mod { ... }
.block__bar { ... }
.block--mod .block__bar { ... }
.block { ...
&--mod { ... }
&__foo { ...
&--mod { ... }
}
&__bar { ... }
&--mod &__bar { ... }
}