Using ‘aria-labelledby’ as a styling hook

A couple of months ago, I was greatly inspired by an article on Smashing Magazine entitled Semantic CSS With Intelligent Selectors by Heydon Pickering. It goes into depth on how aria roles can be used as hooks for button styling among other things.

After using some of Heydon’s techniques, I got thinking about how they could be applied to layouts and suchlike. I harassed him on Twitter for his thoughts styling various elements with landmark roles and then stumbled on the aria-labelledby attribute. It turns out that this makes for a perfectly semantic styling hook.

Normally I would use classes when styling sections of content for example:


<section class="section-latest-products">
  <h2>Latest products</h2>
  <ul>
    ...
  </ul>
</section>

<section class="section-press-news">
  <h2>Press news</h2>
  <ul>
    ...
  </ul>
</section>

Now using ‘aria-labelledby':


<section aria-labelledby="latest-products">
  <h2 id="latest-products">Latest products</h2>
  <ul>
    ...
  </ul>
</section>

<section aria-labelledby="press-news">
  <h2 id="press-news">Press news</h2>
  <ul>
    ...
  </ul>
</section>

And the CSS:


section[aria-labelledby="latest-products"] {
  /* Latest products styling */
}
 
section[aria-labelledby="press-news"] {
  /* Press news styling */
}

Using ‘aria-labelledby’ not only increases accessibility, it gives us a styling hook with the bonus of being able to link to the relevant sections using anchors such as ‘#press-news’.

Having not been fan of techniques such as BEM due to them littering markup with unsemantic class names, this just feels right. I’m sure there are other ways that aria attributes could also be used.

Thanks again to Haydon and his article for opening a can of worms in my head, which lead to this solution.

See the Gist and the Twitter conversation.

A few notes on Responsive Design

I’ve been working on a few responsive design projects recently and an old friend of mine asked what I had leaned on my journey, below is my response (pardon the pun):

Basically, it’s seen as bad practice to target specific devices, instead you should just target the breakpoints that make sense i.e. scale the browser down until something looks wrong, then add a media query to fix it, rinse and repeat. That way you’re future proofing yourself as it will look good at any width, even on that device that hasn’t come out yet.

Ideally you should do ‘mobile first’ design whereby you start with the mobile version (duh!) and work your way up, this ensures that you focus on the content and that you don’t get into a situation where something won’t fit the mobile version. The problem with this approach is that old versions of IE will display the mobile version, as they don’t understand media queries without including something like respond.js.

I have not been following the ‘mobile first’ approach on the projects I’ve been involved in due to the IE factor. I have instead been starting with the full width version (keeping in mind how it will respond for narrow screens) and adding media queries where required to adjust the layout for a given breakpoint:


/* All */
.main .module   { float: left; width: 33.333%; }

/* 600 and down */
@media screen and (max-width:600px) {
  .main .module { float: none; width: auto; }
}

The design process becomes an interesting one, do you show the client a full width mockup, mobile, or both? Or should this be done at the wire-framing stage? I went with showing the client a full width mockup and just keeping in the back my mind how it would respond.

I am keen to try the ‘mobile first’ approach, however I will attempt this first on a personal project so that I can nail the workflow before unleashing it on a client project.

As an aside, the css and media queries for ‘mobile first’ would look something like this:


/* Mobile */
.main .module     { }

/* 600 and up */
@media screen and (min-width:600px) {
  .main .module   { float: left; width: 33.333%; }
}

So there we have it, my notes from the trenches of responsive design.

The Solution to Fluid Inconsistencies and Equal Height Columns

Update: There is a follow up article to this one addressing issues raised in the comments.

An introduction

Being an early adopter of Web Standards back in 2001 and thanks to Jeffrey Zeldman’s Designing with Web Standards released in 2003, I strived for a life without tables and 1 pixel shims and instead one filled with semantic markup and a clean separation of content from presentation. Early on in the transition to Web Standards came frustration, the things we used to do with tables without batting an eyelid became a series of CSS hacks and erroneous markup.

To this day there are two core concepts which still make us standards freaks wince. The first is equal height columns and the second is percentage width consistency across browsers. Chris Coyier of CSS Tricks recently rounded up the current solutions for Fluid Width Equal Height Columns but all have their limitations. We have a new flexible box model in CSS3, however it will be a number of years before we can use this in practice due to the slow uptake of new browsers.

A couple of weeks ago, I decided that enough was enough and that it was time to sit down and come up with a solid answer to the problem. Combining a number of CSS tricks that I have amassed over my years in the industry, I have come up with what I believe to be a solution.

Fluid Inconsistencies

Just today I read a post by Steffan Williams on his frustrations with “Fluid Inconsistencies“, so I will address this first.

As documented by John Resig, the reason for inconsistencies with percentage widths comes down to the fact that different browsers round in different ways. Webkit rounds down to the nearest pixel, IE rounds up and Firefox does a bit of both in order to spread the difference across the containing element.

