A List Apart

Menu

If I Told you you had a Beautiful Figure…

Issue № 246

If I Told You You Had a Beautiful Figure…

by Published in JavaScript, Layout & Grids · 25 Comments

Let’s face it, images are a pain in the ass. Okay, well, maybe the images themselves aren’t the problem, but laying out images consistently within a design is difficult; especially when you hand the keys over to someone else to fill in the content.

Article Continues Below

Sure, you can write a mountain of documentation that clearly informs your clients of the image widths your carefully constructed grid layout will accept without breaking, but even if you are emphatic about the client adhering to the guidelines in the documentation, there’s always the possibility that a mistake will be made. One innocent mishap—something as simple as the dyslexic transposition of 238px to 283px—and your layout’s toast.

Of course, you can also enforce image sizing via a CMS (with the appropriate image libraries installed), but what if we aren’t working with a CMS or the images are indexed-color and pixelate horribly when resized?

DOM scripting to the rescue!

When tackling this very problem, it occurred to me that a little clever JavaScript could go a long way toward resolving any image layout inconsistencies within our web pages.

Note: To distinguish between content-related images and design-related images, I will be referring to the former as “figures” from here on out. I will only use the term “image” to refer to the actual file referenced by an img element.

A sporty figure

Before I could jump into scripting, I needed a solid pattern for marking up figures; one that would be flexible enough to work in pretty much any situation. Building off of some of the work being done on a potential microformat for figures, here’s what I came up with:

<div class="figure">
	<img src="fa.jpg" alt="" />
	<p class="credit"><abbr class="type" title="Photograph">Photo</abbr>by <cite>Aaron Gustafson</cite></p>
	<p class="caption"><em class="title">Figure 1</em></p>
	<p>The “Faces of the Fallen” exhibit at Arlington National Cemetery.</p>
</div>

This simple markup provides support for the image itself as well as several optional data points:

  • a title,
  • a type (photograph, illustration, etc.),
  • a caption, and
  • a credit or byline.

Those data points cover about 90% of figures used on the web and make this markup pattern flexible enough to allow as few (or as many) data points as you like:

<div class="figure">
     <img src="faces-of-the-fallen.jpg" 
          alt="The Faces of the
               Fallen exhibit at Arlington
               National Cemetery." />
</div>

You could, of course, take this simple markup several steps farther and embed licensing information, an hcard, geo-positioning data, etc. but my own preference is to keep that information on a page referenced by the image’s longdesc attribute rather than in the figure itself.

An attractive figure

With the markup in place, it was time to think about default styles. After all, I needed to be able to lay out the figures whether JavaScript was available or not. For most purposes, the following works nicely:

.figure {
  margin: 0 0 1.5em;
}
.figure p {
  margin: 0;
}
.figure .credit {
  font-size: .8em;
  text-align: right;
}
.figure .credit cite {
  font-style: inherit;
}
.figure .caption {
  font-style: italic;
  font-size: 1.1em;
}
.figure .title {
  font-style: normal;
  font-weight: bold;
}
.figure .title:after {
  content: ":";
}

When applied to the figure markup, it looks something like Figure 1 (obviously inheriting the body styles, etc.).

A screenshot of the example figure and its caption information with the default styles applied.

You’ve probably noticed that I have not created any styles to float the figures left or right. I don’t think presentational information belongs in the markup (at least not by default). And that is my main bone of contention with many of the “existing practices” figure examples on the microformat page.

In the interest of consistent design, it only makes sense to lay out figures based on image size.  For example, figures that take up more than 50% of a column’s width simply should not be floated, as text wrapping around such a figure looks awful. For similar reasons, you don’t want a figure that takes up roughly half of the column width floating to the left of the text.

As designers, we know these things, but we shouldn’t expect content folks to know them (or even care). In fact, it is often in your best interest to avoid giving non-designers options when it comes to laying out a figure—that is the job of the designer. There’s no reason to burden non-designers with figuring out how much of a column their figure occupies either. If you do, one of three things is likely to happen:

  1. She follows your instructions and makes the right choice.
  2. She applies the wrong class.
  3. She ignores image classification altogether.

Only one in three of those options has a pleasant outcome for your design. I’m not much of a gambler, so I really don’t like those odds. Thankfully, the task of calculating image widths relative to the column they call home is a mundane task for JavaScript. And by pushing that task to a script, FigureHandler, we can free content folks from having to deal with the image sizing stuff and enforce consistency.

A supple figure

FigureHandler makes it dead simple to manage figure layout across your site. It comes with a set of sensible default classes for you to work with, but it also allows for pretty granular customization.

                                                                                                                                                                             
Table 1: FigureHandler’s Default classes
Percent of the Columnclass Applied
Percent of the Columnclass Applied
0-25quarter-col
25-34third-col
34-50half-col
50-67two-thirds-col
67-75three-quarters-col
75-100full-col

If you want to run with the default settings, you can simply include FigureHandler.js (and Prototype, the library upon which FigureHandler is built) and create a new FigureHandler, like this:

if( typeof( Prototype ) != 'undefined' &&
    typeof( FigureHandler ) != 'undefined' ){
  Event.observe( window, 'load', function(){
    new FigureHandler; } );
}

FigureHandler will then

  1. parse the page looking for div elements classified as “figure,”
  2. compare the width of the image within that figure to the overall column width (assumed to be the figure’s parentNode), and
  3. apply a class to the figure that corresponds to the percentage of the column width the image takes up.

As an added bonus, FigureHandler will also adjust the widths of any paragraphs within the figure to match the width of the image, so you never have to worry about the text and the image not aligning properly.

A screenshot of the example figure and its caption information after FigureHandler has run.

Then it’s up to you to create custom styles for each classification of figure, as I’ve done in this example.

If you’re interested in more granular control, FigureHandler can accommodate you as well. You can direct the script to only work within an identified element by supplying that id as an argument:

if( typeof( Prototype ) != 'undefined' &&
    typeof( FigureHandler ) != 'undefined' ){
  Event.observe( window, 'load', function(){
    new FigureHandler( 'main' ); } );
}

You can even apply your own custom classes by supplying a JSON object to FigureHandler as a second argument (seen in this example):

if( typeof( Prototype ) != 'undefined' &&
    typeof( FigureHandler ) != 'undefined' ){
  Event.observe( window, 'load', function(){
    new FigureHandler( 'main', { '0-27':   'small',
                                 '27-100': 'large' } );
    new FigureHandler( 'extras', { '0-50':   'potato',
                                   '50-100': 'tomato' } );
  });
}

Go figure

FigureHandler opens up many possibilities for designers, while simultaneously reducing the headache of laying out figures and enforcing consistent design. It is also a progressive enhancement and is built on top of what could eventually become an official microformat. In short, FigureHandler has a lot going for it. Try it out for yourself and rest easy that images won’t be running roughshod over your designs ever again.

25 Reader Comments

Load Comments