On Github Snugug / rwd-sass-compass
Go to
https://github.com/Snugug/code-rwd-sass-compass
to fork and clone the repo
Each challenge's starting point is available as a branch.
If you would like to be caught up quickly, simply check out the branch of the challenge you're on.
// If the window is at least 500px wide... @media (min-width: 500px) { ... } // If the window is less than 785px wide... @media (max-width: 785px) { ... } // If the user is printing the page... @media print { ... } // If the window is in between 520px and 699px... @media all and (min-width: 520px) and (max-width: 699px) { ... }
Breakpoint is a Compass extension. It makes media queries much easier to maintain.
$nav-lg: 680px; .main-nav { width: 100%; @include breakpoint($nav-lg) { width: 60%; margin: 0 auto; } }
.main-nav { width: 100%; } @media (min-width: 680px) { .main-nav { width: 60%; margin: 0 auto; } }
Boil down most media queries to one simple value.
Assign that value a meaningful name.
You keep all the styles for a component in one place
Manage media queries by purpose and context.
Pass Breakpoint just a number and you get a min-width query.
// THIS IS OUR FIRST BREAKPOINT VARIABLE $basic: 500px; // <-- YUP, THIS ONE #main-nav { width: 100% @include breakpoint($basic) { width: 75%; } }
#main-nav { width: 100% } @media (min-width: 500px) { #main-nav { width: 75%; } }
Two values creates a min-width / max-width query.
$big-header: 330px 750px; #header { font-size: 2em; @include breakpoint($big-header) { font-size: 2.5em; } }
#header { font-size: 2em; } @media (min-width: 330px) and (max-width: 750px) { #header { font-size: 2.5em; } }
If one value is a string, assume a feature/value pair
$too-damn-wide: max-width 1000px; #hero-image { max-width: 100%; margin: 2em 0; @include breakpoint($too-damn-wide) { margin: 0.5em 0; } }
#hero-image { max-width: 100%; margin: 2em 0; } @media (max-width: 1000px) { #fifty-seven-chevy { margin: 0.5em 0; } }
String them together to create more complex queries
$tighten-text: (max-width 1000px) (orientation portrait); #main-article { font-size: 1em; line-height: 1.375; @include breakpoint($tighten-text) { line-height: 1.25; } }
#main-article { font-size: 1em; line-height: 1.375; } @media (max-width: 1000px) and (orientation: portrait) { #pappas { line-height: 1.25; } }
Breakpoint can also output fallbacks for when no media queries are present, such as in IE<9
$breakpoint-no-query-fallbacks: true; $nav-lg: 500px, 'no-query' '.lte-ie9'; nav { @include breakpoint($nav-lg) { width: 60%; margin-right: 4%; } }
@media (min-width: 500px) { nav { width: 60%; margin-right: 4%; } } .lte-ie9 nav { width: 60%; margin-right: 4%; }
Just add a conditional class to your <html> element
*, *:before, *:after { @include box-sizing('border-box'); }
$grids: 12; // Number of Columns $gutters: 1/3; // Gutter to Column ratio, 20px/60px = 1/3
Out of the box, Singularity offers two output styles, float and isolation. The default output style is isolation, but we're going to change it float for now as it will be more familiar to begin with.
$output: 'float';
Align to columns using Grid Span:
@include grid-span($span, $position);
$span is the number of columns to span$position is what column to start from
#container { max-width: 960px; // Outer Container padding: 0 10px; // Side Gutter margin: 0 auto; // Center Container @include clearfix; // Have container clear floats properly } .left { @include grid-span(6,1); } .right { @include grid-span(6,7); }
Grids should work with the content itself, not impose a class structure. We should not limit ourselves to a 12 column layout with four breakpoints.
Instead, let's design our sites around the content, creating awesome mobile-first layouts.
In short: We deserve better.
We are going to build and style our grid based upon the content.
Start with the small screen first, then expand until it looks like shit. TIME FOR A BREAKPOINT!
Stephen HayThis is the opposite of using a framework like Twitter Bootstrap, where the grid is pre-defined.
Grids provide order to your design and structure to your information.
The ideal grid is specific to your content and your design, since it is an extension of both.
Within singularity you can create completely different grids for different breakpoints.
You can also customize each section of the site completely, creating sub-structure within a block of content.
Grids where the columns are not the same size
Custom grids for each design allow for more unique designs to better highlight your content
Singularity Extras is very useful when working with asymmetric grids
// List of column width in relation to each other $grids: 5 2 3 3 7 9;
// List of symmetric grids to compound together $grids: compound(3, 4);
// Ratio and number of columns $grids: ratio(golden(), 4);
// Number of columns and ratio $grids: ratio-spiral(5, golden());
// Asymmetric grid and the gutter width of the grid to snap to. $grids: snap(2 4 4 2, 1/3);
Settings $grids and $gutters set a global context for them, making them available to use without redeclaring them each time they're needed.
You can set different global contexts to use at different min-width breakpoints
$grids: 12; $grids: add-grid(2 8 2 at 500px); $gutters: 1/3; $gutters: add-gutter(1/4 at 532px);
When using the breakpoint mixin, Singularity is able to determine which global context you'd like and subsequently use the correct one when you use the grid-span mixin
$grids: 2; $grids: add-grid(4 at 475px); $gutters: 1/6; #nav { width: 100%; @include breakpoint(500px) { @include grid-span(3, 2); } }
If you need to override the global contexts, for instance if you need to nest a grid and therefore change the grid you're using, use the layout mixin
$grids: 12; $gutters: 1/3; #main { @include grid-span(8, 1); @include layout(8) { .left { @include grid-span(4, 1); } .right { @include grid-span(4, 5); } } }
Toolkit has been providing for us our box model fix and our fluid images, but it can do so much more
Designed not as a CSS System, but rather a set of tools to build your own, Toolkit makes doing things the right way the easy way
Provided by Toolkit by default, the basic way to get images to squish and maintain their dimensions is fairly easy CSS
img, video { max-width: 100%; height: auto; }
But Embedded Content Isn't So Easy
Intrinsic Ratios are a CSS technique that allow you to constrain child elements to a ratio and percentage of its parent
// Intrinsic Ratio mixin comes from Toolkit .ratio-16-9 { @include intrinsic-ratio; } .ratio-4-3 { @include intrinsic-ratio(4/3); }
Progressive Enhancement allows us to provide an enhanced experience to superpowered browsers.
Progressive Enhancement is best done through feature detection, like that provided by Modernizr
Sass plus Modernizr is a powerful one-two punch for progressive enhancement
Modernizr provides test to determine browser support without user-agent sniffing
Each test provides a class, either .test or .no-test class, on our <html> tag, as well as a boolean property at Modernizr.test in JavaScript
.logo { .svg & { background-image: url('../img/logo.svg'); } .no-svg &, .no-js &{ background-image: url('../img/logo.png'); } }
.svg .logo { background-image: url("../img/logo.svg"); } .no-svg .logo, .no-js .logo { background-image: url("../img/logo.png"); }
Modernizr can also be bundled with yepnope.js, allowing for conditional loading of additional assets (both CSS and JS) based on passed or failed tests
Scripts are loaded asynchronously and in parallel!
Modernizr.load({ test: Modernizr.svg, yep: '../css/svg.css', nope: '../css/no-svg.css' });
Partials allow us to divide up our styling into discrete pieces, making organizing and maintaining our styling easy
There are many different ways to organize your partials, this is the standard we will be working with from now on.
Global partials contain styling and development knowledge that are central and can be shared across multiple components.
Examples of shared styling knowledge includes color variables, dark/light contrast mixins, and general typography extendable classes
In your sass folder, create a globalfolder and inside that, a folder apiece for extends, functions, mixins, variables to place respective partials in to. In each folder, create a _all.scss partial for a global import for those folders
style.scssglobalextends
_all.scssfunctions
_all.scssmixins
_all.scssvariables
_all.scss
In your style.scss file, start it with any of your file-specific setup variables (cross-browser/Jacket, etc…, not global setup variables that need to be shared across multiple files, like grid and media query variables), then the Compass extension imports you need for that file, finally followed by your global imports
////////////////////////////// // Cross Browser Support $legacy-support-for-ie: false; $jacket: 'base'; ////////////////////////////// // Normalize @import "normalize"; ////////////////////////////// // Compass Extensions @import "toolkit"; @import "breakpoint"; @import "singularitygs"; ////////////////////////////// // Globals @import "global/variables/all"; @import "global/functions/all"; @import "global/mixins/all"; @import "global/extends/all";
Everything on your site is a component; your messages, your media galleries, your buttons, your navigation.
Each component should be written as a generalized mixin with defaulted, globally scoped variables. Then, each instance of a component should be written as an extendable class. Finally, each extendable class should be extended as a full selector
In your sass folder, create a components folder and inside of that, a folder and a partial a piece for each component. Inside each folder, create _extends.scss, _mixins.scss, _variables.scss partials for that component, and import them into your component partial
style.scsscomponents
_button.scss
_message.scssbutton
_extends.scss
_mixins.scss
_variables.scssmessage
_extends.scss
_mixins.scss
_variables.scss
$message-status-color: $primary-color !default; $message-warning-color: $secondary-color: !default; $message-error-color: $tertiary-color !default; $message-border-radius: $std-border-radius !default; $message-extend: true !default;
@mixin message--core($border-radius: $message-border-radius, $extend: $message-extend) { @if $extend and $border-radius == $message-border-radius { @extend %message--core; } @if $extend and not $border-radius == $message-border-radius { @extend %message--core; @include border-radius: $message-border-radius; } @else { width: 80%; margin: 0 auto; padding: .5em; border: 1px solid black; @include border-radius: $message-border-radius; } } …
$message-extendables-extended: false !default; @if not ($message-extendables-extended) { %message--core { @include message--core($extend: false); } %message--status { @include message--core($extend: true); @include message--instance($message-status-color); } … %message--error { @include message--core($extend: true); @include message--instance($message-error-color); } } $message-extendables-extended: true;
@import "message/variables"; @import "message/mixins"; @import "message/extends"; .message { @extend %message-core; } .message--status { @extend %message--status; } .message--error { @extend %message--error; }
Layouts get yet a third top level partial folder. Generally there will be a handful of set layouts on a given site, and each layout should get a partial structure similar to components.
In your sass folder, create a layouts folder and inside of that, a folder and a partial a piece for each layout. Inside each folder, create _extends.scss, _mixins.scss, _variables.scss partials for that layout, and import them into your layout partial
style.scsslayouts
_article.scss
_landing.scssarticle
_extends.scss
_mixins.scss
_variables.scsslanding
_extends.scss
_mixins.scss
_variables.scss
Grunt is a Node.js based task runner that can do just about anything. From running development servers to live reloading sites to hinting, linting, compiling and compressing, any development task you can think of, you can get Grunt to do. And it's all written in JavaScript!
When working with Grunt, you're turning your development area into a Node project regardless of what language you're working in. You can quickly initialize a Node project by running npm init, which will create your package.json.
The primary reason for this is the need to install and use Node modules in order to use Grunt.
{ "name": "code-rwd-sass-compass", "version": "0.0.0", "description": "Code for RWD Training", "author": "Sam Richard", "license": "MIT", "devDependencies": {} }
When working with Grunt, most of what you're working with are development packages. When you go to install a package using npm install, appending --save-dev to the end will save them into your package file.
The minimum packages you need in order to run Grunt and use contributed Grunt tasks are grunt and matchdep
Installed modules will be saved to a node_modules file. Be sure to ignore this folder in your version control! Don't commit it in!
Your Gruntfile.js file is the brains of the boar. Each project you start gets its own Gruntfile that you get to write from scratch.
A Gruntfile is written in strict JavaScript via Node, none of your jQuery here. You'll be adding configuration to a grunt object and creating tasks. Unlike most of Node, Grunt tasks run in series, not parallel.
(function() { 'use strict'; module.exports = function (grunt) { // Grunt task configuration grunt.initConfig({ // Configuration goes in here }); // Use matchdep to load all Grunt tasks from package.json require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); // Custom Grunt tasks go here. // This is the special `default` task grunt.registerTask('default', function () { console.log('This runs when you run `grunt`'); }); }; }());
grunt.initConfig({ connect: { server: { options: { port: 9001, base: '.' } } } });
////////////////////////////// // Server Task ////////////////////////////// grunt.registerTask('server', function () { grunt.task.run(['connect']); });
Slides available at
http://snugug.github.io/rwd-sass-compass