Surprisingly, Webkit’s rounding causes me the biggest problem. As an example, lets say we have 12 equal width columns butted up together. When the container is at 800 pixel in width, in an ideal world each column would be 66.666 pixels, the problem being that there is no such thing as a fraction of a pixel, so Webkit rounds each column down to 66 pixels. This gives a total width of 792 pixels meaning there is a gap of 8 pixels between the right of the container and the right of the last column.

So what are our options? Absolute positioning could work as we would manually set the left edge of each column, negating the cumulative rounding problem. The obvious problem is that absolute positioning would take the columns out of the flow of the document meaning we couldn’t have anything below them and they wouldn’t force their container to grow. What we need is absolute positioning only on the x axis so that we can position each column a specific distance from the left edge. We can achieve this effect with a bit of css trickery…

Absolute positioning only on the x axis

To simulate absolute positioning on just the x axis, we will combine floats, negative margins and relative positioning. Relative positioning is like absolute positioning in that you can specify a left and top value, however it differs in that the element is positioned relative to where it would have been without relative positioning. If we could just get all the columns to start at the same x position, we could use relative positioning from there to shift the columns into the correct positions.

Given the following markup and bearing in mind that you should normally use semantic class names instead of col1, col2 etc.


<div class="content">
  <div class="col1"><p>I am column 1</p></div>
  <div class="col2"><p>I am column 2</p></div>
  <div class="col3"><p>I am column 3</p></div>
  etc...
</div>

I turns out that with the use of floats and negative margins we can get all the columns positioned at the same starting x position.


