Usability enhancements with JavaScript

There are some things that are nice to add to a site that you don’t actually want to put in the content. They should be automatically added, so that you can change them systematically across the whole site. Assuming that all the information is in your content, you can use JavaScript to add useful things like highlights for external links and to make quotes clickable.

These aren’t new things to do (and I’ll credit where I can), I’m just trying to collect some robust enhancements together.

Requirements

I had some vague requirements that I wanted to fulfill:

  • Content is golden, the HTML source should not be changed to make these additions.
  • They should not add more information than is available in the source, just be enhancements that show what is there.
  • Fix some aspects of Internet Explorer (IE), such as lack of support for the abbr and q elements.
  • Not add too much file weight.

In practical terms, I had already created a simple DOM scripted versions of some things shown below, but when I used jQuery, it took a fraction of the time and was much more robust (which says as much about my programming skills as it does about jQuery!).

Therefore the examples below use jQuery to speed things up with Silk Icons and CSS to style them. The files (if you want to get straight to the code) are all in use and linked to from the Enhancements test page, or you can download the zip file.

When minimised and used with Apache’s mod_deflate, the JavaScript adds about 14k, including jQuery.

It can be quite annoying to select a link, and not be sure if it goes to another page, another site, a place in the same page, or opens a document or PDF.

My preferred solution was to add an icon after each links that was not a standard link to elsewhere on the current site. I went with foreground images rather than background ones because you might want to add alt text or titles to the image, separately from the link. In this case, I used a null alt for external links because I had reports of it interfered with reading for screen reader users (I link quite a lot), but I did add an alt for the rarer Word and PDF document links.

The script linkHighlight gathers all the links in the content area, and loops through them checking if they match these criteria:

// Match documents
if (url.lastIndexOf(".doc") == (url.length-4)){
...}
// Match PDFs
if (url.lastIndexOf(".pdf") == (url.length-4)){
...}
// Match external links
if( ( url.indexOf("http://")==0) && ( url.indexOf(mydomain)!=0 ) ) {
...}
// Match within page links
if( ( url.indexOf("#")==0)) {
...}

mydomain is declared at the top (I have a nagging suspicion I should make it a non-global variable, perhaps by making it an object?), and should match the start of your domain name. If the href doesn’t match your domain or a relative URL, an icon is added at the end of the link.

The only other function in there is to reduce down long URLs, mostly for people posting comments:

if( ( contents.indexOf("http://")==0 ) && ( contents.length>25 ) ) {
...}

That calls a helper function called shrinkUrl, that takes a URL (text string) and returns it with the middle missing.

All of these then produce the following (JavaScript obviously required for the effect):

CSS for the icons

The icons are simply added inline at the end of the link, which can be a bit untidy if it varies from the font size being used. I wanted the icons to re-size with the text as they are inline, but rather than working out the exact nature of all the font aspects, I guessed at this which seemed to work:

#content img.highlightlink {
	border:0;
	height:0.8em;
	margin:-0.2em 0;
	vertical-align:baseline;
}

IE didn’t quite behave the same way as the others, so this was also required in the IE specific stylesheet (it still needs a bit of work in IE6):

#content img.highlightlink {
	vertical-align: middle;
	margin: 0 0 0 0.2em;
}

Highlighting heading anchors

I tend to give quite a few headings within the content area an ID, so they can be referenced directly (something I noticed Joe Clark takes to another level). To let others notice and use this, I added onhover & onfocus events that adds in a link to each heading that does have an ID.

The main JavaScript/jQuery methods are:

var hId = $(heading).attr("id");	// get the ID.
$(heading).attr("tabindex", "0");	// add a tab index to the headings
// Create an anchor to add (NB: artificially wrapped)
var anchor = "<a href='#" 
  + hId + "' class='hidden'><img src='" 
  + imagefolder 
  + "je_anchor.png' title='within page anchor' class='highlightlink' alt='' /> #" 
  + hId 
  + "</a>";

// Add hover event to heading.
$(heading).append(anchor);
$(heading).hover(function(){
  $("#" + hId + " > a").removeClass("hidden");
},function(){
  $("#" + hId + " > a").addClass("hidden");
});

// Add keyboard events
$(heading).focus(function() { $("#" + hId + " > a").removeClass("hidden"); } );
$(heading).blur(function() { $("#" + hId + " > a").addClass("hidden"); } );

Just hover over or tab to the heading below to see the effect, except that unfortunately this doesn’t work across browsers yet. It works perfectly in Firefox, not at all in Safari, Opera or IE7, and partially in IE6. IE6 and Firefox understand the tabindex="0" to allow keyboard access to the heading, but IE6 doesn’t add the link.

I might try an off-screen technique rather than show & hide to get around this problem.

Transforming quotes

I first saw this done by Simon Willison, which really kicked off the idea of progressive enhancement for me. In this case, using the cite attribute to provide direct access to the quotation source, where possible.

For each blockquote or q element, the script then:

// Create variable for the cite and title attributes.
var source 	= $(quote).attr("cite"); 
var t 		= $(quote).attr("title");

if(source) {
  // add class and onclick.
  $(quote).addClass("linked");
  $(quote).click(goToCite);
	
  // change status bar, if browser allows it.
  $(quote).hover(function(){
    window.status=source;
  },function(){
    window.status='';
  });
	
  // if there isn't a title already, create it from the URL.
  if(!t){
    t= "Go to: " + shrinkUrl(source);
  }	
	
  // Replace the title
  $(quote).attr("title", t);

  // Add a link to blockquotes
  if($(quote).is("blockquote")){
    $(quote).append("<address><a href='"+ source +"'>" + t + "</a></address>");
  }
}

