Notes from My Workshop at Webstock ’13

Published by Chris Coyier

I thought my trip to New Zealand for Webstock warranted a special workshop. In honor of their unique national bird, I created a little one-pager website The Kiwis of New Zealand. The site started life as a simple Photoshop document and during the workshop we turned it into a complete finished website. Below is a list of everything we covered in that process.

The design was largely "laptop first". Not designed for a tiny screen or an enormous one, but the design is so simple it won't be too hard to make it fluid and adapt to different screen sizes. There is nothing sacred about the canvas size originally chosen in the Photoshop file.

The font in use is Proxima Nova. I happen to own it so I could work with it locally, but on the web we used it through Typekit. It has many weights and styles, which is fantastic, but loading all of them on the web would be very heavy and slow. Instead we only picked Thin, Regular Italic, and Semibold which weighed in at 77K.

In our SCSS, we made a note of which weights we had available so we make sure to be specific about that and not risk a browser faux-bolding or faux-italicizing.

body {
  font-family: "proxima-nova", sans-serif;
    Thin: 100
    Regular Italic: 400
    Semibold: 600

In the kit settings, we told TypeKit it's OK to serve this kit on our local development domain as well as where the final site will live.

Speaking of local development, ours consisted of editing code in Sublime Text (now in v3).

We used CodeKit to watch our project folder which handled preprocessing, image compression, and JavaScript minification/concatenation for us.

We made a local domain name to work from using MAMP. This gave us the ability to use PHP, which we took advantage of to use include()s to work in smaller modular chunks. Every bit of code we wrote, be it CSS, HTML, or JS, was in small modular chunks. Having a "real" domain to work with instead of a file:// URL meant:

  • We can include resources from the root. E.g. src="/js/file.js" which I think is a nice convention as it becomes very obvious where that file really lives.
  • We can tell a service like Typekit our local development domain so the fonts can be served there.
  • We can do thinks like make Ajax requests, which you can't unless at a "real" domain due to browser security restrictions.

Our typography rules were very simple. The UA stylesheet rules for typography are pretty OK and we just adjusted a bit as needed. For instance, the line-height for headers is different than the base line-height.

All font-sizing, and in fact even all margin and padding on the site was set in EMs. That means all sizing/spacing has a direct relationship to the font-size on the body, which we adjust at different breakpoints.

Many of our headers had different parts of them set thicker and in a different color than the rest of the header. But this was just a visual effect, not for emphasis. So, the <b> tag was perfect, which is just for styling and not for emphasis.

We used box-sizing everywhere because it's just all-better all-the-time. In our case, we used floats to make a simple grid. The math is a lot easier when our em-based padding comes from the inside of the percentage-based fluid columns.

Because we used floats for a variety of things, that means needing to clear those floats for layout integrity. Our browser target (IE 9+) was such that we could use a very simple clearfix.

.clearfix:after {
  content: "";
  display: block;
  clear: both;

Instead of using that class name in the HTML where we need it, we made a placeholder selector instead:

%clearfix {
  &:after {
    content: "";
    display: block;
    clear: both;

Then whenever we need to clear a float on a particular element, we can just extend that placeholder:

.page-wrap {
  @extend %clearfix;

This makes for a very efficient final selector. Just a comma-separated list of everything that needs clearing.

That placeholder selector we put into a file called _bits.scss. The underscore at the beginning of the file name is just a convention that means "this file is a partial to be included elsewhere, not to be compiled on its own."

My own convention for that file is to put little "bits" that don't compile into anything, but are useful elsewhere. For example variables:

$green: #51cd4b; /* Don't get fancy, get memorable. */

The breakpoint @mixin had different mutually-exclusive breakpoints as well as a retina test:

@mixin bp($point) {
  @if $point == 'baby' {
    @media (max-width: 600px) { @content; }
  @if $point == 'mama' {
    @media (min-width: 601px) and (max-width: 1100px) { @content; }
  @if $point == 'papa' {
    @media (min-width: 1101px) { @content; }
  @if $point == 'retina' {
    @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { @content }

This makes working with media queries super easy and logical. Note the "Three Bears" style naming convention. Better that than names of specific devices that will become meaningless over time.

When using this bp() mixin, The properties/values you are changing are right next to each other in the authored code, not in some far-away block. For example the grid at different widths:

.module {
  float: right;
  @include bp(mama) {
    width: 31%;
    margin-left: 3.5%;
    &:nth-child(3n) {
      margin-left: 0;
  @include bp(papa) {
    width: 48%;
    margin-left: 4%;
    &:nth-child(2n+1) {
      margin-left: 0;

And placeholder selectors are great for repeated bits of code:

%texture-light {
  background: url(../images/subtle_dots.png);
  @include bp(retina) {
    background: url(../images/subtle_dots_@2X.png);
    background-size: 27px 15px; /* Size of non-2x version */

It might be tempting to use a @mixin for something like that, but placeholder/@extend is slightly more efficient when using multiple times.

The "texture" was subtle dots, which I inverted in Photoshop to make the dark version for the footer.

The kiwi bird graphic is a vector shape. That's perfect for SVG. We grabbed her from a stock photo and cropped her down to size in Adobe Illustrator, which can save out natively as SVG. We could have linked it up as a or placed as a background-image of another element, but doing it that way doesn't give you DOM-access and ability to style via CSS. Instead, we PHP include()'d the SVG right into the HTML.

<svg class="logo" viewBox="0 0 522.342 410.83">
  <path id="bird" d="..." />

Notice the ID on the path? We can literally target that shape right in CSS and use special SVG CSS to affect it. Here we are setting the color (with our Sass variable) and applying a hover color change (with a Sass color function):

#bird {
  fill: $green;
#bird:hover {
  fill: darken($green, 10%);

Our targetted browsers all support SVG, but if we needed to do a proper fallback, Modernizr is perfect for that. The most efficient way would be to have two elements on the page.

<div class="logo-fallback"></div>

Modernizr will give you a class name on the element if SVG is supported or not.

.logo-fallback { display: none; }
.svg .logo-fallback { background-image: url(logo.png); }

That resource (in most cases) won't load if SVG is supported.

The button in the footer we created with just CSS3 stuff like border-radius, text-shadow, and gradients. Compass is a great add-on for Sass for these types of things. We don't need prefixes for border-radius, but we certainly do for gradients, and writing that @mixin by hand would be incredibly difficult.

With Compass loaded (very easy in CodeKit), we can use its background() @mixin for the gradient:

.button {
  @include background(
    linear-gradient(#89f784, #068925)

Which compiles into what I call a pile of "robot barf" - CSS that would be tedious and error prone at best to write by hand. Things get even barfier if you have Compass give you an SVG version of the gradient for better IE 9 support.

@import "compass/css3";
$experimental-support-for-svg: true;

In the :active state of the button, we remove the bottom border and move it down the width of the border for a faux 3D effect. The movement we do with translateY(), because it's a design movement choice, not a positioning concern.

Fluid and adapting layout is part of responsive design. Loading proper content is another. We use the map in the footer to illustrate this. At our "baby" screen size, we load a static linked map, which is better for mobile devices. At our "mama" size or larger, we load an iframed Google Map. More info from Brad Frost.

We achieve this different content by Ajaxing it in with jQuery when our media queries match. We use Enquire.js to test for this and give us the callbacks we need.

The project is on GitHub here. And demo here.

It's probably worth going deeper with browser support on it. Maybe that would be a good screencast.

Last but not least: real Kiwi birds really are in trouble and you can help.