DEV Community

Otavio Monteagudo
Otavio Monteagudo

Posted on • Edited on

SASS / SCSS in a Nutshell

SASS

  • Notes on Marksheet's SASS chapter, with a few additions of my own: https://marksheet.io/sass-scss-less.html
  • SASS Documentation: https://sass-lang.com/documentation/syntax/
  • CSS preprocessor that extends it; LESS is an alternative, so is SCSS
  • These include variables, functions, reusable components, syntax enhancers in general that generate CSS
  • We'll use SCSS, since it is very similar to CSS (basically a superset; all valid CSS is valid SCSS)
  • Main difference between CSS and SASS is that SASS uses indentation-based syntax (no curly braces)

SASS Features

  • variables: instead of repeating #fce473 throughout your CSS file, just set $yellow: #fce473 once (prevents repeating values)
  • nesting: CSS rules can be nested within each other (prevents repeating selectors)
  • partials: import commonly used properties without extra requests or heavier than needed CSS files
  • mixins: custom functions that can accept parameters and will prevent useless repetitions (prevents repeating properties)
  • extensions: an easy way to inherit the same properties of another selector (also prevents repeating properties)
  • operators: adding/substracting/multiplying/dividing values, like 960px / 4 or $space * 2

SASS Variables

  • Variables can be defined and reused
  • You can also define a set of variables and then point one variable to another, so say you want to change primary color from yellow to pink, just update $primary-color
// Defining color values
$yellow: #fce473;
$pink: #c71585;
$green: #32cd32;
$blue: #1d90ff;

// Defining color types
$primary-color: $green;

.quote{ border-left: 5px solid $primary-color;}
.button{ background: $primary-color;}
.sidebar a:hover{ border-bottom-color: $primary-color;}
.footer a{ color: $primary-color;}
Enter fullscreen mode Exit fullscreen mode

It is possible to change any type of content with variables:

// Colors
$yellow:              #fce473;
$pink:                #c71585;
$green:               #32cd32;
$blue:                #1d90ff;

$primary-color:       $blue;
$secondary-color:     $yellow;

// Fonts
$serif:               "Lora", "Playfair Display", Georgia, serif;
$sans-serif:          "Roboto", "Source Sans Pro", "Open Sans", Arial, sans-serif;
$monospace:           "Inconsolata", monospace;

$primary-font:        $sans-serif;
$secondary-font:      $serif;

// Spacing
$mobile-space:        10px;
$desktop-space:       35px;

// Also possible to add built-in manipulations for easy color transition & others, for instance:
$primary-blue: #1d90ff;
button {
  background: $primary;
  &:hover { background: lighten($primary-blue, 10%); }
  &:active { background: darken($primary-blue, 15%); }
}
Enter fullscreen mode Exit fullscreen mode

SASS Nesting

  • Meant to reuse same parent selector
  • Attempt to replicate HTML's nesting structure in CSS
  • Rule of thumb is to avoid nesting deeper than 3 levels, which would lead to over-specificity and large CSS output

For instance:

//scss
.parent{
  .child{}
}

// becomes in css
.parent .child{}
Enter fullscreen mode Exit fullscreen mode

So the nested .child element will be applied to elements nested withing elements with the .parent class.

What about elements that must have both classes/states at once?

  • Note that these generated CSS classes have no space between class names (so it only applies to elements with both classes)
//scss
.parent{
  &:hover{}
  &.other-class{}
}

// becomes in css
.parent:hover{}
.parent.other-class{}
Enter fullscreen mode Exit fullscreen mode

For reference: Generated CSS alongside SCSS selectors:

| CSS Selectors                        | SASS Selectors                      |
|--------------------------------------|-------------------------------------|
| `.post-content{}`                    | `.post-content {`                  |
| `.post-content a{}`                  | `  a {`                            |
| `.post-content a:hover{}`            | `    &:hover {}`                   |
| `.post-content aside{}`              | `  aside {}`                       |
| `.post-content blockquote{}`         | `  blockquote {}`                  |
| `.post-content code{}`               | `  code {}`                        |
| `.post-content h3{}`                 | `  h3 {`                           |
| `.post-content h3 a{}`               | `    a {}`                         |
| `.post-content h4{}`                 | `  h4 {`                           |
| `.post-content h4:before{}`          | `    &:before {}`                  |
| `.post-content h4:after{}`           | `    &:after {}`                   |
| `.post-content p{}`                  | `  p {`                            |
| `.post-content p:first-child{}`      | `    &:first-child {}`             |
| `.post-content p:last-child{}`       | `    &:last-child {}`              |
| `.post-content ul{}`                 | `  ul {`                           |
| `.post-content ul ul{}`              | `    ul {`                         |
| `.post-content ul ul ul{}`           | `      ul {}`                      |
| `.post-content dl{}`                 | `  dl {`                           |
| `.post-content dl:before{}`          | `    &:before {}`                  |
| `.post-content dl dt{}`              | `    dt {}`                        |
| `.post-content dl dd{}`              | `    dd {}`                        |
| `.post-content pre{}`                | `  pre {`                          |
| `.post-content pre code{}`           | `    code {}`                      |
| `.post-content table{}`              | `  table {`                        |
| `.post-content table tr{}`           | `    tr {`                         |
| `.post-content table tr:nth-child(2n){}` | `      &:nth-child(2n) {}`     |
| `.post-content table th,`            | `    th,`                          |
| `.post-content table td{}`           | `    td {`                         |
| `.post-content table th{}`           | `    th {}`                        |
| `.post-content table td.empty,`      | `      &.empty {}`                 |
| `.post-content table th.empty{}`     | `    }`                            |
| `.post-content table code{}`         | `    code {}`                      |
| `.post-content table pre{}`          | `    pre {`                        |
| `.post-content table pre:before{}`   | `      &:before {}`                |
Enter fullscreen mode Exit fullscreen mode

