Using multiple classes within selectors

Date: 5 November 2007
Author: Russ Weakley

Some basic definitions to start…

Before we get into using multiple classes, here are a few basic definitions.

HTML Elements

HTML Elements are the basic components that are used to create the structure of an HTML document. HTML elements generally consist of three parts: a start tag, content and an end tag. For example:

<p>
	This is a paragraph.
</p>

HTML Attributes

HTML Attributes are used to assign additional properties to HTML elements. For example:

<p class="intro">
	This is a paragraph.
</p>

CSS Selectors

CSS Selectors are a component of CSS rule sets. They are used to "select" the elements on an HTML page that is to be styled. For example:

.intro
{
	color: red;
}

Multiple classes within one attribute

It is possible to add more than one class to an HTML element. For example, you can add two classes to an <li> element like this:

<li class="page-1 current-page"><a href="#">Home</a></li>

The two classes are written within the same attribute, with spaces separating each class.

The advantage of multiple classes is that you can write a CSS rule to select either of the classes – and they both affect the same element. For example:

.page-1
{
	color: white;
}
.current-page
{
	background: red;
}

You can also use multiple classes in the same selector. To do this, all classes must be written directly after each another – with no white space. For example:

.page-1.current-page
{
	background: purple;
}

Why would you use multiple class selectors?

There may be times when you want to write a CSS rule that is more specific or has more weight than a previously written rule. If no other ids or classes are available further up the document tree you may have to resort to using classes that have been assigned to the same element. Creating a multiple class selector may make the selector more specific or give it additional weight. This means it will overwrite less specific selectors.

Support for multiple class selectors?

Most browsers, excluding Win/IE5 and Win/IE6 support multiple class selectors.

Browser support chart
Mac: Safari 4.0 supported
Mac: Chrome 5.0 supported
Mac: FireFox 3.6 supported
Mac: Opera 10 supported
Win: FireFox 3.6 supported
Win: Opera 10 supported
Win: IE6 NOT SUPPORTED
Win: IE7 supported
Win: IE8 supported

Multiple selectors in action

Here is a simple tabbed menu:

Sample 1

The HTML for this menu could be something like this:

<ul class="topnav">
	<li class="page-1 current-page"><a href="#">Home</a></li>
	<li class="page-2"><a href="#">About us</a></li>
	<li class="page-3"><a href="#">Services</a></li>
	<li class="page-4"><a href="#">Portfolio</a></li>
	<li class="page-5"><a href="#">Contact</a></li>
</ul>

This HTML has been generated by a Content Management System and cannot be changed. We have to find ways of using the available classes to style the list. To achieve the design shown above, we may need to use multiple class selectors.

Let’s take a look at how selectors can be used to target aspects of the list.

Selecting the <a> elements

You could use a selector for all <a> elements, such as:

.topnav li a { }

That would select all these elements:

Sample 2

Selecting the first <a> element

To add a curve to the top left corner of the list, you will need to select the first <a> element. This can be achieved using a selector like this:

.topnav li.page-1 a { }

This would select the first <a> element only:

Sample 3

Selecting the last <a> element

To add a curve to the top right corner of the list, you will need to select the last <a> element, using a selector like this:

.topnav li.page-5 a { }

This would select the last <a> element only:

Sample 4

Highlighting the current page

To change the tab colours to show that the pages are “current” we can use the “current-page” class in a selector like this:

.topnav li.current-page a { }

This will select each tab when the “current-page” class is written by the CMS, like this:

Sample 5

Styling the current page top left and right corners

Now we have a problem. The first and last tabs (“Home” and “Contact”) have square top corners when the “current-page” class is used. Ideally, their “current-page” look should be red, but with a curved corner. To do this, we have to write selectors that are specific to these elements. As we only have classes within the same element to use, we can finally use multiple class selectors such as:

.topnav .page-1.current-page a { }
.topnav .page-5.current-page a { }

We can then use these two specific selectors to add curved red background images into the elements.

The results will then look like this:

Sample 6

Issues

It seems too easy, doesn’t it? The problem, as mentioned above, is that Internet Explorer 5 and 6 do not support multiple class selectors. Instead of reading the two classes, Internet Explorer 5 and 6 will read the last class only. So, instead of seeing this:

.topnav .page-1.current-page a { }
.topnav .page-5.current-page a { }

Internet Explorer 5 and 6 interpret these selectors as:

.topnav .current-page a { }
.topnav .current-page a { }

This means that these browsers could add curved tops to EVERY element classed with “current-page” – like this:

Sample 7

This issue is not a problem for Internet Explorer 7, which supports multiple class selectors.

There are ways to work around the Internet Explorer 5 and 6 issue. One method is explained in the tutorial below.

A step-by-step tutorial

Here is a “step-by-step” tutorial showing how the menu was styled, and how to work around Internet Explorer 5 and 6.

The HTML markup

<ul class="topnav">
	<li class="page-1 current-page"><a href="#">Home</a></li>
	<li class="page-2"><a href="#">About us</a></li>
	<li class="page-3"><a href="#">Services</a></li>
	<li class="page-4"><a href="#">Portfolio</a></li>
	<li class="page-5"><a href="#">Contact</a></li>
</ul>

The unstyled list looks like this:

Sample 8

Time to start styling!

Step 1 – styling the <ul> element

The first step is to remove all default margins and padding from the <ul> element. This can be achieved using:

ul.topnav
{
	margin: 0;
	padding: 0;
}

The list now looks like this. The bullets are still present, but they sit off the left side of the screen now that the left margins have been removed:

Sample 9

Step 2 – styling the <li> element

The next step is to get the <li> elements to sit in a line rather than as new lines. We also need to remove the default bullets. This can be achieved using:

.topnav li
{
	list-style-type: none;
	display: inline;
}

The list items are now sitting beside each other:

Sample 10

Step 3 – Styling the <a> element

Now to style the <a> elements – this is where most of the action takes place. First, we need to float the <a> elements so they sit beside each other. We also need to set them to “display: block” so we can given them some dimention. (Inline elements cannot be given width or height, and padding really only affects the sides of the element.)

Then we add some padding and a background image. The image is a tall narrow one, so we can set it to repeat along the x (or horizontal) axis. A background colour is also included in case people have images turned off. The color also matches the bottom of the background image tint – so the tab will always scale well, no matter how large the text is.

To add a single pixel line between each tab, we can set a margin on the right using the shorthand margin property – “margin: 0 1px 0 0;“.

Finally, we can centre the text, set it to white and take off the default underline using “text-decoration: none;”.

.topnav li a
{
	float: left;
	display: block;
	padding: 3px 10px;
	background: #016fac url(bg-topnav.jpg) repeat-x;
	margin: 0 1px 0 0;
	text-align: center;
	text-decoration: none;
	color: #fff;
}

The background image I have used looks like this:

The background is now working across all <a> elements:

Sample 11

Step 4 – Styling the :hover pseudo-class

Next, we can add a simple hover colour to the <a> element using:

.topnav li a:hover
{
	color: yellow;
}

Now the basic styling is done. As you can see, the only problem is that the top left and right corners are still square.

Step 5 – styling the top left curved corner

To create the top left corner we need to select the first list item (which has a class of “page-1″) and apply a new background image. This time it is set to “no-repeat”. The rule set is:

.topnav li.page-1 a
{
	background: #016fac url(bg-topnav-left.jpg) no-repeat;
}

The background image looks like this:

The top left corner is now a curve:

Sample 12

Step 6 – styling the top right curved corner

We can do the same for the top right corner, except we need to make sure the image always sits in the top right corner of the element. This is achieved by setting the background position to “100% 0″.

.topnav li.page-5 a
{
	background: #016fac url(bg-topnav-right.jpg) no-repeat 100% 0;
}

The background image looks like this:

The top right corner is now a curve:

Sample 13

Step 7 – setting the current page color

Now, to style the current page, we can change the background image and color from blue to red.

.topnav li.current-page a
{
	background: #aa0201 url(bg-topnav2.jpg) repeat-x;
}

The background image looks like this:

The current page will now have a red tab:

Sample 14

Step 8 – applying a current page color to the top left corner

This is where the job gets more interesting. Current pages are given a new class that is written into the same attribute as the identifying class. So, we have an attribute that looks like this:

