Friday, 26 April 2013

A navigation animation (for your users delectation)

The Vexation

The current application I'm working on lives within an iframe. A side effect of that is that my users no longer get the visual feedback that they're used to as they navigate around the site. By "visual feedback" what I mean are the little visual tics that are displayed in the browser when you're in the process of navigating from one screen to the next. Basically, these:

When an application is nested in an iframe it seems that these visual tics aren't propogated up to the top frame of the browser as the user navigates around. Clicking on links results in a short lag whilst nothing appears to be happening and then, BANG!, a new page is rendered. This is not a great user experience. There's nothing to indicate that the link has been clicked on and the browser is doing something. Well, not in Internet Explorer at least - Chrome (my browser of choice) appears to do just that. But that's really by the by, the people using my app will be using the corporate browser, IE; so I need to think about them.

Now I'm fully aware that this is more in the region of nice-to-have rather than absolute necessity. That said, my experience is that when users think an application isn't responding fast enough their action point is usually "click it again, and maybe once more for luck". To prevent this from happening, I wanted to give the users back some kind of steer when they were in the process of navigation, iframe or no iframe.

The Agreeable Resolution

To that end, I've come up with something that I feel does the job, and does it well. I've taken a CSS animation courtesy of the good folk at CSS Load and embedded it in the layout of my application. This animation is hidden from view until the user navigates to another page. At that point, the CSS animation appears in the header of the screen and remains in place until the new screen is rendered. This is what it looks like:

How's that work then guv?

You're no doubt dazzled by the glory of it all. How was it accomplished? Well, it was actually a great deal easier than you might think. First of all we have the html:

Apart from the outer div tag (#navigationAnimation) all of this is the HTML taken from CSS Load. If you wanted to use a different navigation animation you could easily replace the inner HTML with something else instead. Next up is the CSS, again courtesy of CSS Load (and it's this that turns this simple HTML into sumptuous animated goodness):

And finally we have the JavaScript which is responsible for showing animation when the user starts navigating:

It's helped along with a little jQuery here but this could easily be accomplished with vanilla JS if you fancied. The approach works by hooking into the beforeunload event that fires when "the window, the document and its resources are about to be unloaded". There's a little bit more to the functionality in the JavaScript abover which I go into in the PPS below. Essentially that covers backwards compatibility with earlier versions of IE.

I've coded this up in a manner that lends itself to re-use. I can imagine that you might also want to make use of the navigation animation if, for example, you had an expensive AJAX operation on a page and you didn't want the users to despair. So the navigation animation could become a kind of a generic "I am doing something" animation instead - I leave it to your disgression.

Oh, and a final PS

I had initially planned to use an old school animated GIF instead of a CSS animation. The thing that stopped me taking this course of action is that, to quote an answer on Stack Overflow "IE assumes that the clicking of a link heralds a new navigation where the current page contents will be replaced. As part of the process for perparing for that it halts the code that animates the GIFs.". So I needed animation that stayed animated. And lo, there were CSS animations...

Better make that a PPS - catering for IE 9 and earlier

I spoke a touch too soon when I expounded on how CSS animations were going to get me out of a hole. Unfortunately, and to my lasting regret, they aren't supported in IE 9. And yes, at least for now that is what the users have. To get round this I've delved a little bit further and discovered a frankly hacky way to make animated gifs stay animated after beforeunload has fired. It works by rendering an animated gif to the screen when beforeunload is fired. Why this works I couldn't say - but if you're interested to research more then take a look at this answer on Stack Overflow. In my case I've found an animated gif on AjaxLoad which looks pretty similar to the CSS animation:

This is now saved away as navigationAnimation.gif in the application. The JavaScript uses Modernizr to detect if CSS animations are in play. If they're not then the animated gif is rendered to the screen in place of the CSS animation HTML. Ugly, but it seems to work well; I think this will work on IE 6 - 9. The CSS animations will work on IE 10+.

Wednesday, 17 April 2013

IE 10 Install Torches JavaScript Debugging in Visual Studio 2012 Through Auto Update (Probably)

OK the title of this post is a little verbose. I've just wasted a morning of my life trying to discover what happened to my ability to debug JavaScript in Visual Studio 2012. If you don't want to experience the same pain then read on...

The Symptoms

  1. I'm not hitting my JavaScript breakpoints when I hit F5 in Visual Studio.
  2. Script Documents is missing from the Solution Explorer when I'm debugging in Visual Studio.

The Cure

In the end, after a great deal of frustration, I happened upon this answer on Stack Overflow. It set me in the right direction.

In my "Browse With..." drop down in Visual Studio I was *not* seeing this:

I was seeing exactly the same as this list but with TWO instances of Internet Explorer in the list instead of one. Odd, I know.

I fixed this up by selecting Google Chrome as my target instead of IE, running it and then setting it back to IE. And interestingly, when I went to set it back to IE there was only one instance of Internet Explorer in the list again.

The Probable Cause

My machine was auto updated from IE 9 to IE 10 just the other day. I *think* my JavaScript debugging issue appeared at the same time. This would explain to me why I had two instances of "Internet Explorer" in my list. Not certain but I'd say the evidence is fairly compelling.

Painful Microsoft. Painful

Tuesday, 9 April 2013

Making IE 10's clear field (X) button and jQuery UI autocomplete play nice

This morning when I logged on I was surprised to discover IE 10 had been installed onto my machine. I hadn't taken any action to trigger this myself and so I’m assuming that this was part of the general Windows Update mechanism. I know Microsoft had planned to push IE 10 out through this mechanism.

I was a little surprised that my work desktop had been upgraded without any notice. And I was initially rather concerned given that most of my users have IE 9 and now I didn't have a test harness on my development machine any more. (I've generally found that having the majority users browser on your own machine is a good idea.) However, I wasn't too concerned as I didn’t think it would makes much of a difference to my development experience. I say that because IE10, as far as I understand, is basically IE 9 + more advanced CSS 3 and extra HTML 5 features. The rendering of my existing content developed for the IE 9 target should look pixel for pixel identical in IE 10. That’s the theory anyway.

