Big news for web fonts and video today

WebM Video

The codec wars around the HTML5 video element might be settled sooner than you think:

Basically, Google just open-sourced VP8, a video codec. VP8 is being combined with the Vorbis audio codec to create a new video format called WebM.

This wouldn’t be news at all except that a ton of groups have already pledged to support it, including Firefox, Chrome, Opera, and Youtube(!). YouTube has committed to encoding EVERY video on their service to WebM, including the back catalog.

Given that kind of support, I would be shocked if it didn’t get back-ported into Safari, and then IE9 announced support as well. Whatever happens, this is worth keeping an eye on.

Typekit and Google

Google released a bunch of open source fonts (including the Droid fonts and Inconsolata, the finest monospace font I’ve ever used). They also released the Google Font API, which is really just Google doing all the @font-face generation and declarations, as well as encoding the fonts for all browsers.

Then Typekit announced that they were open-sourcing their javascript font-loading API, which fires events at various points in the font-loading process, so you can make a more consistent cross-browser experience. That library is now an open-source collaboration with Google, the WebFont Loader, and can be used through Google’s ajax library.

Pretty cool that Typekit would open their doors like this, and it speaks to their (and Google’s) commitment to making fonts easy to use for everyone, not just paying members.

Note: This was originally posted on my work blog, and I’m re-posting it here for archival purposes.

How to use jQuery to open external links in a new window

A common request from clients is to open all external links on their website in a new browser window. (Leave aside for now whether this is a good idea or not, and just assume that you need to do it.) It’s easy enough to add target="_blank" to a link, but there are two problems. First, the target attribute is deprecated, so we don’t want to use it in our nice standards-compliant code. Secondly, on a large content-managed site, you might not have control over every link.

jQuery to the rescue! We can use $("a[href^=http://]") to select all links that start with http:// and then .attr("target","_blank"); to add the target attribute so they will open in a new window.

But now we have a new problem. In a content-managed system, the site will commonly render all links, even local ones, using a full URL. Now your jQuery is opening every link on the site in a new window. So we’ll write a few more lines of code to remove the target attribute from local links.

$(function() {
  $("a[href^=http://]").attr("target","_blank");
  $("a[href^=http://example.com/]").removeAttr("target");
  $("a[href^=http://www.example.com/]").removeAttr("target");
  $("a[href^=http://dev.example.com/]").removeAttr("target");
  $("a[href^=http://example.local/]").removeAttr("target");
  $("a[href*=.pdf]").attr("target","_blank");
});

As you can see from the example, I’ve removed it from any links that include the final domain name, both www and plain versions. I’ve also removed it from the dev site and from example.local, which might be a local installation of the site. You could add or remove any of these as needed, they’re just examples.

The last line is there because the client also wants all PDF files, whether on our site or elsewhere, to open in a new window, so we add the target attribute back on for any link that ends in .pdf.


How to use jQuery to target CSS at older browsers

On a recent project where I had to support Firefox 3.6, 3.0 and 2.0, I had to find a way to target a specific version of the browser due to differences in the rendering engine. It turns out the easiest way to do this is by using jQuery to detect the browser and add a class to the body tag.

// add a body class for firefox 2.0 only
if($.browser.mozilla && $.browser.version.substr(0,5)=="1.8.1") {
  $('body').addClass('ff2');
}

// add a body class for firefox 3.0 only
if($.browser.mozilla && $.browser.version.substr(0,5)=="1.9.0") {
  $('body').addClass('ff3');
}

The reason $.browser.version doesn’t appear to match is because for Firefox, jQuery actually detects the version of Gecko, the rendering engine. You can see which versions of Gecko line up to which versions of Firefox on this chart.

The dangers of browser detection have been covered in depth elsewhere, but in this case, I feel it’s acceptable because A) we’re detecting a browser version as well as a browser type, and B) we’re targeting old versions of the browser, whose usage in our stats are 5% or less (but for this particular client, we’re obligated to support them anyway). If someone has a better way, I’m open to it. In the meantime, this solved my problem nicely.


jQuery Slide-Down Language Selector

A site I worked on recently had an international link, and when the user clicked on it, the whole page was supposed to slide down and reveal a language picker. I found some jQuery to slide the page down, but it relied on the language picker being the first div on the page. For SEO reasons, I didn’t want that, so I put the language picker code into the normal site navigation, and then used jQuery to move everything into position. Here’s how it works:

HTML

