Stylish Rails

Scaffolding in Ruby on Rails 2.02 is very simple to use and a great time saver. However, the views that are generated are very, um, well they’re just plain ugly. In addition, they’re not very accessible to users with older browsers or that use assistive technology.

Of course everyone that codes in Rails is an expert in CSS of has access to a professional web designer who can clean up those ugly and inaccessible views really quick, right? Well, not in my one-man show. And all of the reference material that I’ve read on Rails skips over the part that explained how to make your views presentable, usually by simply stating: “Magic Happens Here”. So I learned styling the hard way – by reading everything I could get my hands on.

In this post I’m going to demonstrate how to apply simple styling to scaffold generated views using CSS. I’ll demonstrate how to markup and style a simple form layout that includes a border with a legend and right-justified field labels. Sure, there are plugins you can get to help you out but what fun would that be? Besides, everyone has their own style.

I will be referencing the excellent SitePoint book The Art and Science of CSS. In particular, Chapter 5: Forms, written by Cameron Adams, provides an excellent step-by-step tutorial on creating attractive and accessible forms.

Note that I’m assuming you already know how to use the Rails 2.0 scaffolding feature. If not, there’s lots of material out there that can get you up to speed.

Creating the appropriate markup

The first thing you need to do is to add form markup that contains the necessary elements to refer to in the CSS style sheet. In particular, you will need to add <label> and <legend> tags. These tags not only help with styling specific parts of the page but also permits users of assistive technology such as screen readers to use your site. If you take a look at the scaffold generated markup you’ll see that it does not have these tags:


<h1>New todo</h1>

<%= error_messages_for :todo %>

<% form_for(@todo) do |f| %>
  <p>
    <b>Name</b><br />
    <%= f.text_field :name %>
  </p>

  <p>
    <b>Description</b><br />
    <%= f.text_field :description %>
  </p>

  <p>
    <%= f.submit "Create" %>
  </p>
<% end %>

<%= link_to 'Back', todos_path %>

So let’s add those tags now.

In the rhtml template new.html.erb wrap everything inside of the block with <fieldset> tags and underneath the opening <fieldset> tag add a legend using <legend> tags.


<h1>Create gift exchange</h1>

<%= error_messages_for :gift_list %>

<% form_for(@gift_list) do |f| %>
<fieldset>
  <legend>Gift exchange</legend>
    <p>
      <b>Name</b><br />
      <%= f.text_field :name %>
    </p>

    <p>
      <b>User</b><br />
      <%= f.text_field :user_id %>
    </p>

    <p>
      <%= f.submit "Create" %>
    </p>
</fieldset>
<% end %>

<%= link_to 'Back', gift_lists_path %>

If you save your changes and refresh your browser you should now see your fields surrounded by a border with a legend name.

Basic Styling

Basic Styling

One of the benefits of using the legend tag is that a screen reader will read out the legend text “To do list; Name”.

Next, for the field entry portion of the form replace all of the <p> tags with <li> tags and then wrap the <li> tags with an <ol> (ordered list) tag. The ordered list gives us the ability to add margins and padding to all of the field items and makes the form quite readable in absence of styles such as is the case with older browsers.

Finally, we’re going to give our field names (i.e., “Name” and “Description”) some labels with the <label> tag. Check it out:


<% form_for(@todo) do |f| %>
<fieldset>
  <legend>To Do list</legend>
  <ol>
    <li>
     <label for="name">Name</label>
      <%= f.text_field :name %>
    </li>

    <li>
      <label for="name">Description</label>
      <%= f.text_field :description %>
    </li>
  </ol>
</fieldset>

The last markup change we’ll do is move the <%= f.submit “Create” %> erb tag within its own <fieldset> tag. That may sound a little weird, but the <fieldset> tag is a great way to group multiple actions at the end of a form such as “submit” and “cancel”. We’ll also give this <fieldset> a class of its own names “sumbit”.

