Putting the pieces together

Today I'm working on implementing one of my site designs into the template system for my current project, and I think it'll be interesting to clean up a bit in the process by starting from scratch, and document it here.

My prototype HTML pages are almost good enough, but I'm experiencing a bit of code bloat in the CSS. I seem to have cut some corners to get the prototypes completely ready for the client presentations.

Unfortunately I can't talk too much about the client or the subject of the site, but I'll try to describe in general terms what I'm doing, and post examples where I won't compromise my NDA.

I'm building a website that needs some slight skinning possibilities, as it'll be implemented as a branded “sub site” for our client's clients, so it's important to keep in mind that the brandable styles are grouped in one easy to access place.

Let's organize!

The first step I take is to identify and list all the different modules that need separate styling, and every part of the site that'll share global styles.

quickie layout demo

Let's dive right into it. As you can see from these crudely made wireframes, we have a header area with a horizontal top menu, a logo, and a search form. This area will be consistent through the site. Let's call the whole area .site-header.

Further down, on the front page, there's a sliding featured image gallery, definitely a unique module on the site. The site will offer a choice of three different featured image solutions for the front page. We'll call them .feat-panes (sliding images), .feat-masonry (A Masonry image wall), and .feat-thumb (A large wall of square image thumbnails).

Underneath the featured images there are a few text blocks. Text formatting will be consistent throughout, I'll talk more about that later. The first text block we'll call .intro, the next is a list of upcoming events, .events.events-small (As this will have slightly different styling than the main events list), and then we have a tag cloud, .tags / .pills (I'll make a generic “pill” rule that I can reuse whenever I need anchors to be pill-shaped).

The next page shows search results in a four column wide grid. I'll just apply a generic .grid-list to the container .search-results, and .column and .search-item { @include width(4); } (see article on my grid system) to the separate items so it all floats nicely.

The pagination and view options in the top and bottom need some styles as well. Chances are we'll have pagination in several places so I'll separate that into it's own module .pagination.

Cut to the chase, geek boy!

This is getting long winded. Hopefully you get the idea. I go through all the blocks and elements and try to define what can be a standalone module in my style sheets. In the end I'll end up with something like this:

/* MODULES */
.site-header {}
  .site-nav {}
  .site-logo {}
.search {}
  .search-small {}
.search-advanced {}
.featured {}
  .feat-thumbs {}
    .feat-thumb {}
  .feat-panes {}
    .feat-pane {}
  .feat-masonry {}
.intro {}
.events {}
  .events-small {}
.tags {}
.search-results {}
  .search-item {}
  .search-options {}
.pagination {}
.object {}
  .obj-img {}
  .obj-def {} /* <;dl><;dt>Title<;/dt><;dd>Description<;/dd><;/dl> */
.copyright {}
.related {}
.comments {}
  .comment {}
    .comment-img {}
    .comment-meta {}
.info {}
  .info-aside {}
.collections {}
  .collection-item {}
.cart {}
.site-footer {}
.site-copyright {}

/* GLOBAL + ABSTRACTIONS */
.rate {}
.share {}
.nav {} /* http://csswizardry.com/2011/09/the-nav-abstraction/ */
  .stacked {}
  .breadcrumb {}
  .dropdown {}
.grid-list {}
.row {}
  .column {}
.tooltip {}
.icon-* {} /* http://fortawesome.github.com/Font-Awesome/ */
.media {} /* http://www.stubbornella.org/content/2010/06/25/the-media-object-saves-hundreds-of-lines-of-code/ */
.note {}
  .error {}
  .success {}
form {}
.button {}
.ie {} /* UGH */

I'm sure I'll discover more in the process of marking all this up, but this is the list I start with. The indentation is kind of arbitrary, and should only serve as a guide for myself to make connections to elements that are visually or logically tied together.

Perl? In my HTML?

From here on I start marking up my templates. For this project I'm using the Perl based Template Toolkit. Not my favorite, but it does the job.

I won't go into much detail about the HTML/templates. It basically works like this:


    [% FOREACH item IN result.docs %]
  • [% item.title %]

    [% h.highlight(item.short_title) %]

    [% item.producer_role%]: [% h.highlight(item.producer) %] – [% h.highlight(item.from_year) %] [% IF item.to_year && item.from_year != item.to_year %] – [% h.highlight(item.to_year) %] [% END %]

  • [% END %]

As you can see it's pretty straight forward, though in my opinion Template Toolkit gets messy fast. But this part is undramatic so I'll just run through this and zoom along to the next part.

Setting some ground rules

If you read my previously mentioned article on grid systems, you'll know I use SASS to help me define a thing or two. You might not like the idea of CSS preprocessors, but I dare you to find a single reason why I shouldn't use it like I do. Seriously, write it up and tweet me, I'll listen.

So anyway, there are some things I know about this site. I know each single column should be 48 pixels, or 3ems, wide, and the gutters will be a half column wide. The headers are Palatino/serif and everything else is sans-serif (Helvetica or Arial, depending on what the browser/OS you use). The brand color is … Let's say lime green for this example (not the actual brand color). Base font size will be 100%, which is 16 pixels in almost every single browser, and line height is double. So how do we write all these defaults into SASS? Easy:

/* SITE SETTINGS */
// Fonts
$font-size:     16;
$line-height:   $font-size * 2;
$font-family:   sans-serif;
$font-header:   Palatino, serif;
// Colors
$brand:         lime;
$attention:     red;
$font-color:    #333;
// Grids
$column-width:  48;
$gutter-width:  $column-width / 2;

In the same go I add all my mixins and functions I need for browser prefixes and grid calculations. Once again I refer you to my previous article on grid systems. The mixins I didn't mention in that article are radial, linear, border-radius, box-shadow, border-box, content-box and transition, all to avoid having to write in those tedious vendor prefixes.

Back to basics

A good practice when writing up your style sheets is to start from the base styles, and add on outwards. With this in mind (it hasn't always been as obvious to me), I start by adjusting normalize.css to fit my design choices. I figure there's no point to leaving it as is, just to override the normalized styles later, so I adjust it to work as a starting point for my base style sheet, after removing most of the typography rules, as we'll define them in their own section.

In an effort to preserve the vertical flow, and keep everything on the baseline grid, I start by making sure every block element that can affect the successive elements' position has a margin-bottom of $line-height (32px/2rem). I also want every element to line up nicely with the grid columns, so I “reset” the left and right margins of a bunch of elements to 0.

h1,h2,h3,h4,h5,h6,hgroup,
ul,ol,dd,
p,figure,
pre,table,fieldset,hr,
.column, .columns,
.search-item,
.featured
{
    margin-top: 0;
    @include rem(margin-bottom, $line);
}
h1,h2,h3,h4,h5,h6,hgroup,
p,figure,
pre,table,fieldset,hr{
    margin-left: 0;
    margin-right:0;
}

With every change like this I do, I try to remove or change the corresponding rules in normalize.css. That way I keep my normalizations from being superfluous, and avoid confusion when sharing my styles with other developers. My general rule is: Block elements should have no top, left and right margins, and same margin-bottom as base line-height, and no set width or height. They should follow and uphold the flow, and be sized by content height and container width. Very rarely do I stray from this.

Yeah, but how does it read?

The base font size, used on paragraphs, form elements and … well, almost everything, will be 100%. I set this rule like this: html { font-size: 100%; } (Only necessary to override local user styles). The most common place to set a base font size is on the body element, but since I use rem sizes for everything, and I want to be able to resize the entire site up and down with media queries, I need to change the actual base font size, not just the body font size.

A lot of people advocate 62.5% base font size, so their calculations will be easier (1em = 10px), but since most of my sizes are multiples of 16 anyway, I don't really need any of that, plus all my calculations are done in a SASS function, so I never have to think about it. Philosophically I also have a problem with setting the base font size to 10px just to change it up to 16px, instead of just going with the desired font size in the first step.

Thanks to my SASS mixins, my typography base styles are really easy to write up. You've probably stopped reading and started skimming 15 paragraphs ago, so I'll just show you what they look like:

body, .normal {
    font-family: $font;
    color: $font-color;
}
p {
    max-width: 35em;
}
.lead, h4 {
    @include font-size($font-size + 1);
    font-weight: bold;
}
h3,h2,h1,
.subh,.h,.bigh,.biggerh,.gianth {
    font-family: $font-header;
}
h3, .subh {
    @include font-size($font-size * 1.25);
    @include line-height($line-height);
}
h2, .h {
    @include font-size($font-size * 1.5);
    @include line-height($line-height);
}
h1, .bigh {
    @include font-size($font-size * 2);
    @include line-height($line-height * 2);
}
.biggerh {
    @include font-size($font-size * 4);
    @include line-height($line-height * 3);
}
.gianth {
    @include font-size($font-size * 8);
    @include line-height($line-height * 6);
}

So why do I have these awkwardly named alternative classes on my type styles? I've adopted it as a good practice inspired by the article Don’t Style Headings Using HTML5 Sections by Nicole Sullivan, though I don't often use it for that specific case. I find that there are use cases where semantics and the visuals get mixed up a bit, and I need the styling to differ from what the markup would suggest. Plus a giant header comes in handy surprisingly often.

Modular docking snakes on a modular docking plane

… I … Yeah I ran out of ideas for sub headers. Snakes on a Plane? Really? You see, I was trying to go for a play on words about how I dock my content modules into their designated places, but the only thing I could think of was that. Sorry.

So, now that the awkwardness is apologized for, I wanna do a step-by-step on how I style up the tag cloud. The HTML for the tag cloud will be like this:


As you can see I've put three classes on the list element, .cloud, .nav and .pills. The nav class is lifted from Harry Roberts' 'nav' abstraction, and the cloud class expands on that.

In fact, I have several different extensions of the nav class. .comma makes a comma separated list, .stacked makes a vertically stacked list (I'm unsure about whether this is the right way to do this, but it works), .breadcrumbs makes … wait for it … breadcrumbs. And then there's .pagination that puts some spacing and a border around the list items.

/* NAV ABSTRACTION AND EXTENSIONS */
.nav {
  list-style:none;
  margin-left:0;
  padding-left:0;
}
.nav li{ display:inline; }
.nav a { display:inline-block; }
.stacked li { float: none; display: list-item; }
.stacked a { display: block; }
.breadcrumb > :before { content:"» "; }
.breadcrumb > :first-child:before { content:normal; }
.comma > :after { content:", "; }
.comma > :last-child:after { content:normal; }
.pagination li { 
  @include rem(margin-left, 4); 
  border: 1px solid $extra;
}
.pagination a { height: 100%; }
.cloud a {
  color: white;
  background-color: $extra;
  padding: 3px 10px;
  margin: 0;
  @include rem(margin-right, 5);
  @include rem(line-height, $font-size);
}
.cloud li { @include rem(line-height, $line); }
.cloud a:hover { background-color: $brand; }

This is a bit of a simplification of the actual styles, the actual thing has more visual information.

The pills class just tells us that containing elements should have round corners, so I avoid repeating a whole bunch of vendor prefixes every time I want completely round corners. I use two classes for that, .pills, for when I want to style many anchor elements inside a parent element, and .pill, for when I just want to style one single element with rounded corners.

.pills a, .pill {
    @include border-radius(999em);
}

As you can see the 'nav' abstraction is very versatile. I use it pretty much every time I need a list of links to be displayed in any way other than this:

I treat almost every part of my site in the same way. Usually it's only a matter of thinking “How can I make this simpler?”, and of course to study how other people do it. The day I first read the FAQ for Nicole Sullivan's OOCSS was the day I changed the way I write my front end code entirely. Then I progressed from there to study Jonathan Snook's SMACSS and Harry Roberts' blog. While I don't always agree with them, they have helped me turn my work completely around from being a bloated, nested mess to being lightweight and highly scalable.

Oh God, I messed up!

While I was marking up and styling the search results, I realized that the meta data on the search result items may possibly push the heights to be uneven, which means they won't float properly. So what do I do? Here's the thing, we have this nav abstraction concept that could possibly do the job. But there's a problem with floating something like this with inline-block: The items won't line up properly, because there will be spaces inserted between the list items. So I have to be a bit creative with the HTML to make it work. I have no words for how much this bugs me, but a deadline is a deadline and this is the solution I can come up with right now: I have to remove all white space between the list items… The list markup will now look like this:

  • Title

    Title

  • Title

    Title

  • Title

    Title

  • As this search result is so far removed from the other .nav use cases, I've decided against reusing the nav class for this. Here's the CSS I've written up to solve this annoying problem:

    .search-items {
    	list-style: none;
    	padding: 0;
    }
    .search-item {
    	display: inline-block;
    	vertical-align: top;
    	@include width(4);
    	@include rem(margin-left, $gutter);
    }

    The search results will now line up perfectly fine, while pushing the next row down properly. It's a bit of a dirty solution, but since I'm the one writing the markup I feel confident that this will do just fine for this project.

    Grid is the new black

    Now let's skip ahead a few steps. I've written up the markup for everything I need, and I'm ready to put it all in the right places. I've already added rows where I need them, and column classes on blocks I know will be floated grid elements. This is traditionally the boring part of the job, but luckily I've simplified the process quite a bit, so I only have to make the choice of how many column widths an element should span at a given browser width.

    The search results grid list is already done, as it'll wrap neatly no matter if our layout is 16, 12, 8 or 4 columns wide.

    A good example of what happens in my media queries at different widths is the text area on the front page. At 16 columns wide the big text block is 8 columns wide and the smaller ones are 4 each. At 12 columns wide the big one drops to 6 columns and the small ones to 3 columns, then at 8 columns, the big text block is back at 8 columns wide and the smaller ones 4 columns each. At 4 columns all the blocks are full width.

    Medium sized text box
    Small text box
    Small text box
    //4col
    @media screen and (min-width: 12.5em) {
      .text-m, .text-s {
        @include width(4);
      }
    }
    //8col
    @media screen and (min-width: 40em) {
      .text-m {
        @include width(8);
      }
      .text-s {
        @include width(4);
      }
    }
    //12col
    @media screen and (min-width: 60em) {
      .text-m {
        @include width(6);
      }
      .text-s {
        @include width(3);
      }
    }
    //16col
    @media screen and (min-width: 84em) {
      .text-m {
        @include width(8);
      }
      .text-s {
        @include width(4);
      }
    }
    //20col
    @media screen and (min-width: 100em) {
      html {
        @include font-size($font-size + 4);
      }
    }
    //24col
    @media screen and (min-width: 125em) {
      html {
        @include font-size($font-size + 6);
      }
    }
    

    See those two last media queries there? They jack up the size of the entire site so users with big and very big monitors can really put their screen real estate to good use. The only thing that happens in my media queries for this site is size changes and font-size changes. I've designed to float in desirable ways so I don't really need to worry about the adaptiveness of it all more than necessary.

    Obviously I haven't gone through every single part of the site in this article, I just wanted to share parts of my process. There's still a way to go to get this beast production ready, but most of the grunt work is done and the CSS is lightweight and modular, like I want it to be. If you have any questions, or objections, please let me know through Twitter and we'll talk.

    Also, if you have any thoughts about what I should ramble on about next, feel free to mention it. I have some ideas but I'm happy to help and explain any part of the process. It helps me consider my ways, and hopefully it helps other people too.

    zp8497586rq

    Comments? Tweet me!