Site icon Treehouse Blog

Stay on :target

In this article, I want to introduce you to a really powerful CSS3 pseudo selector called :target. Much like :hover, :target is invoked during certain interactions with the website. Specifically, when applied to a fragment identifier. On a page such as, the id=”hello-world” element is the target and any matching :target styles would be applied.

I am going to demonstrate two examples of when and how :target can be used. Hopefully, this introduction will get you thinking about some of simple ways :target can add benefit your customers.

Tabs in CSS

A well structured document is one that makes sense in the ordering of sections and topics. It works well when there is no CSS and no JavaScript. Tabbed systems make use of some sort of display tab which shows the current section, and in doing so hides the other sections. We’ve all seen a tabbed system before, and probably plenty of poor implementations as well. Sometimes when you click the tab, it calls a JavaScript function to populate the area below the tab. The downside is that when there is no JavaScript the data does not appear.

The ideal way to build a tab system is to have all your data in the HTML, then use JavaScript to hide the other tab panes and build the tabs themselves dynamically. That way if there is no JavaScript, it just defaults to a linear set of text blocks. This is progressive enhancement; build for the lowest common denominator and add more functionality and styling as you go — no one is left behind, not even googlebot.

Instead of using JavaScript to do this show/hide, it is possible to use CSS3 using the :target selector. Before you get too excited, it must be said that the :target selector is not supported in IE6 or IE7, so the practical uses for this are pretty slim. Instead this can be used for user chrome type objects which don’t effect functionality, but improve usability. You can add the :target info today, and when browsers implementations catch-up they get the bells and whistles auto-magically. It is important to not use :target for mission critical things, but there are plenty of other possibilities. As an example, I will show you how make a simple tab system based on Daniel Glazman’s example.

First we should create the basic un-styled HTML.

<h2 id="topic1"><a href="#content1">Topic 1</a></h2>
This is the text for topic 1. Hello World!
<h2 id="topic2"><a href="#content2">Topic 2</a></h2>
Different text for topic 2. Ah, foobar.

Without CSS or JavaScript this text is completely accessible and reads normally, it just makes the page longer. Tabs are a way to compact the information into a smaller space, so lets proceed to do this.

If we add some simple styles to the page, we can get the two headings to appear and act like tabs through positioning. The interesting part is the :target selector.

// set the default state first
p {
display: none;

// When the link is clicked, set the contents to display
p:target {
display: block;

When the fragment (#content1) is not part of the URL, the :target selector does not match the

element, so it is set the default view of display: none. This is a very simple way to create a tabbed system.

The Yellow Fade Technique

There is a popular usability feature called the “Yellow Fade Technique”. This is used to direct the user’s attention back to a specific area subtly. For example, when you want to edit a piece of a page you may click edit which takes to a new page with form fields. When you press save you are returned to the original page where there is a brief yellow fade of the area that was just edited. It brings your eye to the area, possibly to confirm the changes look correctly in the template, or to just make people aware the change took place at all. Either way, it seems to be a welcomed usability feature that has been picked-up by several web applications.

Normally, this is accomplished through the use of JavaScript and page IDs or classes. The JavaScript runs an onload function looking for those classes or ID and once the parts of the page have been identified, the script runs a timer and ever few microseconds change the background color from pure yellow to white. This create a smooth, not too annoying, yellow fade effect.

The downside to all this is that there are several resources at work, including onload functions (which might be happening every time the page loads, not just the times when a form is submitted) and hooks into the classes and IDs and JavaScript timers. All this adds to the client download and subtracts from the speed of the page.

With CSS3 there is a much easier and simpler solution. Using the :target pseudo class it is possible to emulate the yellow fade without a single line of JavaScript.

First, you need to create a tiny 1 pixel-wide yellow animated gif. This will fade from yellow to white. The animated gif isn’t repeating, so it will fade once and then stay pure white. This also defines the length of the fade, so there is no need to for a JavaScript timer.

Second, we need to set this as the background image for the area which has been changed. To do this, we use the CSS3 :target pseudo selector.

#here:target {
background-image: url('yellow-fade.gif');

This will fade the element with an id=”here”, the URL would look like It is good web architecture to use fragment identifiers for each of your headings and to use RESTful URLs.

Now, the downside to that CSS statement is that it will only fade the area with the ID.

<h1 id="here">Hello World</h1>
I am saying Hello to everyone in the World!

Only the heading element would get the yellow fade. So how do we fix this? Well, we could change the ID to a class and create something like:
.here:target {
background-image: url('yellow-fade.gif');

But then on the server, we’d have to add classes dynamically to all our elements.

<h1 class="here">Hello World</h1>
I am saying Hello to everyone in the World!

We could put a wrapper around both the heading and the paragraph.

<div id="here">
<h1>Hello World</h1>
I am saying Hello to everyone in the World!

But that seems too much work. Instead, we can make use of another CSS combinator, the adjacent sibling selector:
#here:target, #here:target p {
background-image: url('yellow-fade.gif');

This targets both the heading with the ID ‘here’ and the first sibling paragraph. So both will get the background image and the subsequent fade. You can easily change your CSS to fit your HTML design, but this is a quick and simple alternative to the Yellow Fade technique in JavaScript used on so many sites.

In CSS there is also a wildcard * to stand for all nodes. So you could further take the example to
#here:target, #here:target * {
background-image: url('yellow-fade.gif');

This would match the first sibling of #here no matter what the type of element it might be. Firefox correctly supports this, but as of writing, Safari does not.

Blurring the lines between behaviour and presentation

I am obligated by the behaviorists to mention that there is a debate over presentation and behavior, where does one stop and the other start? By adding the :target selector into your CSS, you are styling the HTML based on the behavior of the browser and the users. We talk about the “holy trinity” of web design, and we have spent the last few years campaigning to divide data, presentation and behavior into their respective HTML, CSS and JavaScript camps. The :target, as well as the :hover, selectors blur that line between presentation and behavior. Depending on how comfortable or how much of a purist you are, you may or may not agree with what has been demonstrated.

These examples were written to better understand the CSS3 :target element and to explore those blurry grey-areas. Hopefully, a discussion will emerge with even more ideas, caveats and problems that were not originally thought of. Together we can create some best practices on when to best use CSS behavior and JavaScript presentation.


Over a year ago, Andy Budd demonstrated the yellow-fade technique with :target and I was impressed! ( In the time in between, I have seen very little attention or articles on this little known selector. As I was started working on this article, I found several examples some from as early as January 2003 that talk about uses for the :target selector. The reason for not getting the traction it deserves could be the lack of information about when and how to use it correctly or documentation on the poor CSS3 implementations in browsers.

CSS3 is closer than you think, many of the selectors and attributes are available in several major browsers today. They can be used with progressive enhancement to add more style to your design at little cost, when other browsers catch-up they get the benefits of your progressive code for free. The CSS3 :target selector is just one example of some of the new selectors arriving that can be taken advantage of in interesting new ways.

Exit mobile version