Most web standards-based developers are more than familiar with creating their sites with semantic HTML with lots and lots of CSS. With each new page in a design, the CSS tends to grow and grow and more elements and styles are added. But CSS can be used to better effect.
The idea of object-oriented CSS isn’t new. Nicole Sullivan has written a presentation on the subject and outlines two main concepts: separate structure and visual design; and separate container and content. Jeff Croft talks about Applying OOP Concepts to CSS
I can make a class of .box that defines some basic layout structure, and another class of .rounded that provides rounded corners, and classes of .wide and .narrow that define some widths, and then easily create boxes of varying widths and styles by assigning multiple classes to an element, without having to duplicate code in my CSS.
This concept helps reduce CSS file size, allows for great flexibility, rapid building of similar content areas and means greater consistency throughout the entire design. You can also take this concept one step further and apply it to site behaviour with JavaScript.
Build a versatile slideshow
I will show you how to build multiple slideshows using jQuery, allowing varying levels of functionality which you may find on one site design. The code will be flexible enough to allow you to add previous/next links, image pagination and the ability to change the animation type. More importantly, it will allow you to apply any combination of these features.
Image galleries are simply a list of images, so the obvious choice of marking the content up is to use a <ul>. Many designs, however, do not cater to non-JavaScript versions of the website, and thus don’t take in to account large multiple images. You could also simply hide all the other images in the list, apart from the first image. This method can waste bandwidth because the other images might be downloaded when they are never going to be seen.
Taking this second concept — only showing one image — the only code you need to start your slideshow is an <img> tag. The other images can be loaded dynamically via either a per-page JavaScript array or via AJAX.
The slideshow concept is built upon the very versatile Cycle jQuery Plugin and is structured in to another reusable jQuery plugin. Below is the HTML and JavaScript snippet needed to run every different type of slideshow I have mentioned above.
<img src="path/to/image.jpg" alt="About the image" title="" height="250" width="400" class="slideshow">
<script type="text/javascript">
jQuery().ready(function($) {
$('img.slideshow').slideShow({
images: ['1.jpg', '2.jpg', '3.jpg']
});
});
</script>
Slideshow plugin
If you’re not familiar with jQuery or how to write and author your own plugin there are plenty of articles to help you out.
jQuery has a chainable interface and this is something your plugin must implement. This is easy to achieve, so your plugin simply returns the collection it is using:
return this.each(
function () {}
};
Local Variables
To keep the JavaScript clean and avoid any conflicts, you must set up any variables which are local to the plugin and should be used on each collection item. Defining all your variables at the top under one statement makes adding more and finding which variables are used easier. For other tips, conventions and improvements check out JSLint, the “JavaScript Code Quality Tool”.
var $$, $div, $images, $arrows, $pager,
id, selector, path, o, options,
height, width,
list = [], li = 0,
parts = [], pi = 0,
arrows = ['Previous', 'Next'];
Cache jQuery Objects
It is good practice to cache any calls made to jQuery. This reduces wasted DOM calls, can improve the speed of your JavaScript code and makes code more reusable.
The following code snippet caches the current selected DOM element as a jQuery object using the variable name $$. Secondly, the plugin makes its settings available to the Metadata plugin‡ which is best practice within jQuery plugins.
For each slideshow the plugin generates a <div> with a class of slideshow and a unique id. This is used to wrap the slideshow images, pagination and controls.
The base path which is used for all the images in the slideshow is calculated based on the existing image which appears on the page. For example, if the path to the image on the page was /img/flowers/1.jpg the plugin would use the path /img/flowers/ to load the other images.
$$ = $(this);
o = $.metadata ? $.extend({}, settings, $$.metadata()) : settings;
id = 'slideshow-' + (i++ + 1);
$div = $('<div />').addClass('slideshow').attr('id', id);
selector = '#' + id + ' ';
path = $$.attr('src').replace(/[0-9]\.jpg/g, '');
options = {};
height = $$.height();
width = $$.width();
Note: the plugin uses conventions such as folder structure and numeric filenames. These conventions help with the reusable aspect of plugins and best practices.
Build the Images
The cycle plugin uses a list of images to create the slideshow. Because we chose to start with one image we must now build the list programmatically. This is a case of looping through the images which were added via the plugin options, building the appropriate HTML and appending the resulting <ul> to the DOM.
$.each(o.images, function () {
list[li++] = '<li>';
list[li++] = '<img src="' + path + this + '" height="' + height + '" width="' + width + '">';
list[li++] = '</li>';
});
$images = $('<ul />').addClass('cycle-images');
$images.append(list.join('')).appendTo($div);
Although jQuery provides the append method it is much faster to create one really long string and append it to the DOM at the end.
Update the Options
Here are some of the options we’re making available by simply adding classes to the <img>. You can change the slideshow effect from the default fade to the sliding effect. By adding the class of stopped the slideshow will not auto-play and must be controlled via pagination or previous and next links.
// different effect
if ($$.is('.slide')) {
options.fx = 'scrollHorz';
}
// don't move by default
if ($$.is('.stopped')) {
options.timeout = 0;
}
If you are using the same set of images throughout a website you may wish to start on a different image on each page or section. This can be easily achieved by simply adding the appropriate starting class to the <img>.
// based on the class name on the image
if ($$.is('[class*=start-]')) {
options.startingSlide = parseInt($$.attr('class').replace(/.*start-([0-9]+).*/g, "$1"), 10) - 1;
}
For example:
<img src="/img/slideshow/3.jpg" alt="About the image" title="" height="250" width="400" class="slideshow start-3">
By default, and without JavaScript, the third image in this slideshow is shown. When the JavaScript is applied to the page the slideshow must know to start from the correct place, this is why the start class is required.
You could capture the default image name and parse it to get the position, but only the default image needs to be numeric to work with this plugin (and could easily be changed in future). Therefore, this extra specifically defined option means the plugin is more tolerant.
Previous/Next Links
A common feature of slideshows is previous and next links enabling the user to manually progress the images. The Cycle plugin supports this functionality, but you must generate the markup yourself. Most people add these directly in the HTML but normally only support their behaviour when JavaScript is enabled. This goes against progressive enhancement. To keep with the best practice progress enhancement method the previous/next links should be generated with JavaScript.
The follow snippet checks whether the slideshow requires the previous/next links, via the arrows class. It restricts the Cycle plugin to the specific slideshow using the selector we created at the top of the plugin. This means multiple slideshows can run on one page without conflicting each other.
The code creates a <ul> using the arrows array we defined at the top of the plugin. It also adds a class to the slideshow container, meaning you can style different combinations of options in your CSS.
// create the arrows
if ($$.is('.arrows') && list.length > 1) {
options.next = selector + '.next';
options.prev = selector + '.previous';
$arrows = $('<ul />').addClass('cycle-arrows');
$.each(arrows, function (i, val) {
parts[pi++] = '<li class="' + val.toLowerCase() + '">';
parts[pi++] = '<a href="#' + val.toLowerCase() + '">';
parts[pi++] = '<span>' + val + '</span>';
parts[pi++] = '</a>';
parts[pi++] = '</li>';
});
$arrows.append(parts.join('')).appendTo($div);
$div.addClass('has-cycle-arrows');
}
The arrow array could be placed inside the plugin settings to allow for localisation.
Pagination
The Cycle plugin creates its own HTML for the pagination of the slideshow. All our plugin needs to do is create the list and selector to use. This snippet creates the pagination container and appends it to our specific slideshow container. It sets the Cycle plugin pager option, restricting it to the specific slideshow using the selector we created at the top of the plugin. Like the previous/next links, a class is added to the slideshow container allowing you to style the slideshow itself differently.
// create the clickable pagination
if ($$.is('.pagination') && list.length > 1) {
options.pager = selector + '.cycle-pagination';
$pager = $('<ul />').addClass('cycle-pagination');
$pager.appendTo($div);
$div.addClass('has-cycle-pagination');
}
Note: the Cycle plugin creates a <ul> with anchors listed directly inside without the surrounding <li>. Unfortunately this is invalid markup but the code still works.
Demos
Well, that describes all the ins-and-outs of the plugin, but demos make it easier to understand! Viewing the source on the demo page shows some of the combinations you can create with a simple <img>, a few classes and some thought-out JavaScript.
Decide on defaults
The slideshow plugin uses the exact same settings as the Cycle plugin, but some are explicitly set within the slideshow plugin when using the classes you have set.
When deciding on what functionality is going to be controlled via this class method, be careful to choose your defaults wisely. If all slideshows should auto-play, don’t make this an option — make the option to stop the auto-play. Similarly, if every slideshow should have previous/next functionality make this the default and expose the ability to remove them with a class such as “no-pagination”.
In the examples presented on this article I have used a class on each <img>. You can easily change this to anything you want and simply apply the plugin based on the jQuery selector required.
Grab your images
If you are using AJAX to load in your images, you can speed up development by deciding on and keeping to a folder structure and naming convention. There are two methods: basing the image path based on the current URL; or based on the src of the image. The first allows a different slideshow on each page, but in many instances a site will have a couple of sets of images and therefore the second method is probably preferred.
Metadata ‡
A method which allows you to directly modify settings in certain plugins, which also uses the classes from your HTML already exists. This is a jQuery plugin called Metadata. This method allows for finer control over the plugin settings themselves. Some people, however, may dislike the syntax and prefer using normal classes, like above which when sprinkled with a bit more JavaScript allows you to control what you need to control.
The takeaway
Hopefully you have understood not only what goes in to a basic jQuery plugin but also learnt a new and powerful idea which you can apply to other areas of your website.
The idea can also be applied to other common interfaces such as lightboxes or mapping services such as Google Maps — for example creating markers based on a list of places, each with different pin icons based the anchor class.


