css • SASS.scss preprocessor - martindubenet/wed-dev-design Wiki

Compiling via Dart Sass

Dart is the new libSass
Since 2021 LibSASS is deprecated in favor of Dart Sass
.

Run npm i sass --save-dev

  "devDependencies": {
      "sass": "^1.50.0"
  },

A common practice is to compile SASS and Javascript sources files « ./src » to a « ./dist » repository.

Originals Compiled
/src/sass/
/src/javascript/main.js
/dist/css/
/dist/js/main.js

Setup Sass for npm CLI

Set npm «./package.json» to compile from/to the two common repositories.

{
  "name": "theme",
  "version": "1.0.1",
  "description": "PROJECT_DESCRIPTION",
  "author": "PROJECT_AUTHOR",
  "license": "ISC",
  "main": "assets/js/main.js",
  "devDependencies": {
    "sass": "^1.50.0"
  },
  "scripts": {
    "watch": "sass src/sass:assets/css --embed-sources --style=compressed --quiet --watch",
    "compile": "sass src/sass:assets/css --embed-sources --style=compressed"
  }
}

 

Sass to CSS variables

Interpolation #{$}

Since Dart compiler is the standard #{$} interpolation is required for parsing Sass variables as CSS var().

Read this post about «CSS4 Variables with Fallbacks Using Sass» from Jake Albaugh to understand how to interpolate Sass variables within :@root{} CSS variables.

// Sass variable
$sass_var: #FEFEFE;

// Sass map
$array-name: (
  "array-key0": #FEFEFE,
  "array-key1": #EEE,
  "array-key2": #FFF,
);

// CSS variables
:root {
  @each $arrayKey, $arrayValue in $array-name {
    --cssVar-#{$arrayKey}: #{$arrayValue};
  }
  --cssVar: map-get($array-name, "array-key0");
  --cssVar: #{$sass_var};
  --cssVar: #FEFEFE;
}

// CSS Style
.selector{
  .color: var(--varCss);
}

Migration tool

https://sass-lang.com/documentation/cli/migrator

  1. npm install -g sass-migrator
  2. assign the migration name to a specific file: sass-migrator module style.scss.

Importing via new module

@use '_variables.scss';
@use 'buttons' as *; // the star removes any namespace
@use 'forms' as f;

a{ color: variables.$primary; }
$btn-color: $color; // buttons.$color without a namespace
$form-border: f.$input-border; // forms.$input-border with a custom namespace

 

Mixins

Mixin names, like all Sass identifiers, treat hyphens and underscores as identical. This means that reset-list and reset_list both refer to the same mixin. This is a historical holdover from the very early days of Sass, when it only allowed underscores in identifier names. Once Sass added support for hyphens to match CSS’s syntax, the two were made equivalent to make migration easier.

How to use mixins

  1. Declare a mixin : @mixin mixinExample(…){…}
  2. Use that mixin within SCSS : @include mixinExample

Learn more about using #{$arguments} as an array or how to use @content blocks as a slot from the official documentation. All this to ad flexibility to your mixins.

 

Important logic of !default

Adding !default at the end of a Sass variable means that this variable is likely to be redefined later in the cascade of the imported files, in which case the other declared variable will be prioritized regardless of its position in the reading cascade logic.

Using this declaration is highly recommended as it is a counter part of using the !important declaration which generates many nightmares at maintenance and is bad for CSS reading performance.

 

Colors

Color functions

Converts hex color value to RGB.

RGB values *,*,* no more requires to be seperated by comas

@function toRgb($hexColor) {
    @return "rgb("+ red($hexColor) +" "+ green($hexColor) +" "+ blue($hexColor) +")";
}
// Applyed
$rgbColor: hexToRgb(#2d3c54);
@debug "rgbColor": #{$rgbColor};

Color parameters

Listing color parameters:

  1. color.red() : RGB,
  2. color.green() : RGB,
  3. color.blue() : RGB,
  4. color.alpha() : HSL,
  5. color.hue() : HWB,
  6. color.lightness() : HSL,
  7. color.opacity() : transparency,
  8. color.saturation() : HSL,
  9. color.whiteness() : HWB,
  10. color.blackness() : HWB,

Parameter usage:

 

Sass native functions

Math functions

function example new math module
Ceil ceil(1.25) = 2 math.ceil()
Floor floor(1.75) = 1 math.floor()
Percentage percentage( $value100 / $value50 ) = 200% = percentage( 2.0 ) math.percentage()
Random random(100) = 0>99 math.random()

String functions

function example new string module
Lenght lenght($example) string.length($example)
To lower case to-lower-case($example) string.to-lower-case($example)
Unique ID unique-id() string.unique-id()

~ Tilde prefix as import path

@import "~bootstrap";

Prepending module paths with a ~ tells webpack and/or npm loader to search through node_modules. It's important to prepend it with only ~, because if you add a slash after the tilde character (~/) it indicates your personal to the home directory and we don't want that.

 

BEM my SCSS

How to code CSS using BEM nomenclature on SASS preprocessor stylesheets. Here is a real world tutorial from CSS-Tricks.

HTML

<p class="main-style">Main style example</p>
<p class="main-style--variant-style">Variant style example</p>
<div class="main-style">
    <p class="main-style__child-style">Child within main style example</p>
</div>

How does it translate in SASS.scss

.main-style {
    color: gray;
    //
    &--variant-style {
        color: orange;
    }
    &__child-style {
        color: blue;
    }
}

 

Use interpolation to parse variables

#{$…}

To parse a quoted string

$img-path-to-assets: '../img';
background-image: url(#{$img-path-to-assets}/logo.png)

At Root rule interpolation

This rule causes everything within it to be interpolated at the root of the document instead of using the normal nesting. We can NOT nest multiple an `@at-rule Reference

SCSS vs CSS

.selector {                          .selector {
    background: gray;                      background: gray;
    //                                }
    @at-root .parent #{&} {           .selector .thisClass { 
        background: blue;                  background: blue;
    }                                 }
    @at-root .sibling#{&} {           .sibling.selector {
        background: green;                 background: green;
    }                                 }
    @at-root #{&} .child {            .selector .child {
        background: red;                   background: red;
    }                                 }
}



&nbsp;

# Looping through an array with `@each`

This loop is to assign any color from Bootstrap Theme to a custom call

```scss
@each $themeColor, $value in $theme-colors {
    .link-hover--#{$themeColor} {
        @include hover-focus(){
            color: $value !important;
        }
    }
}

 

Extending class

This is useful to replicate a common macro style accros many contexts without duplicating it everytime. Simply declare it once ABOVE then paste that style where you need it later in the cascade.

Useful for extending Bootstrap class (ex.: .sr-only) within your own projet stylesheets.

.common-style {
    font-weight: bold;
    color: white;
}
.example {
    @extend .common-style !optional;
}

 

Looping examples

  1. @for
  2. @while
  3. @each

 

Useful mixins

Animated transition

@mixin anim($speed:0.3, $toWhat:all, $animStyle:ease) {
    $speed_s: $speed + s; //string interpolation as seconds
    //
    transition: $toWhat $speed_s $animStyle;
}

Animations

@mixin anim_opacity( $speed:1, $keyFrameName:blink, $animStyle:infinite ) {
    $speed_s: $speed + s;
    //
    @keyframes #{$keyFrameName} {
          0% { opacity: 1; }
        100% { opacity: 0; }
    }
    animation: $keyFrameName $speed_s $animStyle;
}
@mixin anim_rotate90($speed:1, $keyFrameName:spin, $animStyle:infinite) {
    $speed_s: $speed + s;
    //
    @keyframes #{$keyFrameName} {
          0% { transform: rotate(0deg); }
        100% { transform: rotate(90deg); }
    }
    animation: $keyFrameName $speed_s $animStyle;
}

Background size with vendor prefix

@mixin bg-size ($value: 100%) {
    -webkit-background-size: $value;
    -moz-background-size: $value;
    -o-background-size: $value;
    background-size: $value;
}

CSS arrows

@mixin arrow-setup ($size, $borderWidth:1px, $rotation:-45deg, $padding: floor($size /2)) {
    display: inline-block;
    width: $size;
    height: $size;
    padding: $padding;
    border: solid blue;
    border-width: 0 $borderWidth $borderWidth 0;
    transform: rotate($rotation);
}
// <i.icon-arrow-to-right>,
// <i.icon-arrow-to-left>
.icon {
    &-arrow-to {
        &-right {
            @include arrow-setup(5px, 2px);
            margin-left: 0.75rem;
        }
        &-left {
            @include arrow-setup(5px, 2px, 135deg);
            margin-right: 0.75rem;
        }
    }
}

Background « Barber style » stripped gradient

@mixin backgroundStriped ($color1: transparent, $color2: rgba(255, 255, 255, 0.25)) {
    background-image: repeating-linear-gradient(-45deg, $color1 0rem, $color1 1.5rem, $color2 1.5rem, $color2 3rem);
}

Dimensions shorthand

@mixin dimensions ($width: 1px, $height: 1px ) {
    width: $width;
    height: $height;
}

Heading tags looping

Original post : « SASS function loop for headings h1, h2, h3, h4, h5, h6 » by Alex

@function headingTags ($from: 1, $to: 6) {
    @if $from == $to {
        @return 'h#{$from}';
    }
    @else {
        @return 'h#{$from},' + headingTags($from+1, $to);
    }
}

