Sass

Improving Front-End Workflow with CSS Preprocessing

Why?

  • Extends CSS in a logical way
  • Improves maintainability
  • Improves scalability 
  • Promotes modularity
  • DRYs out code

What?

  • CSS extension language
  • SCSS or Sass format compiles into CSS
  • Open source and created using Ruby (C implementation exists as well - better performance)
  • Vanilla CSS is valid SCSS

How?

  • All Sass files located in /sass folder in root
  • Compile to /stylesheets
  • All Sass partials imported into main.scss
  • Imported partials denoted by underscore
@import
"Utilities/_vars.scss",
"Utilities/_mixins.scss",
"Base/_reset.scss";

Where?

  • All necessary files can be found on ftp
  • \\ftp\Graphics\+ Creative Resources\FED Project Setup
  • gulpfile, package.json, build events, and Sass basic structure

Structure - Base

  • Animations
    • All keyframe animations
  • Framework
    • Foundation (GRID only)
  • Global
    • Global classes, generic components, general global styles
  • Reset
    • Standard browser reset
  • Structure
    • Navigation, Header, Footer
  • Typography
    • Font face declarations, global typography styles, rich text (WYSIWYG) styles, typography classes (silent & otherwise)

Structure - Utilities

  • _mixins.scss
    • Contains all mixin declarations
  • _vars.scss
    • Contains all variables and maps: media queries, colors, fonts, page/block-specific pixel/percentages

Structure - Other

  • Components
    • All component-specific styles
  • FeatureDetection
    • Global browser-specific or global touch-specific styles
  • Pages
    • All template-specific styles
  • Responsive
    • Global responsive styles (rarely used) - older projects

Compiling

  • Web Workbench (older projects)
    • Install Mindscape Workbench; compiles on save automatically (make sure /stylesheets folder is checked out!)
  • Issues:
    • TFS
    • Ruby-based = slow (~15 seconds)
    • Often generates unwanted .css files
    • Hates life

Compiling

  • Gulp (newer projects)
    • Run "npm install" in directory with package.json file
    • Run "gulp sass:watch" to start watch task
    • "gulp sass:build" will compile CSS
      • Don't forget to disable Workbench/Web Essentials
  • Improvements:
    • No TFS issues
    • Fast (C based)
    • Autoprefixer - no need to worry about vendor prefixes
    • Source maps in Dev Tools

Troubleshooting

  • Gulp depends on:
    • iojs - 32bit
    • Git - "Use from Windows Command Prompt"
    • Python 2.7.x 
  • "gulp not recognized command" error
    • Install gulp globally ("npm install gulp -g") 
  • FYI: "stylesheets/main.css" is not included in the project - is created as a hidden file

Deployment

  • Should be a pre-build event to automatically compile Sass
  • cd $(ProjectDir)
    call npm install
    call gulp sass:build-prod
  • "gulp sass:build-prod" should be used for any production deployments
    • Autoprefixer, minification
  • TFSBuild knows how to gulp!
    • Include in automated builds

Getting Started

  • Basic syntax is virtually identical to CSS
  • Partial structure:
    • General styles (some times split up further by section)
    • Media queries, in descending order

Getting Started

  • Safely modify any Pages/Components sass files
  • Generally should not be modifying any Base files
  • Add classes to appropriate template-specific or component-specific Sass partial
  • Make sure your class name is specific - CSS is global scope!
    • ".module-description"
    • Never ".button", ".container", etc.

Nesting

  • Useful for clear visual hierarchy
  • To nest pseudo-classes/elements:
    • &:hover, &:before, etc.
  • To nest stacked classes:
    • &.class-name
  • Caveats
    • Never nest more than three levels deep - creates overly specific selectors

Nesting Ex.

  • Class naming:
    • All lowercase separated by hyphens
    • Semantically
    • .module-description
      • Allows for utilization of nesting w/o unnecessarily increasing selector specificity - new in Sass 3.4+
.module {
    &-title {
        color: red;
        &:before {
            content: "hi";
        }
    }
    &-desc {
        color: blue;
    }
}
<div class="module">
    <p class="module-title"></p>
    <span class="module-desc"></p>
</div>

Nesting Cont.

  • Seriously, no more than 3 levels deep
  • Selector specificity should never exceed (0, 0, X, Y) where X + Y < 4
  • IDs should never be used as selectors

Variables

  • Store information that needs to be reused
  • Properties:
    • Media query breakpoints
    • All colors
    • Font facts
    • Non-arbitrary pixel/percentage values 
      • If a value is used multiple times, a variable should be created
      • Avoid "magic numbers" - use variables to calculate new values to ensure clarity
      • To pass a variable into a calc() function, interpolate

Variable Ex.

Declare a variable

$accent-color:  #000;
$column-gutter: 30px;

Use a variable