Comments
Comments are ordered by helpfulness, as indicated by you. Help us pick out the gems and discourage asshattery by voting on notable comments.
Got something to add? You can leave a comment below.
06/12/2009
Thank you for this tutorial Trevor.
I really like the final effect. It’s also nice that you included all those different previews.
Also, thanks for the links about jquery. I’ve been wanting to learn how to code from scratch and the link that you gave will definitely be of help.
I wish 24 ways was year-round.
Vote Helpful or Unhelpful
06/12/2009
Kind of disappointed. The title led me to believe I was going to read an article on front-end code reusability with CSS and JavaScript. Turned out to be an article on how to build a jQuery slide show. Should be re-titled to more accurately reflect the majority of the article. :(
Vote Helpful or Unhelpful
06/12/2009
Awesome read, Trevor. I use a lot of similar techniques when building sites, but the jQuery caching was new to me. Thanks for all the great tips!
Vote Helpful or Unhelpful
06/12/2009
Some nice work but the only problem I can see is that without js, the visitor can only ever access the first image. It seems to me that you’d better putting the pagination links in the HTML which lead to real images and disabling the link when js is on, so that if js is off, at least the images can be viewed.
Vote Helpful or Unhelpful
06/12/2009
I know this was a very small portion of the article, but I just want to say object-oriented CSS is a terrible name for what should be described simply as CSS that follows the DRY principle.
Regarding OOP, Wikipedia describes it in this way:
Now, last time I checked, CSS is not passing “objects” anywhere. It is applying styles to HTML elements based upon rules. Just want to throw that out there. Again, I know it was not the point of your article, so please pardon my little tangent.
Vote Helpful or Unhelpful
06/12/2009
Recently, I’ve found myself migrating toward this “object” based syntax with my CSS classes. The farther I go down this path, the more I start to wonder if I’m actually moving away from semantics by describing the style (with classes like “wide” or “rounded”) in the markup. This applies to most of the popular grid systems out there also.
I’m not saying these tools (or concepts) shouldn’t be used. I’m just wondering how far my conscience will let me go before I begin having nightmares of Zeldman strangling me with inline styles…
Vote Helpful or Unhelpful
06/12/2009
Hum… (i++ + 1) or (++i) ?
By the way, there is means to make OO CSS, without removing the semantic of the elements… take a look : http://lesscss.org/
Vote Helpful or Unhelpful
06/12/2009
@Benoît – In production I’d use
++i(it’s simpler and faster), but for an examplei++ + 1is less subtle and therefore easier to understand.Vote Helpful or Unhelpful
06/12/2009
@Design Informer; I’m glad you liked the article. jQuery is a great JavaScript framework to learn and has an awesome community, you shouldn’t have much trouble finding a tutorial or plugin to help you achieve what you need. I would always recommend learning some tutorials first, so you can spot good plugins and fix any problems you may have with them.
@Crazy Henaway; I’m sorry you’re disappointed with the article. Although the majority of the article is about applying the concept to a jQuery plugin, I was hoping you would take away the concept – adding a few classes and writing your JavaScript/CSS to be more reusable.
@Ray Brown; thank you, I really appreciate that. Caching of jQuery objects is a really useful way to speed up your application, especially when you have a lot of elements and potentially slow queries.
Vote Helpful or Unhelpful
06/12/2009
@John Faulds; This is a good point, however, there are a few issues I see with this behaviour. The technique you mention is similar to that found when using the “lightbox” popup. If the user doesn’t have JavaScript, then the full image is shown – on it’s own, top left in the browser, usually surrounded by white-space. I don’t think this is a very good way of fallback content (albeit an easy one) but it does mean the full-sized image is available to the user. Another method is linking to a page within the site which just displays the full-sized or next slide image or within the current context, simply swapping out the old image with the new. This method would be preferable, but this rarely happens due to numerous reasons, but mainly due to budget and potential conflict in duplicate content. If the slideshow is simply icing on the cake (so to speak), then losing this functionality isn’t a great problem. If the content IS the slideshow, then I agree you should definitely have separate URLs and you could then hijax it in to a better user-experience.
Vote Helpful or Unhelpful
06/12/2009
@Chris Wallace; you make a good point. DRY principle is probably a better way to describe what is happening. However, I was simply expanding on what others, such as Nicole Sullivan & Jeff Croft, have been talking about. They talk about the object-oriented CSS concept and I think it is known within the industry now (although this doesn’t detract from the misuse).
@Ben Callahan I feel your reluctance on this issue – I really do! Since working in the industry I’ve learnt that you need to make certain compromises. The compromise of adding a few non-semantic classnames to your beautifully semantic HTML (!important;) is not only a very minor misdemeanour, but also helps build code-reusability, gain consistency throughout your website/application & can dramatically improve development time.
Vote Helpful or Unhelpful
06/12/2009
I am a fan of using css frameworks for rapid prototyping which make use of reusable classes similar to how you describe in this article. There is however a divide between designers, some saying the classes bloat markup and are un-semantic. I am happy to use these in personal projects where I can apply semantics through applying ID’s, but for a large-scale production website these reusable classes just won’t do.
It is interesting that you are applying these classes through jQuery which may get around the problem when javascript is enabled, but what happens when it is disabled? How unobtrusive is this javascript?
I think for most, writing well formed, semantic HTML and CSS will be the order for the day when it comes to the day-to-day markup. This is a great tutorial but will be kept to the personal website where a playground for code is acceptable.
Vote Helpful or Unhelpful
06/12/2009
Everyone is free to use whatever method they like, but ultimately what you are proposing here is using presentational class names.
Is class=“rounded” any different to class=“red”?
I accept that truly separating content and presentation isn’t always practical or achievable. I can see the productivity benefits. It just doesn’t seem right to me personally, and it’s not the sort of idea I expect to see promoted on an otherwise progressive site like this.
Humf. As you were.
Vote Helpful or Unhelpful
06/12/2009
@Kevin Rapley; I don’t understand your logic about large-scale production websites and reusable code. It’s large-scale websites which require reusable code the most. Reusable classes (whether you agree with the multiple OOP/DRY class method described in the article or not) are the only way to build large scale websites. Sure, you have IDs for the main sections and for markers throughout the content, but it’s the classes you will style to maintain cohesion and keep the style across a lot of content – that, and as you mentioned, well-formed semantic HTML.
I think you’ve mis-understood my article. I am not apply these classes through jQuery. These classes are on the IMG itself and are being used by the JavaScript. I also describe what happens when JavaScript is disabled, that is the starting point. I also justify the method I have chosen and state an alternative. The JavaScript is completely unobtrusive and the outcome is a good example of progressive enhancement.
Vote Helpful or Unhelpful
06/12/2009
@Pieman; I am proposing “presentational class names” or even behavioural class names, but it’s all about context and common sense. To your question, yes and no! I wouldn’t recommend using class=“red” but instead ask WHY is this content being styled as red? Is it because it is important, or required in a form. Most cases you should be using the answer to this question to decide on your class and ID names. You are free to take what you will from this article, hopefully it will spark another idea which will work better than this, and if it does I would love for you to share it with us.
Vote Helpful or Unhelpful
06/12/2009
One of the ways of adding data to your markup that can be quite useful is being able to grab database information such as ids from classes. Here is a generic function for doing this (I can’t find a way to get pre blocks working on here, which makes this look messy…):
Markup:
Call the function:
Hope this is useful to someone… sorry textile bc. codeblocks do not work here…
Vote Helpful or Unhelpful
06/12/2009
@trovster admittedly I breezed over the jQuery explanation as I am not familar with writing javascript, sorry about that, my bad.
At this time I have to agree with Pieman, the classes are too presentational for my liking. Although great for rapid prototyping, I would not allow (nor would my colleagues) these classes in the kinds of websites that we build.
I disagree that these classes are required for a large scale build to maintain cohesion. I build websites for financial institutes, public sector agencies and large private sector brands. I never use these types of classes for these builds as I don’t deem them as being semantically written.
The stylesheets are large by not using such classes, but I write stylesheets that are well commented and structured in such a way that everything is easily located and written logically. I find problems never arise and cohesion is maintained.
I would be interested to have a bit of a stylesheet comparison with you at a multipack meetup in the new year if you’re game? I think your method certainly has a place and I am probably not seeing the whole picture at the moment.
Vote Helpful or Unhelpful
07/12/2009
Just a small remark I have, and has been made before by @Pieman and Kevin Rapley- directed mainly at the concept of Object Oriented css. Often I see people recommend to create classes like .rounded, .floatleft or .bold.
While at first sight this may seem like a good idea in terms of reusability there is something fundamentally wrong with this approach. When you do this, you will create html like this: <div class=“rounded floatleft”>. The problem is that this goes against the concept of seperating markup and content.
The idea is to create meaningful html. For example instead of <p class=“bold”> you might want to go for <p class=“emphasis”> so the classname has meaning, but does not imply any markup. Instead of thinking in terms of markup, you should be thinking of the function this markup serves. e.g. .rounded could be .box or .button.
Ofcourse this will make you repeat yourself when you want to round both box and button. A solution to this might be css variables, but this is a completely different story ofcourse.
Another solution I have been thinking about is to have jquery add these “presentational” classes to the desired elements. This would allow me to combine the maintainability (let’s face it, they are very practical) of these classes, while keeping the markup in javascript-and not in html. Problem here might be rendering speed, and ofcourse it still isn’t completely semantic.
Great article though, and as chance would have it, I just needed a jquery slideshow.
Vote Helpful or Unhelpful
07/12/2009
I see people mention maintainability as an upside of using presentational classnames such as “rounded”. But what about the maintainability of the markup? What if I have defined lots of elements with the “rounded” class and then decide I want some of them to have sharp corners instead? I’d have to go into the markup and make changes in multiple files, instead of just editing one stylesheet.
Arguably using id’s and then inserting the corresponding presentational classes with javascript would get me around this, but otherwise I don’t see the real benefit. Am I missing something?
Vote Helpful or Unhelpful
08/12/2009
Good article Trevor – good to see the Midlands getting some talent rep! Having said that, you spelled your page title wrong on the demo site… ;p keep up the good work!
Vote Helpful or Unhelpful
Impress us