Usage

#{headings(1,6)} {
    color: white;
}

IE fallback for CSS variable

Clean fallback (not a hack) for IE (previous to Edge) browsers

Kendo script adds a class to identify the browsers on the html tag : <html class="k-ie k-ie11">. This mixins rely on that browser detection script.

@mixin cssVar_ie_fallback($css_property, $default_value, $ie_value: $default_value) {
    #{$css_property}: $default_value;
    html.k-ie & {
        #{$css_property}: $ie_value;
    }
}

Responsive media queries

/**
 * Responsive media queries
 * `@include responsive_media(min-width, 1200px, false)`
 */
@mixin responsive_media( $attr: min-width, $breakpoint: 320px, $mediaPrint: false ) {
    @if $mediaPrint {
        @media print and ($attr: $breakpoint) {
            @content;
        }
    } @else {
        @media screen and ($attr: $breakpoint) {
            @content;
        }
    }
}

Placeholder font-style and color

Style input's placeholders to make it look different when not filled. Expending Bootstrap4 $input-color-placeholder to more browsers.

Author: www.stackoverflow.com/questions/20773665/fail-to-change-placeholder-color-with-bootstrap-3

@mixin placeholder_fontStyleColor ($style: normal, $color: #ccc) {
    // Old Safari and Chrome
    &::-webkit-input-placeholder {
        font-style: $style;
        color: $color;
    }
    // Old Firefox
    &::-moz-placeholder {
        font-style: $style;
        color: $color;
        opacity: 1; // Override Firefox's unusual default opacity; See //github.com/twbs/bootstrap/pull/11526
    }
    // Microsoft IE 10-11
    &:-ms-input-placeholder {
        font-style: $style;
        color: $color;
    }
    // Microsoft Edge
    &::-ms-input-placeholder {
        font-style: $style;
        color: $color;
    }
    // w3c
    &::placeholder {
        font-style: $style;
        color: $color;
    }
}

Prefixid Container Ratio To Child Contents

  • Control aspect ratio to center align child tag. The logic is based on Bootstrap3.
  • Default ratio is 16:9 but can be set to whatever required.
  • Requirement: Can only contain ONE of either , <iframe>, or tags and nothing else.
@mixin fixedRatio_toChild ( $ratioX: 16, $ratioY: 9, $framePadding: 0 ) {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
    padding: 0;
    //
    &:before {
        content: '';
        display: block;
        padding-top: ($ratioY / $ratioX) * 100%;
    }
    // child containers
    > iframe,
    > object,
    > video {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        height: 100%;
    }
    // child images
    > img {
        flex: 0 0 auto;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        max-width: 100%;
        width: auto;
        height: auto;
        max-height: 100%;
        padding: $framePadding;
    }
}

Text-shadow as border

Use Text Shadow as wrapping border around text

@mixin textShadow_asBorder ($borderCorlor: black ) {
    text-shadow: -1px -1px 0 $borderCorlor, 1px -1px 0 $borderCorlor, -1px 1px 0 $borderCorlor, 1px 1px 0 $borderCorlor;
}

Compiling Sass to CSS

A bunch of application plugins exist to compile Sass and SCSS files for small personnal tasks but if your are developing an important project with colegues the standard is to set-up an npm package.json file from where you will set scripts to either update you CSS files as you save your Sass files or executing simply compiling all before doing your git commit.

My stylesheet repositories :

  • myTheme/dist/css/myTheme.css
  • myTheme/src/sass/myTheme.scss
  • myTheme/package.json

Dart Sass CLI command lines :

  • --embed-sources tells Sass to generate the «*.css.map» file that allow the browsers web inspecters to traceback the lines numbers.
  • --quiet tells Sass not to emit any warnings.
  • --style=compressed tells Sass to minify when exported as css file.
  • --watch tells Sass to keep on re-compiling CSS files everytime the OS detects that you save a changed file.

package.json

{
  "name": "myTheme",
  "version": "1.0.0",
  "description": "Front-end stack for custom wordpress theme",
  "author": "",
  "license": "ISC",
  "main": "dist/js/theme.js",
  "devDependencies": {
    "sass": "^1.42.1"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch-sass": "sass src/sass:dist/css --embed-sources --style=compressed --watch",
    "compile-sass": "sass src/sass:dist/css --embed-sources --style=compressed --quiet"
  }
}

Scss VS Less

LessCss is kind of depricated since CSS variables are supported by major browsers.

preprocessor prefix mixin declaration mixin usage
sass $ @mixin my-mixin(){…} @includ my-mixin();
less @ .my-mixin(){…} @my-mixin();
⚠️ **GitHub.com Fallback** ⚠️