Managing Responsive Web Design With Sass And Breakpoint

And Singularity

The Right Way to do RWD.

Of Course Responsive Web Design is Hard. It's Design. Mason

Who is this guy?

I

Let’s Get a Few Things Straight.

Hold up your hand if you own a smartphone.

Lower it if you have the same make and model phone as your neighbors

That's Devicist

Responsive Web Design isn’t about current devices and known unknowns, it’s about future devices and unknown unknowns.

Sam Richard

So what's the Right Way?

We start with content first.

It’s not about mobile first (or just small screen first) – it's about content first. But it happens that thinking about what works for mobile does work for other things as well.

Jeffery Zeldman

Then we design for mobile and work our way up from there.

Using web standards and best practices along the way.

We're device agnostic and future friendly.

Like good little web builders.

Bonus

Gold stars to you if you also consider:

Style Tiles

Living Style Guides

Style Prototypes

Nailing your Typography first / early

Is there a secret weapon?

We know Sass.

  • You're familiar with variables and nesting.
  • You've used some mixins.
  • You've hopefully tried Compass.

Let's learn some Sass together.

II

Media Queries with Vanilla Sass

Breakpoints vs Tweakpoints

  • Breakpoints for large changes

  • Tweakpoints for small adjustments

Separation vs Nesting

Why is this wrong?

.menu {
  padding: 10px;
}
.subnav {
  padding: 5px;
}
@media (min-width: 500px) {
  .menu {
    padding: 100px;
  }
  .subnav {
    padding: 25px;
  }
}

Nesting and Media Bubbling

In many cases it's more intuitive to keep your media queries with what they're altering.

.menu {
  padding: 10px;
  @media (min-width: 500px) {
    padding: 100px;
  }
}
.subnav {
  padding: 5px;
  @media (min-width: 500px) {
    padding: 25px;
  }
}
.menu {
  padding: 10px;
}
@media (min-width: 500px) {
  .menu {
    padding: 100px;
  }
}
.subnav {
  padding: 5px;
}
@media (min-width: 500px) {
  .subnav {
    padding: 25px;
  }
}

NO.

Is this a problem?

III

Breakpoint

breakpoint-sass.com

Team Sass: Mason Wendell (@codingdesigner) & Sam Richard (@snugug)

Why do I want this?

  • Boil down most media queries to one simple value.
  • Simplify creating all media queries, even the crazy complex ones.
  • Assign that value a meaningful name.
  • Manage media queries by purpose and context.

Using Breakpoint

github.com/team-sass/breakpoint

// command line
> gem install breakpoint
// compass.rb
require 'breakpoint'
// working sass file
@import 'breakpoint';

Basic Uses and Sensible Defaults

Only live to get radical.

Bodhi

Single value = min-width

Pass Breakpoint just a number and you get a min-width query.

// THIS IS OUR FIRST BREAKPOINT VARIABLE
$basic: 500px; // <-- YUP, THIS ONE

#johnny-utah {
  color: #C0FFEE;
  @include breakpoint($basic) {
    color: #BADA55;
  }
}
#johnny-utah {
  color: #C0FFEE;
}
@media (min-width: 500px) {
  #johnny-utah {
    color: #BADA55;
  }
}

Convert Numbers to Ems

for more accessible media queries

$breakpoint-to-ems: true;
$basic: 500px;

#johnny-utah {
  color: #C0FFEE;
  @include breakpoint($basic) {
    color: #BADA55;
  }
}
#johnny-utah {
  color: #C0FFEE;
}
@media (min-width: 31.25em) {
  #johnny-utah {
    color: #BADA55;
  }
}

Why again is this cool?

Remember this?

.menu {
  padding: 10px;
  @media (min-width: 500px) {
    padding: 100px;
  }
}
.subnav {
  padding: 5px;
  @media (min-width: 500px) {
    padding: 25px;
  }
}

With Breakpoint

$menu-room-for-air: 500px;
.menu {
  padding: 10px;
  @include breakpoint($menu-room-for-air) {
    padding: 100px;
  }
}
.subnav {
  padding: 5px;
  @include breakpoint($menu-room-for-air) {
    padding: 25px;
  }
}

OH NO! WE NEED TO CHANGE SOMETHING!

$menu-room-for-air: 642px;
.menu {
  padding: 10px;
  @include breakpoint($menu-room-for-air) {
    padding: 100px;
  }
}
.subnav {
  padding: 5px;
  @include breakpoint($menu-room-for-air) {
    padding: 25px;
  }
}

Fenced Values

Two values creates a min-width / max-width query.

$fenced: 330px 750px;

#bodhi {
  color: #C0FFEE;
  @include breakpoint($fenced) {
    color: #BADA55;
  }
}
#bodhi {
  color: #C0FFEE;
}
@media (min-width: 330px) and (max-width: 750px) {
  #bodhi {
    color: #BADA55;
  }
}

Explicit Test / Value

If one value is a string, assume a feature/value pair

$surfboard-width: max-width 1000px;

#fifty-seven-chevy {
  color: #C0FFEE;
  @include breakpoint($surfboard-width) {
    color: #BADA55;
  }
}
#fifty-seven-chevy {
  color: #C0FFEE;
}
@media (max-width: 1000px) {
  #fifty-seven-chevy {
    color: #BADA55;
  }
}

Combine Tests

String them together to create more complex queries

$combined: (max-width 1000px) (orientation portrait);
#pappas {
  color: #C0FFEE;
  @include breakpoint($combined) {
    color: #BADA55;
  }
}
#pappas {
  color: #C0FFEE;
}
@media (max-width: 1000px) and (orientation: portrait) {
  #pappas {
    color: #BADA55;
  }
}

Combine Lots of Tests

String them together to create more complex queries

$long: (500px) (height 700px 1000px) (orientation portrait) (monochrome);
#warchild {
  color: #C0FFEE;
  @include breakpoint($long) {
    color: #BADA55;
  }
}
#warchild {
  color: #C0FFEE;
}
@media (min-width: 500px) and (min-height: 700px) and (max-height: 1000px) and (orientation: portrait) and (monochrome) {
  #warchild {
    color: #BADA55;
  }
}

Going Deeper

The little hand says it's time to rock and roll.

Bodhi

Fallbacks

We need to account for under-powered browsers too, and we have a few different ways to handle that

Use a fallback selector in the same stylesheet.

$breakpoint-no-query-fallbacks: true;
$touch: pointer coarse, 'no-query' '.touch';
#freefall {
  color: #C0FFEE;
  @include breakpoint($touch) {
    color: #BADA55;
  }
}
#freefall { color: #C0FFEE; }

@media (pointer: coarse) {
  #freefall {
    color: #BADA55;
  }
}
.touch #freefall { color: #BADA55; }
No Touching

Fallbacks in Separate Styesheets

Create separate stylesheets for your fallbacks.

// _my-partial.scss
$we-have-mqs: 500px, 'no-query' '.no-mq';
#freefall {
  color: #C0FFEE;
  @include breakpoint($we-have-mqs) { color: #BADA55; }
}
// main.scss
@import "my-partial";
// fallback.scss
$breakpoint-no-queries: true; // Will not print media queries
$breakpoint-no-query-fallbacks: true; // Will print No Query Fallbacks
@import "my-partial";

Fallbacks in Separate Styesheets

compiled css

// main.css
#freefall { color: #C0FFEE; }
@media (min-width: 500px) {
  #freefall {
    color: #BADA55;
  }
}
// fallback.css
#freefall { color: #C0FFEE; }

.we-have-mqs #freefall {
  color: #BADA55;
}

Resolution

We prefer to use the dppx standard resolution unit, but we have you covered with fallbacks.

W3C resolution units

$resolution: resolution 192dpi; // dots per inch
$resolution-standard: resolution 2dppx; // dots per ‘px’ unit
#resolution {
  color: #C0FFEE;
  @include breakpoint($resolution) {
    color: #BADA55;
  }
}
#resolution {
  color: #C0FFEE;
  @include breakpoint($resolution-standard) {
    color: #BADA55;
  }
}

Resolution

compiled css

#resolution { color: #C0FFEE; }

@media (resolution: 192dpi), (-webkit-device-pixel-ratio: 2), (-moz-device-pixel-ratio: 2) {
  #resolution { color: #BADA55; }
}

