Grow your CSS skills. Land your dream job.

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.


  1. Alastair Moore
    Permalink to comment#

    Thanks for this overview, Chris. Some useful ideas in there to improve my SCSS usage!

  2. Permalink to comment#

    Wow, I had no idea that @extend even existed. SASS gets better and better the more I use it.

    Permalink to comment#

    Is @extend working like @inlcude?

    • Sort of.

      @extend enables you to include previously declared styles into a new declaration. @include is for mixins, @extend is for style blocks.

      So for example:

      .red {color: red;)

      .red-bordered {
      @extend .red;
      border: 1px solid black

      Once compiled .red-bordered will become

      .red-bordered {
      color: red; /* This style is extended in from the .red style block */
      border: 1px solid black

      because the declarations contained within the .red block have been “extended” into it.

      But it gets better – as show in Chris’ example site you can create “placeholder” styles – these are declaration blocks which won’t show up in your stylesheet anywhere after compilation, (just use a %sign in front of the declaration block) instead they are designed to be used for extending other styles – just @extend the placeholder into a style block and you’ll get all the styles.

      For example:

      %red {color: red} /* This won’t compile into your stylesheet */

      red-bordered {
      @extend %red;
      border: 1px solid black

      Will also compile to:

      red-bordered {
      color: red;
      border: 1px solid black

      Another huge timesaver from SASS/Compass!

      Note: You can’t extend into media queries from outside of them. So if a style is declared outside of your current media-query you can’t use it as an extend within your media-query.

      More info here:

      (BTW I know these class names are horrible and should never be used in production).

  4. Fred Lunjevich
    Permalink to comment#

    Thanks for this Chris — I was one of the lucky few to witness this workshop live. I can honestly say it was the best 3.5 hours I spent learning about web design ever. Cool tools, very accessible to the novice and professional alike (I’m somewhere in between!)

  5. Permalink to comment#

    You might wanna look at the mobile ‘version’, can’t read all the text (no hover) and the static map image isn’t there :P

    Other then that, great read and nice one-pager!

    • iOS activates tap-on-hover, so it works OK, although it’s not super discoverable. Not sure how other mobile browsers handle it – I predict not as well.

      The amount of text kinda suggests it should just show it all. Happy to take pull requests.

    • Permalink to comment#

      I tried tapping, didn’t work.

    • Permalink to comment#

      Ah yes… my bad! I didn’t try tapping on the picture, that does work. However tapping on the text doesn’t work on iOS (tested on iPhone 4S and iPad3), while it does work on Galaxy SIII.

  6. Permalink to comment#

    Thank You for sharing Chris!
    Really shows me how much more I need to learn.

    Excellent finishing touch with the simple animation on the Kiwis when your resizing!

  7. Ed Melly
    Permalink to comment#

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

    Do you have any information on the specifics here? i.e. under what circumstances will both assets be downloaded?

  8. Permalink to comment#

    The only thing that strike me as odd is that it seems like the widest-layout and the second-widest-layout switched place. Shouldn’t there be a three column layout for the widest and a two column one for the one step smaller breaking point?

  9. Permalink to comment#

    Thanks for this overview @chris.

  10. Piers George
    Permalink to comment#

    I’m a big fan of your breakpoint mixin, however when building a module mobile first how do you easily gather all the scattered Papa bear breakpoint styles for an IE non-media query supporting stylesheet?

  11. Wonderful.
    If only I had the time to improve all these things…
    But work is work… ;(((

  12. Martin
    Permalink to comment#

    Thank you for your tutorial. Why did you position .module relatively?


  13. 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.

    This might be the reason I finally switch back to sizing in ems.

  14. Permalink to comment#


    is there any thing special that you have used relative position module?

  15. MikeyH
    Permalink to comment#

    Dig the design principle; but I’m curious as to what you used for the mapping feature for adding the sightings. I’m actually adding a very similar feature to a site now… I’m implementing a pretty good plugin but am finding it a little tedious. Can you tell me if this is your own code or WP, or what?

  16. Simone
    Permalink to comment#

    Thanks Chris, it was a great session – I had heard of some of the tools that you used but now I feel like I could start using them straight away. The notes will come in very handy to explain my own scribblings.

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".