right: ($max-width - $column-gutter);
width: calc(100vh - #{$column-gutter});

Extend

  • Share a set of properties
    • Important for DRY CSS
    • Helps prevent class overload
    • Ensures consistency 
  • Should only ever extend silent classes
    • Ensures relationships formed only around the correct properties

Extend Ex.

  • Extend typography 
%lt-sans-serif {
    font-family: $sans-serif-lt-font; 
    font-size: .9em;
    line-height: 1.5em;
}

.paragraph {
    @extend %lt-sans-serif;
}
  • Extend grouping
%fixed-arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: map-get($zindex, z-index-1);
	svg {
    	    fill: #fff; 
    	    pointer-events: none;
	}
}

.previous-arrow {
    @extend %fixed-arrow;
    left: 0;
}

.right-arrow {
    @extend %fixed-arrow;
    right: 0;
}

Mixins

  • Group reusable declarations and pass in a value
  • Base mixins included in _mixins.scss partial:
    • Backwards compatibility
    • Transitions
    • Hardware acceleration
    • Gradients
    • Animations
    • + more!
@mixin multiline-ellipsis($number) {
    display: -webkit-box;
    -webkit-line-clamp: $number; 
    text-overflow: ellipsis;
    overflow: hidden;
    -webkit-box-orient: vertical;
}

Mixin declaration

.class {
    @include multiline-ellipsis(5);
}

Mixin usage

Mixins Cont.

  • Can accept multiple values (with option to define default value)
  • Can accept @content blocks
@mixin transition($time, $property: all, $easing: ease-in) {
    transition: $property $time $easing;
    -webkit-transition: $property $time $easing;
    -moz-transition: $property $time $easing; 
    -o-transition: $property $time $easing; 
}
@mixin apply-to-ie6-only {
  * html {
    @content;
  }
}
@include apply-to-ie6-only {
  #logo {
    background-image: url(/logo.gif);
  }
}
* html #logo {
  background-image: url(/logo.gif);
}

Compiles to:

Maps

  • Represent an association between keys and values
    • New to 3.4+!
  • Should be used for z-index values to prevent insanity
  • Useful with @each loops

Maps Ex.

Z-index map

$zindex: (
  z-index-0     : -1, 
  z-index-00    : 0,
  z-index-1     : 10, 
  z-index-2	: 20,
  z-index-3	: 30
);
.class {
    z-index: map-get($zindex, z-index-1);
    position: relative;
}

Z-index usage

$audioHex: (
  1930s		: #909195, 
  1940s		: #e60d64, 
  1950s		: #8cc63e, 
  1960s		: #d15238,
  1970s		: #fdb813,
  1980s		: #00bbe4,
  1990s		: #810055,
  2000s		: #083a81, 
  2010s		: #4c854e
);
@each $key, $value in $audioHex {
  .promo-audio .audio-#{$key} {
    background-color: $value;
  }
}

Decade/Hex Code map

Used in @each loop

Operations

  • All standard mathematical operations can be performed
    • Must be same unit
  • Standard boolean operators

Functions

  • Many built in functions
    • random($limit)
    • saturate($color, $amount)
    • if($condition, $if-true, $if-false)
    • floor, ceil
    • str_index, str_length, str_slice, etc.

Create Functions

$grid-width: 40px;
$gutter-width: 10px;

@function grid-width($n) {
  @return $n * $grid-width + ($n - 1) * $gutter-width;
}

.sidebar { width: grid-width(5); }

Control Directives

$boolean: true !default

@mixin simple-mixin
  @if $boolean
    @debug "$boolean is #{$boolean}"
    display: block
  @else
    @debug "$boolean is #{$boolean}"
    display: none

.some-selector
  @include simple-mixin
  • Expressions for including styles only under some conditions or including the same style several times with variations
  • Provide flow and logic in mixins
  • !default - gives value unless the variable has an assigned value
  • Others include @for, @each, and @while

Control Dir. Ex.

Used on Shedd Aquarium/Ticket Philly

$colorPrimary: #6e7998;
$colorSecondary: #3c1d6d;
$colorTertiary: rgba($colorPrimary, .1);
$colorTint: #d3d6e0;

Each theme has partial file defining these variables:

Import partial; include mixin with name and color variables

@import 'themes/_themeAbout.scss';
@include theme("theme-about", $colorPrimary, 
$colorSecondary, $colorTertiary, $colorTint);
@mixin theme($name, $colorPrimary, $colorSecondary, $colorTertiary, $colorTint){
    body[data-theme="#{$name}"] {
        body:after { background: $colorPrimary; }
        h1 { color: $colorPrimary;}
    }
    @if $name == theme-about {
	> div:before { background-image: url(/Global/bg/dropdowns/about-top.gif); }
    }
    @if $name == theme-animals {
	> div:before { background-image: url(/Global/bg/dropdowns/animals-top.gif); }
    }
}	 

Mixin declaration

Cool Stuff

Animate polyhedral expansion:

http://codepen.io/thebabydino/pen/qDziw

Rotating icosidodecahedron:

http://codepen.io/thebabydino/pen/kpCyx

 

(Relies on Compass - Sass extension that adds helpers)

Resources

Made with Slides.com