The Elusive :target Feature Test

Update: I rewrote this post after determining my feature test was unnecessarily complex. Check out the post diff.
Update #2: This has made its way into Modernizr.
If you’re not familiar with :target, check out this very simple example before readin…

Update: I rewrote this post after determining my feature test was unnecessarily complex. Check out the post diff.

Update #2: This has made its way into Modernizr.

If you’re not familiar with :target, check out this very simple example before reading this post.

:target is a CSS pseudo-class that is often overlooked. It’s a very useful tool in the performance toolkit for moving content hiding from JavaScript up the toolchain into CSS. “Anything CSS can do, JavaScript can do worse”.

With proper Progressive Enhancement, using :target can unfairly feel like it’s creating additional work for you to do since you’ll often still have to write that JavaScript for browsers that don’t support :target (IE8 and below don’t support it—but surpringly Android 2.1+ and Windows Phone 7.5 do). The benefit of using :target is perceived performance. The non-primary content (non-active pages/tabs/menus/et cetera) is hidden higher in the waterfall (assuming a best practice of loading your CSS at the top of the page) than they would’ve been if the hiding code lived in JavaScript.

Another great benefit to using target is that it allows you to use history entries when navigating around on the page (and direct linking to specific content) unless you opt-out of this feature using JavaScript. Chris Coyier describes this is in his post On Target (see the section titled ‘Fighting the Jump’). One limitation of this approach is the current WebKit (and Blink) and Gecko bugs that do not reevaluate CSS when the hash is updated using replaceState (without modifying history) or pushState (to add a history entry) (JSBin Example).

$("a[href^=#]").on("click", function(e) {
e.preventDefault();
history.pushState({}, "", this.href);
});

There are two issues with this method of Fighting the Jump:

  • The page jumps to the newly targetted content.
  • The CSS rules are not re-evaluated.

We can eliminate the second issue with the long forgotten location.replace() method (or it’s twin brother location.hash). You can use replace in lieu of replaceState (or hash instead of pushState) to update the hash and re-evaluate CSS.

// Will re-evaluate CSS.
// Yes, including any newly applicable :target rules.
location.replace( '#myhash' );

Sadly, this method does not resolve the first issue with “Fighting the Jump.” The page will still scroll to the newly targetted content. But it does allow us to avoid adding a history entry. (If you are fine with the history entry, don’t add any JavaScript at all.)

$("a[href^=#]").on("click", function(e) {
e.preventDefault();
// Basically the same as doing nothing except we bypass a history entry.
location.replace( '#' + this.href.substr( this.href.lastIndexOf( '#' ) + 1 ) );
});

However, we won’t use the same mechanism for our feature test. As it turns out, a :target feature test is much simpler.

Feature Test #

Requirements for a good :target feature test:

  • Must be able to execute prior to DOMContentLoaded.
  • Must be unobtrusive and not add a history entry.

A previous version of this blog post included a feature test that attempted to set the hash and measure the updated CSS rules to see if :target applied. This turned out to be woefully overcomplicated. We can exploit the fact that querySelector will throw an error if you feed it an unsupported selector (:target, for example). This means we don’t have to modify the hash at all, which is much safer. (Credit to @wilto for showing me this method.)

Demos #

The new document.querySelectorAll(':target') Method #

  • Chrome 31: Passes
  • Firefox 25: Passes
  • IE7, IE8: Fails Correctly (Not supported)
  • IE9, IE10: Passes
  • Safari 7: Passes
  • Android 2.3: Passes
  • Windows Phone 7.5: Passes
  • BB6.1, BB7: Passes
  • BB5: Passes Correctly and does not require an opt-out like the other method.
  • Kindle 3.4: Passes and does not add a history entry like the other method.
  • Opera Mini: Passes correctly (unlike the other method) but requires a server refresh to repaint the page.
  • Opera 9.10: Fails Correctly (Not supported)
  • Opera 12: Passes

The old location.replace Method #

(Included for posterity)

  • Chrome 31: Passes
  • Firefox 3.6: Opts out of the test to use document.scripts. Otherwise, would pass.
  • Firefox 25: Passes
  • IE6, IE7, IE8: Fails Correctly (Not supported)
  • IE9, IE10: Passes
  • Safari 4, 5, 5.1, 6, and 7: Passes
  • Opera Mobile: Passes
  • Android 2.3: Passes
  • Android 4.1: Passes
  • Windows Phone 7.5: Passes
  • iOS 7: Passes
  • BB6.1, BB7: Passes
  • BB5: Opt-ed out of the test using a weak inference. This test caused BB5 to go all infinite redirect, so the feature test hard-returns false for any non-WebKit Blackberry.
  • Kindle 3.4: Passes (But adds a history entry)
  • Opera Mini: Fails Incorrectly (Is supported, but buggy)
  • Opera 9.10: Fails Correctly (Not supported)
  • Opera 12: Passes

Print Share Comment Cite Upload Translate
APA
Zach Leatherman | Sciencx (2024-03-28T20:14:36+00:00) » The Elusive :target Feature Test. Retrieved from https://www.scien.cx/2013/11/20/the-elusive-target-feature-test/.
MLA
" » The Elusive :target Feature Test." Zach Leatherman | Sciencx - Wednesday November 20, 2013, https://www.scien.cx/2013/11/20/the-elusive-target-feature-test/
HARVARD
Zach Leatherman | Sciencx Wednesday November 20, 2013 » The Elusive :target Feature Test., viewed 2024-03-28T20:14:36+00:00,<https://www.scien.cx/2013/11/20/the-elusive-target-feature-test/>
VANCOUVER
Zach Leatherman | Sciencx - » The Elusive :target Feature Test. [Internet]. [Accessed 2024-03-28T20:14:36+00:00]. Available from: https://www.scien.cx/2013/11/20/the-elusive-target-feature-test/
CHICAGO
" » The Elusive :target Feature Test." Zach Leatherman | Sciencx - Accessed 2024-03-28T20:14:36+00:00. https://www.scien.cx/2013/11/20/the-elusive-target-feature-test/
IEEE
" » The Elusive :target Feature Test." Zach Leatherman | Sciencx [Online]. Available: https://www.scien.cx/2013/11/20/the-elusive-target-feature-test/. [Accessed: 2024-03-28T20:14:36+00:00]
rf:citation
» The Elusive :target Feature Test | Zach Leatherman | Sciencx | https://www.scien.cx/2013/11/20/the-elusive-target-feature-test/ | 2024-03-28T20:14:36+00:00
https://github.com/addpipe/simple-recorderjs-demo