However, I have found one exception to this rule already. IE 10 provides clear field buttons in text boxes that look like this:

Unhappily I found these were clashing with our jQuery UI auto complete loading gif – looking like this:

I know; ugly isn't it? Happily I was able to resolve this with a CSS hack fix which looks like this:

And now the jQuery UI autocomplete looks like we expect during the loading phase:

But happily when the autocomplete is not in the loading phase we still have access to the IE 10 clear field button. This works because the CSS selector above only applies to the ui-autocomplete-loading class (which is only applied to the textbox when the loading is taking place). So we still get to use this:

Which is nice.

Monday, 1 April 2013

Death to compatibility mode

For just over 10 years my bread and butter has been the development and maintenance of line of business apps. More particularly, web apps built on the Microsoft stack of love (© Scott Hanselman). These sort of apps are typically accessed via the company intranet and since "bring your own device" is still a relatively new innovation these apps are invariably built for everyones favourite browser: Internet Explorer. As we all know, enterprises are generally not that speedy when it comes to upgrades. So we're basically talking IE 9 at best, but more often than not, IE 8.

Now, unlike many people, I don't regard IE as a work of evil. I spent a fair number of years working for an organization which had IE 6 as the only installed browser on company desktops. (In fact, this was still the case as late as 2012!) Now, because JavaScript is so marvellously flexible I was still able to do a great deal with the help of a number of shivs / shims.

But rendering and CSS - well that's another matter. Because here we're at the mercy of "compatibility mode". Perhaps a quick history lesson is in order. What is this "compatibility mode" of which you speak?

A Brief History

Well it all started when Microsoft released IE 8. To quote them:

A fundamental problem discussed during each and every Internet Explorer release is balancing new features and functionality with site compatibility for the existing Web. On the one hand, new features and functionality push the Web forward. On the other hand, the Web is a large expanse; requiring every legacy page to support the "latest and greatest" browser version immediately at product launch just isn't feasible. Internet Explorer 8 addresses this challenge by introducing compatibility modes which gives a way to introduce new features and stricter compliance to standards while enabling it to be backward compliant.
- excerpted from understanding compatibility modes in Internet Explorer 8.