<body>
<div id="placeholder-regions"></div>
<div id="container">
  <h1>Page Title</h1>
  <ul id="utilities">
    <li><a href="#">Utility Link One</a></li>
    <li><a href="#">Utility Link Two</a></li>
    <li id="util-int"><a href="#">International</a>
      <div id="util-regions">
        <h4>Select Regional Site</h4>
        <ul>
          <li><a href="#">Europe</a></li>
          <li><a href="#">Australia</a></li>
          <li><a href="#">Deutchland</a></li>
        </ul>
      </div>
    </li>
  </ul>
...
  <p>Page content...</p>
</div>
</body>

Two things to notice here. First, there’s a blank placeholder div, which is the first bit of markup inside the BODY element. Second, the International code is all included in the regular navigation as an LI element. That way, users without javascript still get a functional site, and the search engine spiders can see the most important content, like the headlines, at the top of the page.

Note these two IDs, as well. #util-int is the list item that contains the link to show and hide the internation section. #util-regions is the div that contains the international section, which we want to show and hide.

jQuery

// scroll the page to display the international section
$('#util-int').toggle(function() {
  $("#util-regions").remove().prependTo("#placeholder-regions").slideToggle('swing');
}, function() {
  $("#util-regions").slideToggle('swing');
});

This jQuery is pretty compact, but in plain english, what this says is when util-int is toggled (clicked), then move #util-regions from the navigation into the placeholder DIV at the very top of the page, and also show and hide it. The slideToggle() code is what shows and hides the international section, and the remove() and prependTo() code is what moves the code into the placeholder DIV.

CSS

#util-int {
  z-index: 1000;
}
#util-regions {
  display: none; /* hidden by default, will be shown by jQuery */
  width: 948px;
  margin: 0 auto;
  height: 60px;
  position: relative;
}
#placeholder-regions {
  background: #666;
}

Some important things to note: #util-int has a very high z-index value to make sure it appears on top of anything else. #util-regions has a width and height, and is position: relative so that its contents can be absolutely positioned within, and is also hidden by default (the jQuery will show it later on). #placeholder-regions has a background, but no height, padding or margins, so that when we show and hide #util-regions, it will collapse gracefully.

You can see a version of this code in action over here.


jQuery Popup Footnotes

A recent site I worked on had footnote references throughout the body copy, and a corresponding list of footnotes at the bottom of the page. That’s easy enough to mark up, but the client also wanted the footnote to display it a little tooltip-style popup when you moused over the footnote reference.

I didn’t want to duplicate the footnotes in the markup, so I used jQuery to copy the contents of the footnote and display it. Here’s the code.

HTML

<div id="content">
  <p>Sentence with a footnote<sup><a href="#footnote3">3</a></sup>.</p>
</div>
...
<div id="footnotes">
  <p id="footnote1"><sup>1</sup> This is footnote number one.</p>
  <p id="footnote2"><sup>2</sup> This is footnote number two.</p>
  <p id="footnote3"><sup>3</sup> This is footnote number three.</p>
  <p id="footnote4"><sup>4</sup> This is footnote number four.</p>
</div>

Note that the href on the footnote reference must match the ID on the footnote, so that jQuery can associate them properly. As a bonus, in a non-JS environment, the footnote references will just link down to the proper footnote.

jQuery

// add markup to all footnote references
$("sup a").append("<span><em></em></span>");
// on hover, show the popup and add the matching footnote
$("sup a").hover(function() {
  // show the popup
  $(this).find("span").fadeIn();
  // use our href to find the apprpriate content from the footnote list
  var content = $(this).attr("href");
  var content = $(content).html();
  // copy the footnote content into the popup
  $(this).find("span em").html(content).append("<br /><br />All references are listed at the bottom of the page.");
}, function() {
  // hide the popup on mouseout
  $(this).find("span").fadeOut();
});

This looks much more complicated than it is. In plain english, we add some markup (a span) to each footnote reference, and then use its href to find the correct footnote from down below, and copy its content into the span we just created. Then we show and hide the span when the user hovers over the footnote reference.

CSS

sup a {
  position: relative;
}
sup a span {
  display: none; /* hidden by default */
  width: 294px;
  height: auto;
  position: absolute;
  left: -125px;
  bottom: 1em;
  /* sliding door background image - bottom half on span, top half on em */
  background: transparent url("/images/bg-footnote-bottom.png") no-repeat left bottom;
  padding-bottom: 13px;
  cursor: default;
  z-index: 999;
  text-decoration: none; /* other wise, this is underlined like a link */
}
sup a span em {
  display: block;
  font-style: normal;
  background: transparent url("/images/bg-footnote-top.png") no-repeat;
  padding: 20px 10px 15px 20px;
}

Nothing complex here. We’re using a vertical sliding doors technique to allow the background on the popup to grow to accommodate varying amounts of text. The only other hiccup is to remember to override your link styles within the span, since the browsers will treat your popup as part of the link.

You can see a version of this code in action over here.