Accessible tabs UI with jQuery Tools

by Mike Badgley on September 29, 2010

If you are not familiar with jQuery Tools, I’d suggest you familiarize yourself with them. A helpful clean and small toolkit that acts as a plugin to the popular jQuery library. jQuery Tools allows you to integrate a number of UI tools quickly and easily into any Web project – such as:

  • Tabs
  • Tooltips
  • Scrollable (gallery/content)
  • Overlay

I’ve been using their toolkit for almost a couple of years now and have yet to find anything better. Anyhow, enough with the pleasantries – let me get on with the main topic of this article: Building accessible tabs with jQuery Tools.

Now this article is not meant as a shot against jQuery Tool (I understand that they want to make the HTML and CSS to generate their various UI tools to be as quick and easy as possible, which is something that they definitely accomplish ) but rather as a helpful addition that you should include when using the Tabs UI.

The sample HTML that jQuery Tools provides for generating a tabbed interface is much like the following:

<!-- the tabs -->
<ul class="tabs">
	<li><a href="#">Tab 1</a></li>
	<li><a href="#">Tab 2</a></li>
	<li><a href="#">Tab 3</a></li>
</ul>

<!-- tab "panes" -->
<div class="panes">
	<div>pane 1 content</div>
	<div>pane 2 content</div>
	<div>pane 3 content</div>
</div>

Enabling the proper JavaScript method and applying some basic styling can give you a layout that is similar to the example below. It is very clear that the content being viewed (Tab pane 1) belongs to the tab labelled “First tab”.

Screen_jQueryTools_TabsUI
Source: jQuery Tools

However, if the device being used to browse the page does not have JavaScript support, or, if the content is being printed, the clarity we see above is quickly lost.

Using the same HTML snippet above, you can see how each content ‘pane’ is completely independent from the unordered lists of tabs, and unless each content pane contains a heading that signifies what it is (which is doubtful since the tab displays that information), there is no way of knowing which section the content belongs to – a real accessibility problem for people using assistive devices.

Fortunately, fixing this issue can be done rather easily in a couple of steps:

Step 1: Covert the tabs into anchor links

We’ve all done this before a million times – simply assign a unique ID value to each of the content panes and then update the href attribute for each tab so that they acts as anchor links, like so:

<!-- the tabs -->
<ul class="tabs">
	<li><a href="#pane1">Tab 1</a></li>
	<li><a href="#pane2">Tab 2</a></li>
	<li><a href="#pane3">Tab 3</a></li>
</ul>

<!-- tab "panes" -->
<div class="panes">
	<div id="pane1">pane 1 content</div>
	<div id="pane2">pane 2 content</div>
	<div id="pane3">pane 3 content</div>
</div>

Now, instead of just being dummy links, they are accessible anchors that point to their respective content pane.

A good start, but we can do even better by assigning headings to each content pane.

Step 2: Dynamic tabs based on each content pane’s heading

Adding anchor links like we did in the first step does the job, but it can still be better and more accessible. In this step I propose doing away with the tabbed unordered list altogether (from the HTML mark-up) and instead build it dynamical with JavaScript based on the first heading (<h1> … <h6>) in each content pane. Again, using our original HTML snippet, it would be modified as so:

<!-- tab "panes" -->
<div class="panes">
	<div>
		<h2>Heading for pane 1</h2>
		pane 1 content
	</div>
	<div>
		<h2>Heading for pane 2</h2>
		pane 2 content
	</div>
	<div>
		<h2>Heading for pane 3</h2>
		pane 3 content
	</div>
</div>

Now we have a proper document structure that will make the most sense to users with assistive devices – I feel it’s the most accessible method for displaying this type of content. However, since the ‘tabs’ have been removed (in favor of headings), it means that there will need to be some custom scripting done so that the Tabs UI will work properly like before.

Again, very simple – basically all that the script needs to do is to gather up the first heading it encounters for each content pane. With that resulting object we enumerate through it and create a ‘tab’ for each item, like the following example:

var tabs = $('<ul class="tabs" />'); 

$('div.panes > div').each(function() {
	$(tabs).append('<li><a href="#">' + $('h2:first', this).text() + '</a></li>');
});

$('div.panes').before($(tabs).html()); 

There you have it – a quick and easy solution to some of the accessibility issues that come with the ‘default installation’ of the Tabs UI of jQuery Tools.

A closer look at the max-width property

by Mike Badgley on July 27, 2010

I came across an interesting issue today with the max-width property. It’s a property that I’ve only used in a few occasions in the past – mainly due to the constraints of legacy browsers that do not support it.