SASS Mixins

  • A mixin is basically a predefined set of properties and values that can be reused. Example:
@mixin overlay() {
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
}

/** This mixin called within this class... **/
.modal-background{
  @include overlay();
  background: black;
  opacity: 0.9;
}

/** ...will generate the following CSS: **/

.modal-background{
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  background: black;
  opacity: 0.9;
}
Enter fullscreen mode Exit fullscreen mode

X.7.4.1 Mixin Parameters

  • Mixins can also accept parameters; ex:
@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
      -ms-border-radius: $radius;
          border-radius: $radius;
}

/** This mixin called within this class... **/

.box{
  @include border-radius(3px);
}


/** ...will generate the following CSS: **/

.box{
  -webkit-border-radius: 3px;
     -moz-border-radius: 3px;
      -ms-border-radius: 3px;
          border-radius: 3px;
}
Enter fullscreen mode Exit fullscreen mode

X.7.4.2 Mixins Default Parameters

  • It is possible to add default and optional mixin parameters.
  • For instance, see this one meant to add labels in the top left of code snippet blocks:
@mixin label($text: "Code", $background: $yellow, $color: rgba(black, 0.5)) {
  position: relative;
  &:before{
    background: $background;
    color: $color;
    content: $text;
    display: inline-block;
    font-size: 0.6rem;
    font-weight: 700;
    height: 1rem;
    left: 0;
    letter-spacing: 0.1em;
    line-height: 1rem;
    padding: 0 0.5em;
    position: absolute;
    text-transform: uppercase;
    top: 0;
  }
}

/* used here: */

div.highlighter-rouge{
  @include label(); /* will use default "Code", $yellow and  rgba(black, 0.5) values */
  &.css{ /* will have specific values for codeblocks with css class */
    @include label("CSS", $blue, white);
  }
  &.scss{ /* will have specific values for codeblocks with scss class */
    @include label("SCSS", #c69, white);
  }
}

Enter fullscreen mode Exit fullscreen mode

SASS Extensions and Placeholders

  • These are very similar to mixins; the difference is that mixins write to css directly, and extensors and placeholders only reference it, so they are "more elegant"
  • Placeholders are basically silent classes that do not output to CSS unless extended
  • When in doubt, use mixins as they are the most straightforward
  • As a rule of thumb, use mixins when you need params and placeholders/extensors when you do not
  • As a rule of thumb, use extensions when the base class will also be used in HTML and extensions + placeholders when the base class will be absent from the HTML but classes extending from it will be in the HTML

  • Extend syntax (allows to inherit CSS properties):

// scss
.small-uppercase{
  color: lightslategrey;
  font-size: 10px;
  letter-spacing: 0.1em;
  line-height: 12px;
  text-transform: uppercase;
}

.modal-background{
  @extend .small-uppercase;
}

.product-link{
  @extend .small-uppercase;
}

// generated css
.small-uppercase,
.modal-background,
.product-link,{
  color: lightslategrey;
  font-size: 10px;
  letter-spacing: 0.1em;
  line-height: 12px;
  text-transform: uppercase;
}
Enter fullscreen mode Exit fullscreen mode
  • Note how .small-uppercase was also generated as a class. What if we don't want to do this, to keep our CSS as flat and clean as possible?
// scss
%small-uppercase{
  color: lightslategrey;
  font-size: 10px;
  letter-spacing: 0.1em;
  line-height: 12px;
  text-transform: uppercase;
}

.modal-background{
  @extend %small-uppercase;
}

.product-link{
  @extend %small-uppercase;
}

.image-pattern{
  @extend %small-uppercase;
}

// generated css
.modal-background,
.product-link,
.image-pattern{
  color: lightslategrey;
  font-size: 10px;
  letter-spacing: 0.1em;
  line-height: 12px;
  text-transform: uppercase;
}
Enter fullscreen mode Exit fullscreen mode
Use Mixins When Use Extends When
Need parameters Static styles
Output varies per instance Reducing duplicated styles

SASS Control Directives

  • SASS offer directives such as loops and conditionals
  • These can be used to generate repetitive styles efficiently
// For loops
@for $i from 1 through 4 {
  .mt-#{$i} { margin-top: #{$i * 5}px; }
}

// Each loops
$colors: (primary: blue, secondary: green);
@each $name, $color in $colors {
  .text-#{$name} { color: $color; }
}

// If statements
@mixin theme($dark: false) {
  @if $dark { background: black; }
  @else { background: white; }
}
Enter fullscreen mode Exit fullscreen mode

SASS Imports & Partials

  • The @import directive allows you to include content of a file into another
  • This however can create a new HTTP request every time it is called
  • SASS solves this by including the file in the CSS itself
  • You can import .sass, .scss and .css files; it does not even need an extention, SASS will treat it as a compatible file.
  • Prefix partials with an underscore, like "_filename.scss" so they don't get compiled into their own CSS file.
  • Note that every time you import, code will be duplicated, so keep imports to a minimum. See 7-1 Architecture: https://www.easeout.co/blog/2020-08-25-structuring-your-sass-projects/
/* _colors.scss */
$myPink: #EE82EE;
$myBlue: #4169E1;
$myGreen: #8FBC8F;


/* main.scss */
@import "colors";

body {
  font-family: Helvetica, sans-serif;
  font-size: 18px;
  color: $myBlue;
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)