kelvinluck.com

a stroke of luck

Progressive enhancement with jQuery example


Update: shAIR is now called Sharify so I’ve updated the links below to point to the new website.

As I previously wrote, we just launched a new product called shAIRSharify. The website was a great chance to implement some progressive enhancement using my favourite javascript library, jQuery. So I thought I’d take the chance here to explain some of the things I did and how they continue to work without javascript enabled. None of this is rocket science by any stretch of the imagination but I thought is was worthy of a quick description.

Since much of the functionality discussed below is behind a login in the admin panel I put together a little example sandbox page which demonstrates the points below.

Styled submit buttons

The beautiful site design from hoppermagic called for submit buttons which don’t really look like buttons at all. Styling a normal submit button is fairly limited and hard to do cross browser so instead I decided to use javascript to swap out the submit button for a normal link which has an event listener which submits the form. If js is disabled the user gets a normal, accessible submit button. If js is available then we know that we will be able to use javascript to submit the form.

The code in question looks like this:

$(':submit').each(
   function()
   {
      var $this = $(this);
      var f = this.form;
      var link = $('<a href="#">' + $this.val() + '</a>')
         .bind(
            'click',
            function()
            {
               $(f).trigger('submit');
               return false;
            }
         )
      $this.after(link).css({position:'absolute', top:'-2000px'});
   }
)

Note that rather than hiding the real submit button with visibility:hidden or display:none we instead just move it way off the screen. This means that you can still submit the form by pressing return in one of the form fields (IE doesn’t allow this if there is no visible submit field in the form).

Form validation

Using the validation plugin made it very quick and easy to add clientside validation to my forms. This doesn’t replace serverside validation but it means that you can inform your users of their errors and give them meaningful feedback quickly. One thing that I would love to see added to the validation plugin is some sort of hooks for when the error message is shown and hidden. I wanted my errors to animate nicely into and out of existence. I managed to hack in a slideDown on the appear by abusing the errorPlacement callback but I wasn’t able to animate the disappearance of the element.

The code related to the validation plugin looks like this:

$forms = $('.validated-form');
if ($forms.length) {
 
   $forms.validate(
      {
         errorPlacement: function(error, element)
            {
               element.after(error);
               error.hide().slideDown();
            }
      }
   );  
}

Note that I only try and call the validate method where I find forms with a class of validated-form. This is because I use the same javascript throughout my site but I only include the validate plugin (and add the validated-form class to forms) on pages where it is required. I would get errors complaining that the validate method couldn’t be found if I didn’t have the check.

Tooltips

Another easy one thanks to the jquery.simpletip plugin. None of the examples on that page seem to use the tooltip in a particularly gracefully degrading way though. In my case I decided to use the title element of the items I was creating a tooltip for to hold the text of the tooltip. This means that without javascript enabled people will still see (less pretty) tooltips. The code is very simple, it grabs the value of the title and passes it into the simpletip initialiser. We also need to remember to empty the title attribute so that the browser doesn’t display it’s tooltip as well as ours.

$('.tt').each(
   function()
   {
      var $tt = $(this);
      $tt.simpletip(
         $tt.attr('title'),
         {
            hook: {
               tooltip: 'topLeft',
               target: 'bottomLeft'
            },
            offset: [20, -5],
            stem: {
               corner: 'topLeft',
               color: '#000',
               size: 15
            }
         }
      ).attr('title', '');
   }
);

FAQs accordian

For the FAQs page I wanted to make it easy for people to scan the questions and then click on the one they wanted the answer for. And jquery made it really easy to add a bit of animation to this too. As an added extra I also add a CSS class to the relevant question heading which changes the direction of the arrow besides it. The answers are hidden by javascript on document ready so users without javascript will just see a normal list of questions followed by answers.

var $h2;
var $answer;
$('.answer').hide();
$('#faq h2').bind(
   'click',
   function()
   {
      if ($h2 && $h2[0] != this) {
         $answer.slideUp();
         $h2.removeClass('open');
      }
      $h2 = $(this);
      $answer = $h2.next();
      $answer.slideDown();
      $h2.addClass('open');
   }
)

Message for IE6 users

I spent a little bit of time making sure that the site was at least usable in IE6. But I didn’t want to waste too much time making sure everything looked perfect. So I decided to add a little message to the top of every page which encourages IE6 users to upgrade their browser. This way they are at least aware why things don’t look quite right and they can’t complain. Luckily, IE6 is a (slowly) dying beast and will be used by a very small proportion of the site’s target audience (developers who are using Adobe AIR).

Summary

So that’s a quick description of some of the simple steps we took to make the website as beautiful and easy to use as possible for people on modern browsers while making sure it is still accessible and available to people using older browsers or who have javascript disabled (for whatever reason).

With the tools and information web developers have at their disposal these days it is so easy to build a site in this manner that there really is no excuse for sites which are completely broken with javascript disabled. Hopefully these simple examples illustrate the some of the concepts behind progressive enhancement.