That being said, it’s extremely useful and this week I’ve found an interesting peculiarity with it that I have not come across before. Searching for this issue proved to be fruitless – mainly due to the fact that it’s a bit of a tricky one to word properly!

The issue I was finding in all browsers that support min-width (with the exception of IE7) was how it handled the width when a text label exceeded the allotted max-width value and thus was forced to wrap onto a subsequent line(s).

For example, I had a series of 7 navigational items. No item in the list was to exceed 104 pixels in width. This worked, as expected, but where I saw the ‘funniness’ were on the navigational elements that required word-wrapping (since they were to wide to fit on a single line). In these cases, the max-width value of the item was still being applied as 104 pixels even though the item was now technically less than that in width. This created really ugly gaps between the items, as you can see from the screen-shot below:

Whitespace gaps in the navigation caused by the max-width property

In order to get some context on the issue I was having, I’ve provided the HTML and CSS I used:

<ul id="primary" class="clearfix">
	<li><a href="about_e.html">About us</a></li>
	<li><a href="products_e.html">Investment products</a></li>
	<li><a href="prices_e.html">Prices and performance</a></li>
	<li><a href="management_e.html">Investment management</a></li>
	<li><a href="informed_e.html">Stay informed</a></li>
	<li><a href="helpful_e.html">Helpful information</a></li>
	<li><a class="lit" href="investor_e.html">Investor learning</a></li>
</ul>
#primary {
	font-size: 14px;
	line-height: 1;
	list-style-type: none;
	margin: 0;
	position: relative;
	word-wrap: normal;
	z-index: 100;
}

	/**
	* @subsection Custom-styled for "Home" Page
	*/
	#primary li {
		display: inline-block;
		font-family: Arial, Helvetica, sans-serif;
		margin: 0 0 0 20px;
		max-width: 7.43em; /* 104 pixels */
		padding: 10px 0;
		vertical-align: middle;
		*display: inline;
		*zoom: 1;
	}
		#primary a {
			display: inline;
			text-decoration: none;
			text-transform: uppercase;
		}

		#primary :hover a,
		#primary .sfhover a,
		#primary a.lit,
		#primary a:hover { color: #eaac1f !important; }

Note: This was taken from the existing project so a few extraneous styling rules may have been missed (that were elsewhere in the CSS document), but for the most part this is what I had.

I thought this was a bug until I cracked open a copy of the W3C specification and found the following:

  1. The tentative used width is calculated (without ‘min-width’ and ‘max-width’) following the rules under “Calculating widths and margins” above.
  2. If the tentative used width is greater than ‘max-width’, the rules above are applied again, but this time using the computed value of ‘max-width’ as the computed value for ‘width’.
  3. If the resulting width is smaller than ‘min-width’, the rules above are applied again, but this time using the value of ‘min-width’ as the computed value for ‘width’.

Item number two from the list above is where my problems were stemming from. For all intents and purposes, the max-width properly was working the way it was supposed to (which means that IE7′s version of the property is incorrect, even if it meant that it worked the way I was hoping it would).

In terms of finding a solution with CSS it would appear I was out of luck. Short of rewriting the specification for the property and having it ok’d and implemented cross-browser before this project I was working on was due, well, that wasn’t going to happen! :)

The solution to my problem was to use a bit of JavaScript that ran through each item in the navigation and then assigned a width to the item (the one that has been assigned the max-width property) that was equal to the width of the hyperlink contained therein. Since this width value of the hyperlink could not possibly exceed the max-width value, I knew that the highest the value could go was 104 pixels and the lowest would be however wide the now reformatted (word-wrapped) hyperlink was:

<script type="text/javascript">
	$('#primary > li').each(function() {
		$(this).width($('a', this).width());
	});
</script>

This rendered the navigation in the way I wanted – each item that was previously set to the max-width value was now re-sized to be the actual width of it’s child element, as shown in the screen-shot below:

Whitespace gaps in the navigation removed by JavaScript function

Notes

  • The hyperlink had to be styled as an inline-level element; otherwise if was styled as a block-level element the width of it would always be equal to the width of it’s parent.

CSS3 Lessons: Multiple Background Images

by Mike Badgley on July 16, 2010

The CSS3 background property has been completed enhanced from it’s CSS 2.1 predecessor, with some really interesting new features that I plan on investigating in future articles. For the purposes of this article, I’ll be looking at the multiple image ability of the background-image property.

The following lesson is based on the W3C Working Draft (June 12, 2010) of CSS Backgrounds and Borders Module Level 3.

The CSS2 Problem: Single Background Images