.content        { position: relative; overflow: hidden; background: #f5f5f5; }
.content div    { float: left; margin-left: -100%; position: relative; width: 8.333%; }

Note the “overflow: hidden;” on the container, this serves two purposes. The first is to ensure it expands to the height of the tallest float (a simple clearfix), the second is so that IE, who we have established rounds up, doesn’t overlap the right edge of the container. Also note that the column width is set to 8.333% (100% ÷ 12).

At this stage we have all columns stacked on top of each other and positioned at -100%. The reason that they are now all in the same place is that when the first element is shifted to the left by 100% (due to the negative margin), the second element’s x coordinate is now 0, it in turn gets shifted left by 100% and so on.

This leaves us in a great position (pardon the pun) as we can now position the columns anywhere horizontally by just adding 100% to the desired x position.


.content .col1   { left: 100%;     background: #eee; }
.content .col2   { left: 108.333%; background: #ddd; }
.content .col3   { left: 116.666%; background: #ccc; }
.content .col4   { left: 124.999%; background: #bbb; }
etc...

View example 1

The real beauty of this technique is that the column order is independent of the order they appear in the markup. You can swap 1 with 3, 9 with 2 etc. you can even span multiple columns by doubling the width. Below is an example of changing the column order.


.content .col3   { left: 100%;     background: #eee; }
.content .col2   { left: 108.333%; background: #ddd; }
.content .col1   { left: 116.666%; background: #ccc; }
.content .col4   { left: 124.999%; background: #bbb; }
etc...

Notice how all we have done here is change the class names around.

View example 2

So there you have it, we have addressed the “Fluid Inconsistencies” problem and it works in Safari, Chrome, Firefox and right the way back to IE6. The keen eyed among you will have noticed the occasional 1 pixel gap between the columns on scaling the browser window, I will address this in the next section.

Equal Height Columns

This has long been a subject for debate and is a hot topic for the “Just Use Tables!” clan. Something caught my eye when reading Chris Coyier’s Fluid Width Equal Height Columns and that was the “Nicolas Gallagher Method”. He basically uses “:before” and “:after” pseudo selectors to add blank content to the container element which can then be styled, pure genius. The only downside to his technique however, is that you are limited to 3 equal height columns.

Based on Nicolas’s method, I found that it was possible to add “:after” pseudo selectors to the columns themselves to achieve the effect of equal height columns. The benefit of this is that we can tell the styled content to inherit the background properties of it’s parent element. This way you only have to style the column itself and all will be inherited correctly.

So how do we do it I hear you shout! Well it’s almost disappointingly simple, I will show the code and then explain what is going on.


.content            { z-index: 1; }
.content div:after  { content: ""; position: absolute; z-index: -1; background: inherit;
                      left: 0; top: 0; right: -1px; bottom: -9999px; }

As with Nicolas’s method, we setup an “:after” with blank content, position it absolutely and set it’s z-index to -1 so that it appears under the column element who’s z-index is 1. The difference comes with the actual positioning. As our column is positioned relatively, we set it’s left and top to 0 so that the top left corner matches that of the column. We set the the right to -1px to solve the occasional gap between columns as promised. The bottom value is where the magic happens, we set it to -9999px. This makes it drop way below the bottom of the column and as long as the difference in height between the tallest and shortest columns is less than that value, you are fine, a pretty safe bet I would say.

View example 3

And that’s it, equal height columns with flexible widths. We could end here, as everything works in Safari, Chrome, Firefox and IE9. In IE8 and below, the page will degrade gracefully and just not have equal height columns. We can however add IE 6/7/8 support using CSS expressions and I would recommend including the fixes with conditional comments should you need to support these versions.

Fixing Internet Explorer IE6/7/8


/* IE 6/7/8 fixes */
* html .content { height: 1%; /* IE6 hasLayout */ }
.content div    { clear: expression(innerHTML += '<u class="ieafter"></u>', style.clear = 'none', 0); }
.ieafter        { width: expression(parseInt(parentNode.offsetWidth) + 1 + 'px');
                  height: expression(parseInt(parentNode.parentNode.offsetHeight) + 'px');
                  background-color: expression(parentNode.currentStyle.backgroundColor);
                  background-image: expression(parentNode.currentStyle.backgroundImage);
                  background-repeat: expression(parentNode.currentStyle.backgroundRepeat);
                  background-position: expression(parentNode.currentStyle.backgroundPosition); }

View example 4

Things to consider

When using this method, if you need padding on columns, I would suggest adding it to an element within the column as opposed to the column itself as otherwise Webkit has two more opportunities to round down (one for the left padding and one for the right). If you really need to add padding to the columns themselves then you may want to add the following Webkit fix.


/* If we have left and right padding on columns, Safari has 2 more opportunities to round down so compensate here */
@media screen and (-webkit-min-device-pixel-ratio:0) { .content div:after { right: -3px; } } 

Something else to consider is explicitly setting the z-index for each column in order from left to right as the additional width we are giving our “:after” content has the potential to overlay the next column. With the z-indexes it looks like this:


.content .col3  { left: 100%;     background: #eee; z-index: 1; }
.content .col2  { left: 108.333%; background: #ddd; z-index: 2; }
.content .col1  { left: 116.666%; background: #ccc; z-index: 3; }
etc...

View example 5

You will notice in my examples I have used divs. These can be easily substituted for more semantic HTML5 elements such as “section” but I wanted to keep the examples simple without the need for HTML5 shivs etc. My use of ‘col1, col2′ etc. class names are purely for this example, you should use more semantic class names in real development.

I hope you like my new technique, feel free to leave a comment with any questions.

Acknowledgements

Update 08/12/10: As pointed out by Paul O’Brien in the comments, the equal height column technique shown here suffers the same side effect as the One True Layout solution, in that if you have a link to an anchor in a column, that column will scroll when the link is clicked. If you need to link to anchors in your columns, this may not be the best technique and the only other option without adding additional markup is to equalise the column height with javascript. The only benefit of this technique over the One True Layout option is that it fixes gaps between columns. I will continue my search for a solution to the anchor issue.

Proprietary CSS rules – Are we returning to 1995?

Call me a cynic, but posts like this one on the Surfin’ Safari blog worry me a little. Let me explain…

I don’t know if anyone remembers back to the days of Netscape 4 and Explorer 3.5? – It was a time of table based layouts and browser sniffing. Each browser had it’s own “feature” set and this resulted in hacks galore, for example Netscape had “Layers” but Explorer didn’t, Explorer had feature X but Netscape didn’t.

Along came Web Standards and the likes of Jeffrey Zeldman fighting for a standards based approach to web development. Over a decade on, it looks like were finally getting there as even Microsoft slowly start to get things right with IE7.

As cool as the CSS Transform stuff looks, I can’t help but think we’re stepping right back into 1995.

What does everyone else think?

SonicIQ Hiring! – UK, Ruby on Rails Developer Required

We are looking for a Ruby on Rails, XHTML & CSS Developer to join our team at “SonicIQ”:http://soniciq.com. Head over to “43folders job board to view our ad”:http://jobs.43folders.com/job/6a5255713e8351a5eb2efef7805b7629/?d=1.

These are exiting times with projects like “Propel’r”:http://propelr.com in the pipeline, along with the ever-growing opportunities for new and interesting client projects.

If you are a highly motivated developer and can see yourself in a Ruby on Rails position in sunny (sometimes) Bournemouth, UK then “apply at 43folders”:http://jobs.43folders.com/job/6a5255713e8351a5eb2efef7805b7629/?d=1.

CSS and JS directories in Rails

One thing that annoyed me when I first started using Rails at 0.14 was that I was forced to put my .css files in a ‘stylesheets’ directory and my .js files in a ‘javascripts’ directory.

Previous to Rails I would put .css files in a ‘css’ directory and .js files in a ‘js’ directory (call me old fashioned). I use the following code in my application helper to allow me to do this:

module ApplicationHelper
  def javascript_path(source) compute_public_path(source, 'js', 'js') end
  def stylesheet_path(source) compute_public_path(source, 'css', 'css') end
end

Just incase anyone else has the same niggle.

*Update 29-11-08:* for Rails 2.2, see new post.