// dppx
#resolution { color: #C0FFEE; }
@media (resolution: 2dppx), (-webkit-device-pixel-ratio: 2), (-moz-device-pixel-ratio: 2), (resolution: 192dpi) {
  #resolution { color: #BADA55; }
}

Crazy Advanced Uses

100% Pure Adrenaline

Bodhi

Breakpoint Context

Grab the context of a media query from within a mixin or function.

$basic: 700px (height 600px 800px) (orientation landscape);

#context {
  @include breakpoint($basic) {
    content: 'min-height:' breakpoint-get-context('min-height');
    content: 'orientation:' breakpoint-get-context('orientation');
    content: 'max-width: ' breakpoint-get-context('max-width');
  }
}

Breakpoint Context

Context

@media (min-width: 700px) and (min-height: 600px) and (max-height: 800px) and (orientation: landscape) {
  #context {
    content: "min-height:" 600px;
    content: "orientation:" landscape;
    content: "max-width: " false;
  }
}
whoa. Johnny Utah

IV

Singularity

singularity.gs

Team Sass: Scott Kellum (@scottkellum) & Sam Richard (@snugug)

Why Use Grids at All?

Grids give us:


Proportion

Order

Constraint

The best grids are specific to your content and your design, as they are an extension of both.

Why Grids Suck on the Web

The grid should not drive the design.

They're often used as a technical aid, rather than a creative tool.

All the columns are the same size.

Grid Design 800 Years Ago

Villard De Honnecourt, 13th Century

grid design

Grid Design 800 Years Ago

grid design

Grid Design 800 Years Ago

grid design

Using Singularity

github.com/team-sass/singularity

// command line
> gem install singularitygs
// compass.rb
require 'singularitygs'
// working sass file
@import 'singularitygs';

Symmetric Grids

// Symmetric grids are expressed as a single number denoting how many equal sized columns you'd like.

$grids: 12;
$gutters: 1/3;
Symmetric Grid

Asymmetric Grids

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

Types of Asymmetric Grids

Custom - Any asymmetric grid created to suit your needs

Compound - Created by combining symmetric grids

Ratio - Each column is derived from the previous according to a ratio

Ratio Spiral - Columns are generated based on an overlaid spiral

Snap - Asymmetric grid that takes into account an overlaid symmetric grid's gutters

Custom Grid

// List of column width in relation to each other
$grids: 5 2 3 3 7 9;

Compound Grid

// List of symmetric grids to compound together
$grids: compound(3, 4);

Ratio Grid

// Ratio and number of columns
$grids: ratio(golden(), 4);

Ratio Spiral Grid

// Number of columns and ratio
$grids: ratio-spiral(5, golden());

Snap Grid

// Asymmetric grid and the gutter width of the grid to snap to.
$grids: snap(2 4 4 2, 1/3);

Semantic Grids

Singularity is what we like to call a semantic grid system, meaning that instead of grid classes being generated that you then apply to your HTML, the grid is stored entirely within your CSS and applied directly to the element you want to use it on.

Spanning The Grid - HTML

<body>
  <div class="main">Main Section</div>
  <div class="first">First Section</div>
  <div class="second">Second Section</div>
</body>

Spanning The Grid - Sass

// Simply pass the number of columns you'd like to span and what column you'd like to start from.

$grids: 2 8 2;
$gutters: 1/3;

.first {
  @include grid-span(1, 1);
}

.main {
  @include grid-span(1, 2);
}

.second {
  @include grid-span(1, 3);
}

Spanning The Grid - Display

Grid Span display

Responsive Grid Context - Sass

// add-grid allows you to automatically change your global Grid Context at various breakpoints

$grids: 12;
$grids: add-grid(2 8 2 at 700px);
$gutters: 1/3;

.first {
  @include grid-span(3, 4);

  @include breakpoint(700px) {
    @include grid-span(1, 1);
  }
}

.main {
  @include grid-span(6, 7);

  @include breakpoint(700px) {
    @include grid-span(1, 2);
  }
}

.second {
  @include grid-span(3, 1);

  @include breakpoint(700px) {
    @include grid-span(1, 3);
  }
}

Responsive Grid Context - Display

Thank You