Rounded corner feature boxAs shown on the right, this is just a simple static content feature for the client’s Facebook and Twitter accounts. The layout and decoration of the feature, however, is a bit more complicated. Add to the fact that this element should have a fluid width and height, and you are looking at a very ‘heavy’ piece in terms of the HTML, CSS and imagery that are required to achieve this.

Using this example, it is clear that there will be five background images needed, as well as five HTML elements on which we can layer the images onto:

  • Rounded corner, top left
  • Rounded corner, top right
  • Rounded corner bottom left
  • Rounded corner with shadow and gradient, bottom right
  • Small icon of globe and speech bubbles

We can be creative and combine these images into a single sprite, but alas the same cannot be said for the HTML – we require the same number of elements as we have background images:

<div class="feature">
	<div class="tr">
		<div class="br">
			<div class="bl">

				<h2>Join the Conversation</h2>

				<p>
				Lorem ipsum dolor sit amet, consectetur
				adipiscing elit. Nunc mollis nunc suscipit arcu
				viverra vitae posuere eros dictum.
				</p>

				<p>
				<a href="#" target="_blank"><img alt="Facebook" height="17" width="79" src="/labs/CSS3/lessons/_images/logo_Facebook_79w_17h.png" /></a>
				<a href="#" target="_blank"><img alt="Twitter" height="22" width="93" src="/labs/CSS3/lessons/_images/logo_Twitter_93w_22h.png" /></a>
				</p>

			</div>
		</div>
	</div>
</div>

The alternative is to force the element to be a static width and thus cut down on the amount of HTML required. This method allows you to define just a single background image (plus an extra one for the green icon) which is tall enough to allow the element to grow vertically without any display issues occurring.

In the case of the project I was working this element into, I went with the static width approach as I wanted to keep the markup as clean as possible. The problem with this approach, however, is when the feature needs to be shown within multiple columns of differing widths. I avoided HTML’s ‘tag soup’ only to jump into a nice bowl of CSS ‘soup’!

Of course, neither solution mentioned above is desirable, but our hands are tied with the constraints of the CSS 2.1 specification, so either we dumb down the design or  go HTML/CSS ‘crazy’.

The CSS3 Solution: Multiple Background Images

Note: Before I get into the CSS3 solution to this problem, I want to clarify that I understand using the border-radius property could achieve close to the effect shown above, but for the purposes of this tutorial I am looking for a purely background image based solution.

Creating the required background images

Generating the required (5) images was the first step, and so much like what has been done in the ‘old day’s, a image was sliced for each rounded corner (4) and then one for the green ‘globe’ icon. Since their is a subtle gradient (running bottom to top) in the design, the way I sliced this up was like so (the guides are there to show the dimensions of each image):

Screenshot of the background image boundaries for the feature

Note: The ‘globe’ icon was sliced out separately as an PNG-24.

The resulting images that were created, based on the diagram above, are as follows:

  • Top left (30×30)
    Top left corner of the rounded feature
  • Top right (251×30)
    Top right corner of the rounded feature
  • Bottom left (30×142)
    Top left corner of the rounded feature
  • Bottom right (251×142)
    Bottom right corner of the rounded feature

The HTML markup

With the enhancements to the background properly that CSS3 provides, the markup required to create a rounded-corner feature like this is greatly reduced from what was previously required in the HTML source example provided above. Since CSS3 allows for multiple background images, it means that we are no longer need to define an HTML element for each background image that the design requires. In other words, all the background images we need can be defined on a single element.

<div class="feature">

	<h2>Join the Conversation</h2>

	<p>
	Lorem ipsum dolor sit amet, consectetur
	adipiscing elit. Nunc mollis nunc suscipit arcu
	viverra vitae posuere eros dictum.
	</p>

	<p>
	<a href="#" target="_blank"><img alt="Facebook" height="17" width="79" src="/labs/CSS3/lessons/_images/logo_Facebook_79w_17h.png" /></a>
	<a href="#" target="_blank"><img alt="Twitter" height="22" width="93" src="/labs/CSS3/lessons/_images/logo_Twitter_93w_22h.png" /></a>
	</p>

</div>

So much cleaner – and easier for an author to integrate into their content.

Styling the HTML markup with CSS3

The styling for the feature is very similar to the way this type of feature was done in the past. First, we need to define the general layout of the element before applying the background images (generated in the steps above) to it.

View the first step in the process here. Remember to view source to get the HTML and CSS

Next, using the multiple background image enhancement that CSS3 delivers, we simply map each of our images to the <div class=”feature”> element – positioning each in it’s proper location.

To do this, simply define each of the background images and separate them with a comma, like so:

div.feature {
	background-image: url(_images/layout_feature_top_left_30w_30h.gif),
		url(_images/layout_feature_top_right_251w_30h.gif),
		url(_images/layout_feature_bottom_left_30w_142h.gif),
		url(_images/layout_feature_bottom_right_251w_142h.gif),
		url(_images/icon_globe_51w_49h.png);
}

The order in which the background images are declared is important as the first is the top-most layer while the last one is at the bottom. In other words, you could think of the first background-image (layout_feature_top_left_30w_30h.gif) having a greater z-index than the last one (icon_globe_51w_49h.png)

View the second version of the feature here.

You’ll note that the only image visible is the first one – which is due to the fact that it is being repeated horizontally and vertically. Since none of the images should be repeated, we can simply issue a background-repeat property of no-repeat and this will apply to all the defined background images. There is no need to define a background-repeat: no-repeat 5 times, as is explained here in more detail (first two paragraphs).

The third version of the feature visible shows multiple images being applied to the feature box- that is if your browser supports this property!

The final step is to position each of these images to the appropriate location (x, y). Again, we can either define one position for all, or individually define each image’s position, which in this case is what we need to do, in a similar format to the background-image property we defined above:

div.feature {
	background-position: 0 0, 100% 0, 0 100%, 100% 100%, 100% 0;
}

How cool is that eh? One <div> element handling all five background images! This box can be as wide as we want, and can house as much content as we want – it is completely fluid.

Just one small problem – where did that green logo go? If you viewed the first five examples, there was no sign of it, but if you viewed the last example you could partially see it. Why is this? Remember the images are stacked from top (first image defined) to bottom (last image defined). In this example, the logo was defined last, so in order to make it visible we can just define it first and bump the other four images down one level, like so:

div.feature {
	background-image: url(_images/icon_globe_51w_49h.png),
		url(_images/layout_feature_top_left_30w_30h.gif),
		url(_images/layout_feature_top_right_251w_30h.gif),
		url(_images/layout_feature_bottom_left_30w_142h.gif),
		url(_images/layout_feature_bottom_right_251w_142h.gif);

	background-position: 95% 7%, 0 0, 100% 0, 0 100%, 100% 100%;
}

Also, since the order of the images is shifted, that means the background-position property will need to be updated as well to reflect this change.

And there you have it, the completed rounded corner feature box that utilizes five background images within a single <div> element. View the final example here.

Is your video content getting indexed?

by Mike Badgley on July 9, 2010

Read an interesting article the other day called Video SEO: A technical guide (by Joost de Valk) which goes into a in-depth explanation of video SEO. It is something that I had not really thought about previously – had really just been concentrating on getting individual pages to be indexed by leading search engines like Bing or Google. However, if your site makes use of video content, it is really in your best interest to ensure that it is indexed (viewable).

In Joost’s article, he mentions four methods of getting your video content indexed. The method I ended up choosing was an XML video sitemap. I originally tried the RDFa method, but the WordPress blog platform I’m on kept stripping out all the meta data that was inserted into the <object> tag of the embedded video. This actually was the method I preferred, but I couldn’t find a way to get it to work with the WordPress editor.

To test this out, I used an annoucement video that my employer (High Road Communications) released back in January of this year.

I created an XML file, based on the documentation found on Google’s webmasters site and than submitted it as a sitemap within Webmaster Tools. The XML file that I created looked like the following:

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
	<url>
	  <loc>http://www.lifeathighroad.com/web-development/can-google-see-your-video/</loc>
	  <video:video>
	    <video:title>High Road Announcement Video</video:title>
	    <video:publication_date>
	      2010-01-19
	    </video:publication_date>
	    <video:content_loc>



	    </video:content_loc>
	    <video:thumbnail_loc>

http://i1.ytimg.com/vi/lVT2Q1g02X0/default.jpg

	    </video:thumbnail_loc>
	    <video:description>
		By pushing past the boundaries of conventional public relations with new ideas and original thinking well connect you with the media and influencers that matter. Its all about your brand. Map your companys future with High Road and go forward.
	    </video:description>
	    <video:tag>High Road Communications</video:tag>
	    <video:tag>iStudio</video:tag>
	    <video:tag>annoucement</video:tag>
	    <video:duration>68</video:duration>
	  </video:video>
	</url>
</urlset>

You can get a description of all the various tags by viewing the documentation here on the webmaster’s site referenced above.

Update: RDFa now working

I was able to find a way of getting that RDFa method to work using a nifty plugin called EmbedIt. I’ve updated the <object> tag of my video so that it now has the required RDFa markup, as documented on SearchMonkey:

<object
	classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
	width="640"
	height="385"
	codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"
	rel="media:video"
	resource="http://www.youtube.com/v/lVT2Q1g02X0"
	xmlns:media="http://search.yahoo.com/searchmonkey/media/"
	xmlns:dc="http://purl.org/dc/terms/">

		<param name="allowFullScreen" value="true" />
		<param name="allowscriptaccess" value="always" />
		<param name="src" value="http://www.youtube.com/v/lVT2Q1g02X0&amp;hl=en_US&amp;fs=1?rel=0&amp;hd=1" />
		<param name="allowfullscreen" value="true" />
		<embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube.com/v/lVT2Q1g02X0&amp;hl=en_US&amp;fs=1?rel=0&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed>

		<a rel="media:thumbnail" href="http://i1.ytimg.com/vi/lVT2Q1g02X0/default.jpg" />

		<span property="dc:date" content="2010-01-19" />
		<span property="dc:description" content="By pushing past the boundaries of conventional public relations with new ideas and original thinking well connect you with the media and influencers that matter. Its all about your brand. Map your companys future with High Road and go forward." />

		<span property="media:title" content="High Road Announcement Video" />
		<span property="media:duration" content="68" />
		<span property="media:width" content="640" />
		<span property="media:height" content="385" />

</object>

I’m really curious to see the effect implementing these two methods will have in terms of visibility of the video. Will keep you posted!

A manageable method for creating CSS image sprites

by Mike Badgley on July 8, 2010

The technique for creating and using CSS image sprites has been around for quite some time now. However, they don’t seem to be used near enough, despite the performance bonuses they can deliver. Perhaps it is due to the fact that front end developers feel that they take to much time to create or are to hard to manage. Whatever the case may be, the truth is that they are simple to make and not as annoying to mange as one would think.

In this post I’d like to go over the steps that I use when creating CSS image sprites for any front end development work that I am involved in.

There are a number of online tools out there that can help you with creating these, but when it comes down to it, the simplest method is using the tool you already have – Adobe Photoshop. I find it a bit humorous that there are all these ‘helper’ applications out there that try to aid you in creating image sprites – going as far as allowing you to create image slices around the regions you want to designate a particular style for. Last time I checked, Photoshop has a slightly better interface than some random Web application . just sayin’!

So enough with the trash talking and onto the methods that I use when creating image sprites for my front end development work on client Web/Intranet sites. I’ll be using the current High Road Communications design for this example.

  1. Identify elements from the design that will be included within the sprite. I normally only create sprite for images that elements that are going to be styled with a defined height and width value. Yes, it’s possible to do this for ‘fluid’ elements, but I find it can be a headache and not worth the time and/or performance benefits.

    Screenshot of the home page of High Road Communications

  2. Within Photoshop (I use CS2), I create a new PSD file with decent enough dimensions to fit all the images that will be included in the sprite.

    Create a new PSD in Photoshop

  3. From the original design I select each element that I have identified from step 1 and paste them into the newly-created sprite PSD. For each image that is inserted, I create an image slice for it (if you’re using Photoshop CS4 or higher there is no image slicing tool, so use Fireworks CS4+ instead).

    Adding an image to the sprite PSD 

  4. On the same layer that the image was pasted onto, I draw a thick border around it with the brush tool; using a really ugly color that will stand out. The reason I do this is for one, it is a good visual clue for where an individual sprite is in the PSD – having them all jammed together can get really chaotic in a short time. Secondly, when styling an element with CSS, it will be pretty easy to see when I have wrong background-position values used, as the thick border will show up in the page layout.

    Outline each image in the sprite

  5. When this process is complete, the sprite is saved out in an appropriate web format. I normally use PNG-8 as it has the best file compression, for the most part. In addition, I also save the sprite as a PSD so it can be easily managed if new images are added or old ones removed/updated.
  6. The last step is the CSS, of course! I style up all my elements as if they were referencing an individual image, and not a sprite, although I ensure that the background-image points to the sprite that was saved in the step prior. When that is complete, all that remains is to update the x and y coordinates for the background-position properly of each element that is referencing the sprite, as well as the actual width and height values. This is where the image slices that were created for each element in the sprite (step 3) comes into play. When viewing the properties for a particular slice it will give you all the information you need – x and y position, and the width and height values. Plug those into your CSS and you are complete!

    Slice details for a particular image in the sprite 

So there you have it, the process of creating an image sprite is not only easy, but fairly manageable as well. As long as you keep your image slices updated when making any changes to the sprite, determining the height, width, x and y values will not be a problem at all.