Hi! I'm Olav Bjørkøy, a web developer from Trondheim, Norway. I once created the Blueprint CSS Framework, and am now working on other projects and writing a few articles. Read more.

bjorkoy.com

03 Sep 2010

Page Width and Device Independence

Page width has to be one of the most debated aspects of web design. The discussion used to revolve around fixed versus fluid layouts, and in the case of fixed layouts, the maximum width a website could use without invoking the dreaded horizontal scrollbar.

Recently the notion of device-specific layouts and page widths has been all the rage, through the use of media queries, user agent matching and dynamic layouts with Javascript. For instance, by using CSS media queries, a site can serve up different layouts to phones, tablets and computers based on their respective screen sizes.

Altering content based on screen width is a wonderful and powerful feature, but there’s a few caveats to remember. If you’re designing a typical website, but have a specific device in mind, you might be doing something wrong.

There’s an ever increasing spectrum of device screen sizes, and while some devices are more popular than others, using exact matching to customize a layout to a specific device brings back memories of “this site can only be viewed through IE6 or newer”. Common sense dictates that the spectrum will become more homogenous over time. Right now, there seems to be three main screen width steps represented by phones, tablets and computers, but new devices will surely pop up in between these ill-defined plateaus.

In designers terms, this means that a site should work fine with any screen width, just as it should work fine with any screen height. We can expect users to scroll vertically, but expecting users to continuously scroll in two dimensions is no solution. Page width has to be device independent, not device-specific.

The ideal solution then seems to be to use a fluid layout, with tools such as media queries to fluidly add, move or remove elements as the screen width changes, but not to identify the actual device in use. This way, the layout is not dependent on any one device or window size, but usable on any current or future device screen.

25 May 2010

Contextual Fluid Grids

While reading A List Apart’s latest article on responsive web design, their particular use of fluid grids from a previous article struck me as odd. There seems to be two ways to create such grids – trying to work around context or using it to your advantage to create contextual fluid grids.

There are two things that may seem difficult about creating fluid grids: how to use context and how to employ margins. The technique in the ALA article computes widths and margins through calculations given the current context, i.e. by using the width of the closest container element in relation to the total page width. In contrast, I prefer embracing context which results in a system that is as powerful yet simpler to use.

Take a look at this demo page to see what we’re trying to accomplish. Try resizing the browser window and the text size.

Embrace context

Context can be used by letting every container element define its own sub-grid. For instance, if we have a row element, we can divide this element into a number of columns. Each of the column elements in the container can again define their own grids with the same number of columns as the first container. The basic insight is that context can be used without any special computations. Consider the following HTML:

<div class="row">
  <div class="span12">50%</div>
  <div class="span12">50%</div>
</div>

<div class="row">
  <div class="span12">50%</div>
  <div class="span12">
    <div class="row">
      <div class="span12">25%</div>
      <div class="span12">25%</div>
    </div>
  </div>
</div>

Ignore the lack of semantics, the class names are there for ease of explanation. The first row in this example has two columns spanning 50% of the page width. The second row first has one column spanning half the page width, and then two columns spanning 25% of the page. Pretty simple.

Notice that all spans use the same column numbers. Here, the total number of columns is 24. The second column in the second example spans 50% of the page width, and is divided into 24 new columns. Since the wrapping element is 12 columns wide, 12 columns in the context of this element corresponds to 6 columns, or 25% of the page width. By embracing context, the grid can be as complex as you want without having to calculate precise floats.

Programming the grid

As I mentioned in a previous post, the task of creating grids lends itself well to CSS extensions such as SASS. This is true both for fixed and fluid setups. By specifying the number of columns each primary and sub-grid should have, creating a semantic and flexible implementation is quite simple. Calculations are done with percentages and EMs to ensure proper fluidity and support for text resizing.

$grid_columns: 24;        /* number of columns */
$total_max_width: 950px;  /* max page width */

/* compute width of 1 column */
$grid_col_width: 100% / $grid_columns;

/* create a div spanning n columns */
@mixin col($n: 1) {
  float: left;
  @include span($n);
}

/* make an element span n columns */
@mixin span($n: 1) {
  width: ($n * $grid_col_width);
}

/* prepend n empty columns */
@mixin prepend($n: 1) {
  margin-left: $grid_col_width * $n
}

/* append n empty columns */
@mixin append($n: 1) {
  margin-right: $grid_col_width * $n
}

/* define max width in EMs for proper grid resizing */
body { 
  font-size: 100%; 
  max-width: ($total_max_width / 16px) + em; 
} 

/* a row defines a new grid or subgrid */
.row { float: left; width: 100%; }

/* mixin example usage */
#menu { @include col(5); }
#side { @include col(5); }
#main { 
  @include prepend(1);
  @include col(12); 
  @include append(1);
}

/* For the html example */
@for $i from 1 through $grid_columns {
  .span#{$i}    { @include col($i); }
  .prepend#{$i} { @include prepend($i); }
  .append#{$i}  { @include append($i); }
}

Columns as margins

You may have noticed that this example does not consider margins as a part of the column definition. Fluid margins is often the aspect that makes creating such a grid difficult. Ensuring that margins span the same width across context, and that the widths they span don’t get too small to be rendered, can be a pain.

The proper approach is to see margins between columns as empty columns, not as empty gaps between columns. That is, the columns themselves do not have specified margins. Instead, empty columns are appended or prepended where margins are needed. This makes sense as margins between columns in fluid layouts almost always span greater widths than that of their fixed counterparts. And, if your require fixed margins, they can always be applied to an inner element of a column (as in the demo page).

However, we often need narrow margins, even in fluid layouts. To accomplish this, a high number of columns is needed, as columns now not only specify the width of a column, but also the negative space between them. As always, choosing a number with a high divisor count is essential. The best approach is to use a highly composite number (a positive integer with more divisors than any positive integer smaller than itself) such as 6, 12, 24, 36 or 48. This gives you the most flexibility in creating grids with applicable divisive features.

The result is a simple fluid grid which, because of the use of contextual sub-grids, can be as complex and specific as you need. By using an extension such as SASS, no complex calculations have to be done, or re-done when the design needs a change.

22 May 2010

Semantic CSS Grids With SASS

You design websites, and since you’re brimming with empathy, you want to use a grid-based layout to ensure a minimum amount of confused users. Great! However, you also design a lot of websites, and find yourself doing the same operations for setting up a basic grid at each ⌘+N. Not good.

The way to fix this is a sort of design framework. The problem with such a framework has often been mixing presentational logic with your sweet HTML hierarchy. Nuts to that, you say, I’d like both my CSS and HTML clean and semantically correct. Well, here’s a way to get the best of both worlds.

Using SASS, or any other equivalent CSS extensions, defining functions and variables lets you set up a grid while you stay away from anything less than semantically correct. Here’s a setup of variables and mixins I’ve been using lately:

/*
  Choose a grid width, the number of columns and the margin between columns.
  The result of the following equation has to be an integer, not a fraction:
  
  (width - (columns - 1) * col_margin) / columns = N
*/

$width: 960px;   /* total with of page */
$columns: 24;    /* number of columns */
$col_margin: 0;  /* margin between columns */

/* math magic */
$col_width: ($width - ($col_margin * ($columns - 1))) / $columns;
$col_total_width: $col_width + $col_margin;  

/* create row div */
@mixin row() {
  float: left;
  clear: both;
  width: $width;
}

/* create a column div */
@mixin col($n: 1) {
  float: left;
  @include span($n);
}

/* make an element span n columns */
@mixin span($n: 1) {
  width: ($n * $col_width) + (($n - 1) * $col_margin);
  @if $n == $columns {
    margin-right: 0;
  } @else {
    margin-right: $col_margin;
  }
}

/* the last column in a row needs this */
@mixin last() {
  margin-right: 0;
}

/* prepend n blank columns  */
@mixin prepend($n: 1) {
  margin-left: $col_total_width * $n
}

/* append n blank columns */
@mixin append($n: 1) {
  margin-right: $col_total_width * $n + $col_margin
}

The attentive reader will note I’m using the new SCSS syntax found in SASS 3. This is great, since the syntax is completely compatible with CSS (at least CSS 3), ensuring sweet validation of your files. Because these are mixins, your CSS classes and ID’s can still retain semantic names, and the presentation logic remains where it should be:

.section { @include row; }
.section .main { @include col(18); }
.section .sidebar { @include col(6); @include last; }
.section .promo { 
  @include col(12); 
  @include prepend(6); 
  @include append(6); 
  @include last;
}

If you’re making an extensive site from scratch, or rarely doing new projects, I would suggest using the manual approach. This technique is more for those of us that sometimes needs a conveyor-belt type of web design output. Either way, the point to remember is that a lot of CSS logic lends itself well to programming, and by using an extension such as SASS, much manual labour can be offset by functions and variables.

15 May 2010

Blogging With Jekyll, Git and a VPS

Welcome to another installment in the never-ending story of my quest for the perfect blogging setup. This time, we stray far from the conventional use of content management systems, shared hosts and database storage.

Yes, like so many others, I’m jumping on the bandwagon of using a local setup for generating blog posts, and then publishing the final HTML to my server using Git. Here’s the setup:

  1. Every blog post is a new file on my machine, ensuring great portability and an easy transition to future systems (yes, it will happen). Post files can be anything from markdown and textile, to html and plain source code.
  2. To generate the final site, each post and page is processed by Jekyll, which has support for layouts, partials, syntax highlighting, automatic regeneration and so forth.
  3. The finished HTML is pushed to a git repository on my Slicehost VPS, which gives me full control over the final result.

You can probably see the benefits and drawbacks of this system, so instead of listing pros and cons, I’ll show you how to set it up.

Jekyll has a great wiki describing its many features. You’ll also find examples of how others have customized their installations in the “sites” section. The only mildly interesting thing I did was to make a script for quickly creating new blog post files:

# Create new jekyll post and open in textmate
# $ ruby _new.rb This is the title

# The arguments form the title
unless ARGV[0]
  raise "Please provide a post title."
end

# Create a URL slug from the title
def slugify(title)
    str = title.dup
    str.gsub!(/[^a-zA-Z0-9 ]/,"")
    str.gsub!(/[ ]+/," ")
    str.gsub!(/ /,"-")
    str.downcase!
    str
end

# Create parameters
title  = ARGV.join(' ')
slug   = slugify(title)
prefix = Time.new.strftime("%Y-%m-%d")
file   = "#{prefix}-#{slug}.markdown"
path   = File.join(File.dirname(__FILE__), "_posts/#{year}/#{filename}")
text   = <<-eos
---
title: #{title}
layout: post
---

eos

# Create a new file and open it in textmate
File.open(path, 'w') { |f| f.write(text) }
system("mate #{path}")

By the way: Jekyll has built in support for using latent semantic indexing to create lists of related posts. It’s a slow implementation of a computationally demanding technique, but at the same time, very cool.

When jekyll has generated the html in its “_site” folder, it’s time to upload the new post to the web server.

To upload new content to the server, I use the setup described in this guide. Three distinct git repositories are established to provide the perfect workflow, where publishing a post is as easy as committing and pushing the new post to the server.

My local copy is stored in the first repo. On the server, there is a “live” repo, which is the site served by apache, and a “base” repo which facilitates synchronization between the two other repos. My local changes are pushed to the base repo, which tells the live repo to update its content. The point is to avoid pushing content to a repo containing a working copy - using three repos is way easier. The guide has all the details if you wan’t more on this setup.

All that’s left is creating a virtual host in apache, it’s document root pointing to the “_site” folder in the live repo. My server also have PHP and MySQL installed, so that my Mint installation can reside in the same repo as the rest of the jekyll files. Sweet!

There’s something greatly reassuring about having a separate markdown file for each blog post, a point underlined by the annoying xml-parsing I did to migrate my old posts into this new system. My posts are safer than ever and can be written in any environment I see fit. In the end, this is a system only a programmer would love, but also the only system I, as a programmer, do love.

14 May 2010

Conway's Game of Life in Ruby

#
# Conway's Game of Life in Ruby
# http://en.wikipedia.org/wiki/Conway's_Game_of_Life
# 
# Some code from this excellent article:
# http://rubyquiz.strd6.com/quizzes/193-game-of-life
#

class Cell
  attr_writer :neighbors
  
  def initialize(seed_probability)
    @alive = seed_probability > rand
  end
  
  def next!
    @alive = @alive ? (2..3) === @neighbors : 3 == @neighbors
  end
  
  def to_i
    @alive ? 1 : 0
  end
  
  def to_s
    @alive ? 'o' : ' '
  end
end

class Game
  
  def initialize(width, height, seed_probability, steps)
    @width, @height, @steps = width, height, steps
    @cells = Array.new(height) { 
      Array.new(width) { Cell.new(seed_probability) } }
  end
  
  def play!
    (1..@steps).each do
      next!
      system('clear')
      puts self
    end
  end
  
  def next!
    @cells.each_with_index do |row, y|
      row.each_with_index do |cell, x|
        cell.neighbors = alive_neighbours(y, x)
      end
    end
    @cells.each { |row| row.each { |cell| cell.next! } }
  end
  
  def alive_neighbours(y, x)
    [[-1, 0], [1, 0], # sides
     [-1, 1], [0, 1], [1, 1], # over
     [-1, -1], [0, -1], [1, -1] # under
    ].inject(0) do |sum, pos|
      sum + @cells[(y + pos[0]) % @height][(x + pos[1]) % @width].to_i
    end
  end
  
  def to_s
    @cells.map { |row| row.join }.join("\n")
  end
end

Game.new(100, 50, 0.1, 100).play!