There's the rub

Sounds fair enough? Of course it does. Microsoft have generally bent over backwards to facilitate backwards compatibility. Quite right too - good business sense and all that. However, one of the choices made around backwards compatibility I've come to regard as somewhat irksome. Later down in the article you'll find this doozy: (emphasis mine)

"for Intranet pages, 7 (IE 7 Standards) rendering mode is used by default and can be changed."

For whatever reason, this decision was not particularly well promoted. As a result, a fair number of devs I've encountered have little or no knowledge of compatibility mode. Certainly it came as a surprise to me. Here was I, developing away on my desktop. I'd fire up the app hosted on my machine and test on my local install of IE 8. All would look new and shiny (well non-anchor tags would have :hover support). Happy and content, I'd push to our test system and browse to it. Wait, what's happened? Where's the new style rendering? What's up with my CSS? This is a bug right?

Obviously I know now it's not a bug it's a "feature". And I have learned how to get round the intranet default of compatibility mode through cunning deployment of meta tags and custom http headers. Recently compatibility mode has come to bite me for the second time (in this case I was building for IE 9 and was left wondering where all my rounded corners had vanished to when I deployed...).

For my own sanity I thought it might be good to document the various ways that exist to solve this particular problem. Just to clarify terms, "solve" in this context means "force IE to render in the most standards compliant / like other browsers fashion it can muster". You can use compatibility mode to do more than just that and if you're interested in more about this then I recommend this Stack Overflow answer.

Solution 1: Custom HTTP Header through web.config

If you're running IIS7 or greater then, for my money, this is the simplest and most pain free solution. All you need do is include the following snippet in your web config file:

This will make IIS serve up the above custom response HTTP header with each page.

Solution 2: Custom HTTP Header the hard way

Maybe you're running II6 and so you making a change to the web.config won't make a difference. That's fine, you can still get the same behaviour by going to the HTTP headers tab in IIS (see below) and adding the X-UA-Compatible: IE=edge header by hand.

Or, if you don't have access to IIS (don't laugh - it happens) you can fall back to doing this in code like this:

Obviously there's a whole raft of ways you could get this in, using Application_BeginRequest in Global.asax.cs would probably as good an approach as any.

Solution 3: Meta Tags are go!

The final approach uses meta tags. And, in my experience it is the most quirky approach - it doesn't always seem to work. First up, what do we do? Well, in each page served we include the following meta tag like this:

Having crawled over the WWW equivalent of broken glass I now know why this *sometimes* doesn't work. (And credit where it's due the answer came from here.) It's all down to the positioning of the meta tag:

The X-UA-compatible header is not case sensitive; however, it must appear in the Web page's header (the HEAD section) before all other elements, except for the title element and other meta elements.
- excerpted from specifying legacy document modes

That's right, get your meta tag in the wrong place and things won't work. And you won't know why. Lovely. But get it right and it's all gravy. This remains the most unsatisfactory approach in my book though.

And for bonus points: IFRAMEs!

Before I finish off I thought it worth sharing a little known feature of IFRAMEs. If page is running in compatibility mode and it contains an IFRAME then the page loaded in that IFRAME will also run in compatibility mode. No ifs, no buts.

In the case that I encountered this behaviour, the application was being hosted in an IFRAME inside Sharepoint. Because of the way our Sharepoint was configured it ended up that the only real game in town for us was the meta tags approach - which happily worked once we'd correctly placed our meta tag.

Again, it's lamentable that this behaviour isn't better documented - hopefully the act of writing this here will mean that it becomes a little better known. There's probably a good reason for this behaviour, though I'm frankly, I don't know what it is. If anyone does, I'd be interested.

That's it

Armed with the above I hope you have less compatibility mode pain than I have. The following blog entry is worth a read by the way:

Finally, I have an open question about compatibility mode. I think (but I don't know) that even in compatibility mode IE runs using the same JavaScript engine. However I suspect it has a different DOM to play with. If anyone knows a little more about this and wants to let me know that'd be fantastic.