This allows people to access the cite attribute as though it were a link, because now it is, for example:

JavaScript’s greatest potential gift to a Web site is that scripts can make the page more immediately interactive, that is, interactive without having to submit every little thing to the server for a server program to re-render the page and send it back to the client.

CSS for blockquotes

The reason the script adds a class of .linked is to allow this CSS to take effect:

.linked {cursor:pointer;}
.linked address a {
	display:block;
	text-align:right;
}
.linked:hover address a {text-decoration:underline;}

This makes each quote that has an onclick show a cursor type pointer, puts the added link on the right, and (CSS support allowing) will put an underline on the link.

Fixing inline quotes in Internet Explorer

I’m a fan of the q element, it lets you add that meaning to a sentence within the flow of text. The main problem has been that most browsers automatically add quotation marks, but Internet Explorer (IE) doesn’t. Gez Lemon of Juicy Studio fixed this (proof that you can’t say accessibility experts don’t know JavaScript!).

To apply this, I separated it into an IE only script file brought in with a conditional comment. The logic of this script is the same as the Juicy Studio version, but has been jQueryfied:

// collect q elements.
var objQuotes = $("#content q");

$(objQuotes).each(function(i){
   // objQuote is this instance.
   objQuote = objQuotes[i];
	
   if( $(objQuote).parent().is("q") ) {
      // add single-quotes if it's a nested quotes
      $(objQuote).prepend("\u2018");
      $(objQuote).append("\u2019");
    }
    else {
      // add double-quotes
      $(objQuote).prepend("\u201c");
      $(objQuote).append("\u201d");
    }
});

This provides reasonable cross-browser support for inline quotes, for example: To be or not to be. (NB: Safari and Opera don’t change the quote marks for nested quotes, so that aspect is a nicety really.)

Fixing abbr in Internet Explorer

There have been some indications that abbr is likely to be the preferred element for providing expansions, as it encompasses acronyms as well. However, Internet Explorer <=6 does not recognise that element, so you can’t even script for it properly.

However, Sovavsiti came up with a little script to add in a little markup (in IE only) to compensate. I’m not going to re-publish it, there wasn’t much need to change as it wasn’t really possible to jQuerify. It adds a span around the contents of the abbreviation with an appropriate title.

However, since IE7 does support abbr, you don’t want it to add more markup (it adds a double underline). Therefore I tried a Conditional Compilation to test for the version of JavaScript support in Internet Explorer:

/*@cc_on @*/
/*@if (@_jscript_version < 5.7)
	styleAbbr(); //function to call in IE<7
/*@end @*/

There is probably a cleverer way of testing for browser version IE, but since the whole file is brought in by an HTML conditional comment, I felt able to experiment. (NB: I’ve only tested with the multiple-install versions of IE, but they report 5.7 for IE7, 5.6 for IE6, and 5.5 for IE 5.5.)

This simple CSS applies the same styling to IE and other browsers:

abbr, acronym, span.abbr {
	border-bottom:1px dashed #666666;
	cursor:help;
}

To do

Although I’m happy to put this out there now, there is still a bit to do, for example:

  • Make the global variables not global (I probably need to read chapter 3).
  • Test the accessibility & suitability of the heading anchor highlighter. For example, it might be better to leave the anchor image there, and not use the hover/focus events.
  • Make code samples look better (Dean Edward’s site does this nicely).
  • See if there is a way of allowing people to middle click on quotes to open them in tabs.

Any hints gratefully received, the latest version will be maintained at the test page.

8 contributions to “Usability enhancements with JavaScript

  1. Links:
    So does this work with links that have uppercase extensions?, or mistyped urls with a space or hash at the end? Perhaps use url.search(/.pdf/i).

    Also, I notice you’re writing a new function for every type, what happens when you have multiple types with the same icon (images, and music formats for example)? You might want to store an array of extensions to match, with their respective icon paths and alt texts.

    Anchors:
    I find that when tabbing through the page, I get two highlights around heading anchors, on around both the heading and link, another around just the link. Selecting the former does nothing :(, the latter brings that heading to the top of the page (which is nice :)).

    Could you remove the keyboard events from the heading, as people will be able to tab onto the link anyway.

    Quotes:
    To avoid the middle-click problem, couldn’t you remove the click function from the blockquote, as the link works well by itself.
    I know this would remove the clickability of the whole blockquote, the only solution I can think of is putting the link around the whole thing, or finding some way pass the keyboard and mouse events from the blockquote through to the link.

  2. Thanks Tom,

    Links:
    Isn’t .search a method of the location object? I don’ think that would work with an href attribute?

    Not sure on the most effective way of adding an array of objects?

    Anchors:
    I’ve just replaced that with adding an icon after the heading. You couldn’t tab to the hidden link, which is why I went down the onfocus route. Although now I’ve sidestepped the issue, it was interesting how browsers dealt with that.

    Quotes:
    I do like the large hit-area, and you couldn’t wrap a link around the paragraphs and other block level elements. Still, it’s not a clear cut improvement, depending on your browser.

  3. Pingback: Fatih Hayrio?lu

Comments are closed.