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

Setting-up Sass.scss

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"
  }
}

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

 

@at-root

The @at-root causes everything within it to be interpolated at the root of the document instead of using the normal nesting.

We can NOT nest multiple level of @at-root.

/* scss */
.selector {
  @at-root .parent #{&} { … }
  @at-root .sibling#{&} { … }
  @at-root #{&} .child { … }
}
/* compiled css */
.parent .selector { … }
.selector.sibling { … }
.selector .child { … }

@import

Sass will gradually phase out @import over the next few years, and eventually remove it from the language entirely. Prefer the @use rule instead.

The @import rule extends the CSS at-rule to load styles, mixins, functions, and variables from other stylesheets. Unlike plain CSS imports, which require the browser to make multiple HTTP requests as it renders your page, Sass imports are handled entirely during compilation.

@use and @forward

These two rules are confusing because they kind of do the same task but

The rule is written @forward "". It loads the module at the given URL just like @use, but it makes the public members of the loaded module available to users of your module as though they were defined directly in your module. Those members aren’t available in your module, though—if you want that, you’ll need to write a @use rule as well. Don’t worry, it’ll only load the module once!

If you do write both a @forward and a @use for the same module in the same file, it’s always a good idea to write the @forward first. That way, if your users want to configure the forwarded module, that configuration will be applied to the @forward before your @use loads it without any configuration.

A stylesheet’s @use rules must come before any rules other than @forward, including style rules. However, you can declare variables before @use rules to use when configuring modules.

The @use rule loads mixins, functions, and variables from other Sass stylesheets, and combines CSS from multiple stylesheets together.

Using @forward rule loads a Sass stylesheet and makes its mixins, functions, and variables available when your stylesheet is loaded with the @use rule. It makes it possible to organize Sass libraries across many files, while allowing their users to load a single entrypoint file.

 

Sass to CSS custom properties

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,
);

/**
 * From Sass to CSS ↴
 */

// 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);
}

 

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.

 

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

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()
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

Choose your easing function from easings.net

@mixin anim_transition($duration:0.3, $cssProperty:all, $easingFunction:ease) {
    $duration_s: $duration + s; //string interpolation as seconds
    //
    transition: $cssProperty $duration_s $easingFunction;
}

Animations

@mixin anim_opacity( $duration:1, $keyFrameName:blink, $animStyle:infinite ) {
    $duration_s: $duration + s;
    //
    @keyframes #{$keyFrameName} {
          0% { opacity: 1; }
        100% { opacity: 0; }
    }
    animation: $keyFrameName $duration_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;
}

« Barber style » stripped background pattern

@mixin background_pattern_image(
  $stroke1color: transparent,
  $stroke2color: rgba(255, 255, 255, 0.25),
  $stroke1width: 20px,
  $stroke2width: 20px,
  $patternAngle: 315deg
) {
  background-image: repeating-linear-gradient(
    $patternAngle,
    $stroke1color 0,
    $stroke1color $stroke2width,
    $stroke2color $stroke2width,
    $stroke2color ($stroke1width + $stroke2width)
  );
}

Chevron shape via CSS

@mixin chevron_shape ($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);
}
/*
 * Useful for creating pointing arrows to a direction
 * <i.icon__pointing-arrow--to-right>,
 * <i.icon__pointing-arrow--to-left>
 */
.icon {
    &__pointing-arrow {
        &--to-right {
            @include chevron_shape(5px, 2px);
            margin-left: 0.75rem;
        }
        &--to-left {
            @include chevron_shape(5px, 2px, 135deg);
            margin-right: 0.75rem;
        }
    }
}

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** ⚠️