<li class="page-1 current-page"><a href="#">Home</a></li>

To style the item with a class of “page-1″ but only when it has a second class of “current-page” we need to use a multiple class selector – with both classes written after the type selector – and no spaces between them:

.topnav li.page-1.current-page a
{
	background: #aa0201 url(bg-topnav-left2.jpg) no-repeat;
}

The background image looks like this:

The top left corner has a round corner when current:

Sample 13

The only problem with this elegant solution is that it is not supported in IE5 or IE6, so we will need to create a work-around. But first, we need to finish off by setting the top right corner.

Step 9 – applying a current page color to the top right corner

The same type of selector can be applied to the top right corner:

.topnav li.page-5.current-page a
{
	background: #aa0201 url(bg-topnav-right2.jpg) no-repeat 100% 0;
}

The background image looks like this:

The top right corner now has a round corner when current:

Sample 14

Step 10 – a work-around for IE5 and IE6

Internet Explorer 5 and 6 do not read multiple class selectors correctly. They will apply only the last class that was written. So, a selector like this – “li.page-5.current-page” will be interpreted as this – “li.current-page“.

This presents us with a problem as this means EVERY current page tab will be given a curved edge, as you can see in this example:

Sample 7

If this is a problem, it may be better to let IE render all the current page tabs without corners. This can be achieved by giving IE5 and IE6 a specific rule – one that no other browsers see.

How is this achieved? The simplest way is to place a new rule in a separate style sheet that is linked to via a conditional comment.

Conditional comments allow us to show CSS rules to specific versions of Internet Explorer. In this case we will use a conditional comment to show a new CSS file to all version of Internet Explorer except IE7. This is achieved using “if lt IE 7“, which means “if less than IE7″.

<!--[if lt IE 7]>
	<link rel="stylesheet" href="ie.css" type="text/css" media="screen" />
<![endif]-->

Inside this new style sheet, a new rule can be written that will place a non-curved background image into every tab.

.topnav li.current-page a { background: #aa0201 url(bg-topnav2.jpg) repeat-x; }

Sample 5

Not ideal, but one solution that can be used without having to write specific ids for the various <li> elements.

A final word – using CSS3

Of course, we will soon be able to target elements much more easily using CSS3 selectors. For example, if we wanted to target the first and last elements in a list we could simply use these selectors:

li:first-of-type a { }
li:last-of-type a { }

Comments so far

  1. Matt Robin says:

    Which CMS are you using Russ?

  2. [...] Shigeru-Nakagaki.com wrote an interesting post today onHere’s a quick excerptThe other day I had to style a menu that looked like this:. While styling the menu, I came across an interesting problem. The Content management system was writing two classes into the same element, and there were times when I needed to … [...]

  3. Russ says:

    @Matt Robin: the CMS was WordPress, and the PHP could have been rewritten if needed. However, I wanted to see if it was possible using existing markup as an exercise. I was also curious to see if IE7 supported multiple class selectors. :)

  4. Nate Klaiber says:

    This is definitely supported (from what I have seen). There isn’t a special declaration you are using, you are just using the cascade to style elements differently.

    And, WordPress is far from a CMS. It is a blogging tool shoehorned into a CMS :) he.

  5. Sean Landry says:

    Multiple classes are definitely supported. FireFox and IE 6.0+ support it. As a matter of fact it can give you great control.

    http://www.w3.org/TR/css3-selectors/

  6. Multiple classes are an amazing way to create reusable css classes.

    Especially if you are using class selectors with Javascript to hide/show elements. You can just add the class along with other classes you are using.

    I use it alot when creating menus. I have a class for the current page state, and a class I use for the last item on the menu. And sometimes I have to use those classes in conjunction with other classes, and I’ve never ran into any problems with IE.

    So, I say enjoy the realization and joy of more control!!!!

  7. tetrix says:

    Nice tutorial, thanks.

  8. David says:

    I’m just grateful about this website. In the night I had lots of requirements but I was getting nowhere until I landed on this website. Thanks a lot.

  9. Aelthwin says:

    Thanks for posting! I somehow missed learning about this selector before now.

  10. Gray says:

    This just saved me a big headache – thanks