<fieldset class="submit">
  <p>
    <%= f.submit "Create" %>
  </p>
</fieldset>

If you save your changes and refresh your browser you’ll notice you page has decidedly taken a step backward, i.e. the field elements are no longer aligned.

Form Using <fieldset> tag

Form Using Fieldset Tag

That’s ok because the markup changes we’ve made now gives as complete control over how we want to style this sucker!

Using the Scaffold Style Sheet

There are several ways you can layout the form: for example you can position the label directly above the form element, in a separate left column that’s left-aligned or as a separate left column that’s right-aligned. In this example I’m going to go with a separate left column that’s right-aligned. I’m going to go with this option because a right-aligned column layout allows for a quick association between the field label and the field element.

Now it’s time to open the scaffold.css file located in the public/stylesheets directory. As you can see, there’s already quite a few style tags in scaffold.css. We just need to add styles for the legend and both both fieldsets. At the same time, we’ll add a little background-color to the fieldset element. Let’s add the following styles to the bottom of scaffold.css:


fieldset {
    float: left;
    clear: left;
    width: 100%;
    margin: 1.5em 0 0 0;
    padding: 0;
    border: 1px solid #BFBAB0;
    background-color: #F2EFE9;
}

legend {
    margin-left: 1em;
    color: #000000;
    font-weight: bold;
}

fieldset ol {
    padding: 1em 1em 0 1em;
    list-style: none;
}
fieldset li {
    padding-bottom: 1em;
}

If you refresh your browser now you should see nicely spaced field and labels, however, you’ll notice the field elements are not aligned.

Let’s fix that next with a label style:


label {
    float: left;
    width: 10em;
    margin-right: 1em;
    text-align: right;
}

Now refresh your browser and you’ll see that the field elements and labels are nicely aligned with the text labels right-justified.

Fields Aligned

Fields Aligned

You can adjust the width to accommodate your field labels or if you leave things as they are the field labels will wrap. But be careful if you decide to wrap your labels you will need additional styling; see chapter 5 of The Art and Science of CSS for more detail.

You’ll notice the “Create” button is shoved over to the right and has its own border. That looks strange and we don’t want that. This is where the <fieldset> tags surrounding the erb tag come in handy. The following style uses padding-left to properly align the “Create” button. At the same time we’ll make the background-color transparent.


fieldset.submit {
    float: none;
    width: auto;
    padding-left: 12em;
    border: 0 none #FFF;
    background-color: transparent;
}

Note, that if you adjust the width on the label style you will also need to adjust the left padding on your submit fieldset accordingly.

Styling Complete

Styling Complete

By now you’re probably thinking this is a heck of a lot of trouble, and you would be right, it is! However, with changes you’ve made to scaffold.css will be applied to all of your forms where you adjust the markup as above.

Ideally, it would be great to have a scaffold generator plugin that automatically creates accessible markup… but I’ll leave that for a future post.

Advertisements

6 comments so far

  1. Damon Clinkscales on

    I know you’ve got Rails on the brain, but the book is The Art and Science of CSS. 🙂

    keep on writin’….

    ciao

  2. Navjeet on

    For some reason all the code snippets are not displayed properly in IE7, they are fine in Firefox.

  3. Chris on

    Damon – thanks. I do have Rails on the brain!
    Navjeet – thanks for pointing that out. I’ve had many challenges formating the code snippets so I’m not surprised with this latest challenge.

  4. Chris on

    IE7 formatting problems now fixed. It was a problem with the &lt;span> padding on the Textmate generated stylesheet.

  5. Ahsan on

    But does your xhtml validate ?

    The text_field helpers generate an html id of the format: modelname[attribute], and the ‘[‘ character is not permitted within label’s “for” attribute.

    That’s the problem I faced. Though I haven’t tried your code, it sure looks like it wouldn’t validate either.

  6. Chris on

    It validates but with a warning: reference to non-existent ID “name”. It doesn’t fail though.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: