Zend certified PHP/Magento developer

RubySource: An Introduction to Haml

Haml is an XHTML Abstraction Markup Language that, according to haml-lang.com:

functions as a replacement for inline page templating systems such as PHP, ASP, and ERB

It can be used in many Ruby frameworks, such as Rails and Sinatra, in Node.jsPHP and .NET.

This article is going to introduce you to writing your HTML as Haml. As such it’s not going to contain much Ruby code. But if you’d like a more in-depth look at how Haml works under the covers, have a read of Xavier Shay’s excellent Code Safari articles on Haml: Getting Started in Haml and Haml, Compiling to Completion.

Installing Haml

To use Haml you’ll first need to install it. This shouldn’t be any harder than opening up your command line and typing:

gem install haml 

Now, lets look at how we can write some HTML using Haml.

!DOCTYPE

By default Haml usually defaults to the XHTML DOCTYPE. I say usually because if you’re using Rails 3 then Haml defaults to HTML5. You can change the default DOCTYPE using the :format option but, as this article is dealing with standalone Haml, we’ll look at how to write the DOCTYPE manually in our template:

  • HTML5 DOCTYPE

    !!! 5 

    Will produce:

    !DOCTYPE html 
  • XHTML Strict DOCTYPE

    !!! Strict 

    This gives us:

    !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" 
  • XML DOCTYPE

    !!! XML 

    Will output:

    ?xml version="1.0" encoding="utf-8" ? 

Tags and Attributes

Now we’ve taken care of the DOCTYPE, let’s look at how we can construct our HTML. We’ll start the basic template of a HTML document which in Haml looks like this:


%html
  %head
    %title Our Awesome Haml Template
  %body
    Abstracting HTML since 2006

When the above is compiled it will give us the following HTML:


html
  head
    titleOur Awesome Haml Template/title
  /head
  body
    Abstracting HTML since 2006 /body /html

You may have noticed that:

  • Haml uses whitespace and indenting to format the HTML.
  • Tags are prefixed with a %. Closing tags aren’t required.

So far, so good. But we’ll need to add a bit more content to our page and, with it, some more structure and semantics:


%body
  #container
    %header
      %h1 Our Awesome Haml Template
    #main Abstracting HTML since 2006
    %footer
      %address Ian Oxley

This gives us the following HTML:


body
  div id="container"
    header
      h1Our Awesome Haml Template/h1
    /header
    div id="main"
      Abstracting HTML since 2006
    /div
    footer
      addressIan Oxley/address
    /footer
  /div
/body

With more tags being added it should become more apparent how Haml uses whitespace and indentation to work out the structure of your HTML. But did you notice anything about how we got our div id="container" and div id="main" tags on to the page?

  • Haml assumes you are outputting a div tag unless you specify otherwise
  • id attributes are specified in the same way you write an id rule in CSS i.e. #container

You can also add class attributes to an element the same way you add an id attribute:


%footer
  %address
    .hcard
      .fn Ian Oxley
      .adr
        .locality Newcastle-upon-Tyne
        .country-name England

If you’ve been paying attention, you’ll have probably guessed that this will compile to:


footer
  address
    div class="hcard"
      div class="fn"Ian Oxley/div
      div class="adr"
        div class="locality"Newcastle-upon-Tyne/div
        div class="country-name"England/div
      /div
    /div
  /address
/footer

But what about other attributes that we will need to add to our markup? Things like lang, src, rel and href? Well that’s easily done using one of two methods:

  • You can use curly braces and specify your attributes with a Ruby hash. For example:

    %img{ :src = "/path/to/image", :alt = "Description of image" } 
  • Or you can use parentheses and use a more HTML-like foo=”bar” approach:

    %img ( src="/path/to/image", alt="Description of image") 

Both of these will output the following HTML:

img src="/path/to/image" alt="Description of image" 

Using this approach we can easily add CSS, JavaScript and any meta tags we need to our templates:


%meta{ :charset = "utf-8" }
%link{ :rel = "stylesheet", :href = "/css/master.css" }

Will give us:


meta charset="utf-8"
link rel="stylesheet" href="/css/master.css"

And:


%script{ :src = "/js/site.js" }

Will give us:


script src="/js/site.js"/script

Comments

Haml lets you add three types of comments to your markup:

  1. HTML comments
  2. Conditional comments
  3. Haml comments

HTML comments can be added using a forward slash ‘/’ but depending on where you place it will affect what gets wrapped in comments:


/ A forward slash at the start of a line wraps that line in a comment
%blockquote
  %p Roads? Where we're going we don't need roads
/
  A forward slash at the start of a nested block wraps the whole block in a comment
  %blockquote
    %p Roads? Where we're going we don't need roads

Once compiled our output will be:


!-- Only this line will be wrapped in a comment --
blockquote
  pRoads? Where we're going we don't need roads/p
/blockquote
!--
  Now the whole block will be commented out
  blockquote
    pRoads? Where we're going we don't need roads/p
  /blockquote
--

Conditional comments can be added by placing the condition in square brackets after the ‘/’:


/[if IE] %link { :rel = "stylesheet", :href = "/css/ie.css" }

This gives us the following HTML:


!--[if IE] link href="/css/ie.css" rel="stylesheet" ![endif]--

Haml comments are comments that included in the template file but not rendered in the final output. You specify them with -# and the same rules that applied to HTML comments apply here too:


%p The line below won't appear in the HTML
-# The rest of this line is a comment
%p The line above won't appear in the HTML, nor will the lines underneath
-#
  None of this nested text will appear
  in our rendered output either

This produces:


pThe line below won't appear in the HTML/p
pThe line above won't appear in the HTML, nor will the lines underneath/p

Adding Some Ruby Code

Whilst this article has focused on how you can write HTML using Haml, we couldn’t finish it without a brief bit on how to get some Ruby code into your template.

To insert some Ruby code, just add the '=' sign followed by the code. For example:


%p= Time.now

The code will be evaluated and output into the markup wrapped in p tags like so:


pSat Aug 06 15:06:09 +0100 2011/p

Running Haml from the Command Line

A great way to experiment with Haml is to run it from the command line. Just bung all your Haml code in one file and you can output the compiled template into another file like so:


haml input.html.haml output.html

So, that was a quick look at how you can use Haml when writing your HTML. If you’ve not used Haml yet hopefully it’ll encourage you to give it a try. Don’t forget to check out the Haml website at http://haml-lang.com where you can find loads more info, a complete language reference and can even take Haml for a test drive.

Update: I’ve put all the Haml snippets from the article into a Gist on GitHub. Feel free to fork away: https://gist.github.com/1147666