Building McLaren.com – Part 1: HTML

I’ve just finished working on McLaren’s new F1 site, http://mclaren.com/home, for the 2010 season, at Pirata London, for Work Club.

I’ll be writing up what we’ve done here in several parts. Sign up for my RSS feed to keep updated.

First up, the HTML. The site design is brilliantly engineered for layout on the web. It’s clean, fresh and bold. No rounded corners or “web 2.0” gradients. All credit to our designer, creative director and our client.

You might think this would be a breeze to implement, but actually it threw up several significant issues, which have been tricky. Here’s a few interesting ones:

Dymo labels

The design for the majority of text areas has a strip of colour behind each row of text. I call this the “Dymo label” effect, because it looks like strips of dymo tape.

To get this effect, one cannot assign a background colour to the block-level container, as this will just appear as a solid rectangular block. One needs an inline display element, so let’s use a span. We add a background color to this span, and add padding above and below the text for a bit of coloured space. The gaps between the lines are generated with the ‘line-height’ style. So our text size plus padding is 30px high, and our line-height is 36px, giving us a 6px gap.

Neat – our dymo-style strips are now placed. Only problem is that the text lines butt up hard against the white surrounds:

We want to add some padding to the start and ends of the lines, as shown here:

I tried a variety of options. Margins are useless, because they don’t apply to inline elements. Left and right padding works only on the beginning and end of the span, and so the sentence. Word spacing is only supported in a few browsers, and also increases gaps between words.

In fact, there is no way to control padding at wrapped line ends.

Asking on the CSS discussion groups pointed me to this item in the spec: ‘box-decoration-break‘. This obscurely named property would enable me to treat each line as a box, enabling me to add padding to the start and end of each line. I find the explanation completely confusing, since it mostly concerns itself with page breaks. It’s also unclear whether this fix will solve my inline blocks problem.

Of course, the biggest problem with this idea is that it’s so complex and unasked-for, that it hasn’t been implemented by any browser vendors, and as such, may drop out of the specification.

The following features are at-risk and may be dropped at the end of the CR period if there has not been enough interest from implementers: ‘box-decoration-break’.

And yet, since this is specified, there is resistance to the idea of implementing this (clearly useful) feature in any other way. Personally, I would like to see a ‘wrapped-line-padding’ property.

Another suggestion was to use a striped background-image property, with scaling. I imagine that would work, but present the same problems. If applied at the block-level, the last line would run to the end of the box. If applied inline, there would be no padding.

So, what have I done? I have implemented a fix in JS of course, and look forward to your inevitable criticism. 🙂

$(document).ready(function() {
	if(!$.browser.msie || $.browser.version>7) $('span').not('.no-jswrap').each(function() {
		var text = $(this).html();
		var outstr = text.replace(/([^ ]+)/g, '<b>$1</b>');
		outstr = outstr.replace(/ /g, '');
		$(this).html(outstr);
		$(this).addClass('jswrap');
	});
});

After document ready, each word is wrapped with deprecated, but still valid, <b> tags. I then remove the spaces between the words.
The <b> tags have padding of their own.

The downsides to this approach are of course, extra JS (though it’s only a cosmetic enhancement, so I’m not fussed if you’re running without JS. And the bigger issue – the lack of spaces. If you cut and paste text from the site (notice the pretty selection styles when you do), then your text pastes without spaces. I can only apologise, and hope that it doesn’t ruin your screenreader.

Jenson-Champion’smoment 2009BrazilianGrandPrix- AdelugeonSaturdayafternoonleftJensonpowerlesstoovercomehiscar’sgripproblems,andhequalifiedadisappointing14th.OnSunday,however,hedrovewithflairandmercilessaggressiontosweepthroughtofifth–itwasnocoincidencethatoneofhisgreatestdrivesfinallyelevatedhimtothestatusofworldchampion.

But it does give us our line padding.

Hiding Navigation

The navigation at the top of the page hides itself away after an amount of time. It won’t win any usability awards of course, but might garner ourselves the odd design award (who never like sites to be too easy). Regardless, it’s got to be hidden away.

This was a simple effect to add. I simply used jQuery to hide the navigation element after 3 seconds of the page loading, revealing if the user rolls their mouse over it. After implementing it locally, I found an immediate issue. When clicking to a new page, it was easy to leave the mouse over the navigation, which wouldn’t trigger a mouse enter event, especially if focus was on another window or tab. Basically, it produced a lot of circumstances where the navigation was hiding, regardless of the mouse being over the nav. Not good.

I have now moved the event, so the trigger for the timer would only start after the user rolls over the content on the page. This works a lot better, though it’s a little confusing because the navigation appears or disappears seemingly at random. But it’s effective, and it works.

The next problem was based on scrolling. If you scroll to the bottom of a page, then use jQuery to slowly hide an element higher up the page, the document gets shorter. Browsers do not handle this smoothly (even Chrome). The screen flickers and jumps all over the place, and is likely to induce seizure even in the most hardened fans of strobe lighting.

I solved the scroll problem by hiding the navigation immediately after a page scroll. So, on any scroll event, the nav disappears, fast. No more flicker, no more problems.

	/*
	 * Expand and contract the navigation
	 */
	var navHider = function() {
		// show the nav when you roll over the top
		var showNav = function() {
			clearTimeout(navHideTimer);
			$('#navigation-wrapper').slideDown("slow");
		};
		// hide the header 1 sec after you roll over the content
		var hideNav = function() {
			clearTimeout(navHideTimer);
			navHideTimer = setTimeout(navHiderAction, 1000);
		};
		$('#header').mouseenter(showNav);
		$('#header a').focus(showNav);
		$('#header a').blur(hideNav);
		$('#content').mouseover(hideNav);

		// the hiding function
		var navHiderAction = function() {
			if (hiderEnabled) $('#navigation-wrapper').slideUp("slow");
		}
		// if the window is scrolled, hide it quickly to avoid jerky/flickering effects
		$(window).scroll(function() {
			clearTimeout(navHideTimer);
			if (hiderEnabled) $('#navigation-wrapper').slideUp(100);
		});
		var navHideTimer = 0;
	};

Of course, you’re probably still thinking of the usability issues. Certainly, we initially saw a large number of visitors to our footer links (like the copyright page) when we launched, but this has flattened off. Our visitors have found the navigation, they know how to bring it back, and we’ve had several compliments from the online design community. I think we’ve brought our visitors with us on this one, and it’s probably acceptable now.

Shadowbox URLs

We use the cool ShadowBox plugin for our lightbox effect. But of course, the articles shouldn’t show navigation in the lightbox, so they have to know when they’re in the lightbox and when they’re not. I want to keep the link the same, so non-JS users can use the article links as they stand.

Simple fix to the init for ShadowBox gives the solution:

	Shadowbox.init({
		players:['iframe','img','swf','html'],	
		onOpen:function(e) {
			// let the page know that it shouldn't show headers
			if (Shadowbox.gallery[0].player=='iframe' &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; !Shadowbox.gallery[0].content.match('iframe=true')) Shadowbox.gallery[0].content = e.content = e.content+'?iframe=true';
		},
		onClose:function(e) {
			// reload the CSS in IE8 to avoid sporadic font-face corruption
			$('#main-css').each(function() {
				this.href = this.href.split('#')[0];
			});
		}
	});

This tells ShadowBox to append the ‘?iframe=true’ querystring to links as they are opened. Note that I’ve also added a font-face fix for IE8 to the onClose function – for this to work, you’ll need to put an ID on your main stylesheet of ‘main-css’.

That’s it for the HTML. In the next part, I’ll look at the telemetry feed.