If I Told you you had a Beautiful Figure…
Issue № 246

If I Told You You Had a Beautiful Figure…

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#section1

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#section2

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#section3

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 Column class Applied
Percent of the Column class Applied
0-25 quarter-col
25-34 third-col
34-50 half-col
50-67 two-thirds-col
67-75 three-quarters-col
75-100 full-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#section4

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

  1. I generally don’t like the idea of using Javascript to control presentation; but I’m not a purist so much so that I cannot see the benefit of this technique. The only question I have: How do we make this degrade in a manner that does not make the page unusable? Is it preferable to float an oversized image and create some ugly word-wrapping–or to not float a small image and wonder where the text went. I imagine the answer is likely tied to the specific design, but I’m sure many have their opinion on what is preferable.

    I’ve been working with mootools a bit more than Prototype these days, and I’m thinking about doing something similar to work with mootools.

    Great idea; great tool, and a well-written article to bring it all together.

  2. Aaron thank for great article the idea is brilliant! “Let’s face it, images are a pain in the ass.” I fully agree with You laying out images consistently within a design is difficult. It’s interesting to read ideas, and observations from someone else’s point of view”¦makes you think more. Regards

  3. Iny my opinion, that would be a bad practice for several reasons:

    – visitors without javascript would get a messy page
    – a page edited in CMS via a WYSIWYG editor woud be displayed differently that one displayed to the visitor, therefore it would be hard to edit it for style/formating errors

    But aside for that, it’s not all that bad 🙂

  4. The hack is not that you’ve used JavaScript to correct HTML/CSS problems. The hack is that you’ve put the burden on browsers to correct theoretical content problems originating from the server.

    There are so many ways to tackle content management, from big to small. Anyone who wants to sell image formatting training wheels to their clients really ought to implement them server-side–if not with a full-blown CMS, at least with some kind of custom script (e.g. PHP GD). I laud the band-aid practicality of your solution, Mr. Gustafson, but it’s far from best practice.

  5. I think you’re absolutely right that using something like this is not something to file under “best practices,” but we’ve got to realize that not everyone gets to work on projects where best practices can be applied. Client budgets, and even client mandate sometimes prevents the optimal solution from being used–it’s always good to explore options for when those situations arise (and, in at least my own personal experience, they arise fairly often).

  6. In response to Brian and the others above, go to the demo page and disable Javascript. The page is just as usable, it looks fine. It’s just not as elegant in terms of widths and wrapping content.

    Implemented well this solution does degrade and I think it’s a very useful tool for certain situations where clients don’t have a complex CMS solution, but still need the ability to add different figures in different scenarios on their site without worrying about layout.

    I can understand the server side argument, but I am sure there would be cases in reality were this solution might be preferred for one reason or another.

  7. Wow, this is exactly what I’ve been trying to do ever since I started designing (and coding) for my blog. I wrote my own script to handle this problem on my blog, a bit messy, but your code is way much cleaner and flexible.

    However, there is one problem, the script doesn’t seem to check whether the image (figure) fills up how much portions of its parent column if the column resizes.

    Let’s say, the column (div, for example) has a width of 50%, assuming it takes up 200px of the page. The figure in that column is probably 100px, so the script applies ‘half-col’ to it. When I resize the browser window, the column resizes, so the figure is not ‘half-col’ anymore, right?

    I hope you get my idea…

  8. I wholeheartedly agree with Bart and Flippant.
    If you’re running a WYSIWYG CMS, use Prototype to layout the image nicely while the user is adding input, but catch the image dimensions and make the correction when the HTML is posted.
    This can be done:
    1) With a backend image utility in the CMS, which you likely already have if your users can upload images. That’s super-crossbrowser, foolproof, no need for a framework, but won’t display pretty until the user previews/posts. Or,
    2) By reading the image dimensions and adding the correct class in the background with JS, before the content is posted. A framework is not necessary for this, either.

    The visitor shouldn’t have to wait on a framework for basic layout to render. This is a bad habit to start, especially for n00bs.

  9. I laughed when I read the first section about “dyslexic transposition”. This does happen all the time, as I work with designers who provide graphics according to specifications– sometimes. Usually it’s then up to me to re-slice from PSD.

    As much as I like this method, I don’t have a good reason to use it yet. But I can’t wait!

    Thank you.

  10. Have two sets of styles apply a class to the body, one with floats if js is disabled and if it is enabled add a class to the body like hasJS and then set some different styles. This would make it more usable for non-js people.

  11. This looks to be an interesting technique, although I’m not sure it will find its way into a project yet. My initial readthrough has given me some ideas though.

    The problem comes when the content editor also fancies themselves as a designer and wants that huge image to be floated. They just aren’t going to accept that it looks crappy that way.

    Maybe I work with the wrong sort of clients 🙂

  12. The reality of working in the web industry is that often sites are developed quickly and changed frequently, so there scope for designing the perfect CMS is often simply not there.

    I think this is a useful technique, not only for when front end developers are working with an inflexible CMS, but also for prototyping new functionality without bloating the CMS itself.

  13. At the beginning, I spent many times to manage my “float”, in CSS, write scripts on PHP whith GD library. But if I was a noobs, I would have certainly used FigureHandler.

    In other part, when developers say that we have to be afraid about users would disable js, I agree with them like I’m against that mind!

    We have to envisage all client configurations, although we are in the reactive web time, when users build himself his interface on your site. We can say that web pages look alike web applications.

    So, the js can become one of principles in our development or a standard of web!

  14. Maybe I’m mistaken, but where is this work being done? I’m assuming a CMS or some type of admin. area that is CMS-like. I don’t see anything wrong with either case requiring JavaScript to administer a site (but not for regular visitors to use it). I don’t see anything wrong with having the CMS/admin. using Prototype to define the figure like in the example, and then saving the results to a database for all users to see that result. For any good design (that is everything except a liquid design where the designer forgot to include a minimum width) this should work with all cases.

    Now, if you don’t have a CMS or an admin. area and you’re telling clients to manually edit HTML files and upload them to the server… I think you have other concerns going on then how well a layout will look with or without JavaScript. :p

  15. I wholeheartedly agree with comment #8 by Charles Phillips. This problem should definitely be solved server side. It can be done perfectly in the way Charles describes.

    Using JS to fix layout issues goes completely against the principle of discretely separating the three layers (markup, css, JS).

  16. Many of you have brought up that this should be done server-side and, while I agree that it _could_, it would need to be done in the most flexible way possible (which many won’t bother with). You see, what this script allows quite easily is redesign; a designer can change page layout — of an entire site *or* section by section — without ever having to touch the back-end. It also allows for different columns to receive different figure classification schema.

    If this were done on the content-entry side (as some have suggested), the image classifications would be stored in the database (or XML or whatever) along with the rest of the content HTML. That means that if the design were to shift to a wider column (for example), the figures that once occupied a half-column, may no longer continue to do so, making the classifications hard-coded in the HTML incorrect.

    The only way to truly do this flexibly on the back end (as far as I can see) is to leave the classification step to be handled by a function which pre-processes the page output, dynamically assigning the classifications to each figure based on values obtained from the CSS for that page. Essentially, the script would need to go through the same steps as the JavaScript, but it would need to be able to go the extra step of determining applicable CSS rules to obtain the column width. Thankfully, most server-side languages support some means of DOM walking (albeit sometimes in less-than-desirable ways), but, as far as I know, none have a CSS parser, so you’d likely need to write that as well. From a server overhead point-of-view, I imagine that preprocessing would be fairly costly (most DOM-related stuff is), but the output for each page could be cached, reducing it somewhat.

    If you’re interested in doing something like this, goodonya. I’ve built you a pretty decent roadmap for implementation, but I don’t imagine it will be easy to get it up and running. That said, I wish you luck…it would be yet another great tool for enabling designers to create consistent layouts with figures.

  17. bq. 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).

    I agree with this statement. With figures, however, there is one piece of markup I add that is presentational. I do so because I think the benefits are great, and no flexibility is lost when it comes to a redesign.

    As with any design involving images one must consider the direction the figure is “facing”? — it may lead the eye to the right or to the left, or neither.

    Figures that “face”? left or do not matter receive no extra markup. The smaller (relative to the column) ones that don’t matter I float right because they sit better in the text (for left-to-right languages). Smaller left-facing figures float right because they bring the reader’s eye back into the page.

    Right facing figures receive an extra class: @alt@. This class can then be used position the figure so that it points into the page. For example:

    * .figure.half-col, .figure.third-col { float: right; }
    * .figure.half-col.alt, .figure.third-col.alt { float: left; }

    Were the markup going to be translated between left-to-right and right-to-left languages both left and right-facing figures would need their own distinct class, while neutral figures would be left alone.

  18. My approach to this (assuming you have server side scripting) would be to use a php statement like –

    < ?php $image_filename = '../assets/images/$imageUrl'; if (file_exists($image_filename)) { list($w, $h) = getimagesize("$image_filename"); print '‘;
    print “$enterDescription”;
    } else {
    print ‘

    Sorry, no image available

    ‘;
    }

    ?>

    That would test for the name and file size. You could include this as a class file so that your web author would only have to write –

    < ? // /// DEAR EDITOR - Please enter these fiese fields /// $imageUrl = enter File Name; $desciption = enter Description; $title = enter image title; $alt = eneter you alt description here; // ///// THANKYOU ///// // include "imageTestClass.php"; /* just include the name of the file with the php above */ ?>

    Then your web author only has to edit enterFileName (p.s. I wrote that code off the top of my head, so there may be bugs, but the basic idea is there). Then, depending on $w and $h values you can give various elements a class to resize them. I might test this properly and write an article.

  19. @Ben Spaulding: Interesting design point regarding left-facing versus right-facing images, which seem thoroughly reasonable. Moreover, where you said “_With figures, however, there is one piece of markup I add that is presentational_”? I would argue that your markup is not presentational at all. You are adding data about the nature of the image, and the class attribute is the most appropriate place for such metadata.

    However, your chosen class name “˜alt’ doesn’t make this metadata clear; I would call the class “˜right-facing’ instead, unless the neutrality of the class name proves critical in simplifying the handling of both left-to-right and right-to-left scripts.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA