Ask the CSS Guy

Link Boxes

I was looking over the shoulder of another designer who wanted a box with a headline and copy, and wanted the entire thing to be clickable. Here are some thoughts on marking this up.

As a brief aside, I started looking for this effect on other web sites so I can see how others mark it up, but wouldn't you know it, I couldn't find any examples. (Never there when you need them...) If you know of any, leave a comment with a link so we can peak under the hood. I'm confident there is a better way, or at least some solid alternatives out there, to achieve this effect - let me know what they are.

The Idea

A box contains a headline and some copy, and we want the entire box to act as a link to another page. Let's pretend for now it's an "About Us" type of box that we want to look like this:

Forgetting about the link for now, here's some code that would make sense to start with.

<h2>About Us</h2>
<p>How my life story became a Hallmark movie.</p>

I realize that perhaps using <dt> and <dd> could establish more a relationship between the headline and copy, but I'm not sure how I would achieve the end result that way, so stick with me.

To get the box effect, and link effect, a temptation is to do this:

<a href="#">
  <h2>About Us</h2>
  <p>How my life story became a Hallmark movie.</p>
</a>

but that's a no-no. <a> is an inline element, and block-level elements (like <h2> and <p>) cannot be nested inside inline elements.

However, inline elements can be nested within other inline elements, so one way to work around the validation hurdle is to use <span> tags within the encompassing <a>, like so:

<a href="#">
  <span class="h2">About Us</span>
  <span class="paragraph">How my life story became a Hallmark movie.</span>
</a>

Then the span elements could be styled as display:block; and be presented like one would want them to be.

This could work. If styles are turned off, the spans may all run together, but that could be easily fixed with a <br /> following the first <span>. Still, it doesn't really seem like an ideal way to mark this up.

I am guilty of using spanitis to achieve this kind of thing, and that's partly why I'm doing this post - to find a good way out of it. I want to keep some semantic meaning with my tags, not just with my classes. I want to keep the <h2> and the <p> because they mean more than <span>, but how do I get the clickable encompassing box? For that, I'm guessing I need more than what can currently be provided by HTML tags. I need DOM Scripting.

A DOM Scripting approach

I envisioned wrapping the headline and paragraph in a <div>, and attach the link to the <div>'s onclick event using JavaScript. Also, if JavaScript is off, we should still provide a link, so I ended up with this:

<div class="linkbox">
  <h2>About Us</h2>
  <p>How my life story became a Hallmark movie.</p>
  <p class="readmore"><a href="#">Read more...</a></p>
</div>

Before writing the JavaScript, it sometimes helps to put the desired behavior in plain English.

  1. When the page laods, the find all <div> tags with a class of "linkbox".
  2. Within a linkbox div, find the "readmore" paragraph, which should contain an anchor link.
  3. Take the href attribute's value of the anchor link, and attach it to the encompassing div's onclick event.
  4. Since the "readmore" paragraph is no longer needed, hide it.
  5. To give an indication that the <div> is clickable, add a hover effect by adding and removing a hover class to the <div> based on mouse placement.

To help achieve all this, I borrowed functions from Robert Nyman's EJ - The only JavaScript library you’ll ever need, which contains some homegrown scripting for getting elements by their class name, adding a class name, and removing a class name.

Working Example

Showing you the code in this post would be pointless. Instead, go to the working example, where you can view source and modify to your pleasure. Note that instead of using <div>, I used an unordered list to organize the page differently. Turn off CSS, JavaScript, or both, and all needed elements should still be present.

Comments (39)

TIGOS said:

Great tip... I will use this with certainty

Thanks Guy!

chris said:

this site has an example of what you may be trying to do:

http://hd.se/

didn't try to see how its done myself, but i'd assume javascript is used there.

Marc said:

Veerle uses this in the approved section of her site.

http://veerle.duoh.com/

CSS Guy said:

@Marc:

Thanks for the link.

Veerle is using all inline elements, including <em> tags, wth <br /> tags to break them up.

<a href="">Headline<br />
  <em>copy copy copy</em><br />
  <span>date posted</span>
</a>

Now that I think about it, using <strong> to emulate headlines makes sense, too.

Kate Bolin said:

Couldn't you just use

<a href="#">
<strong>Headline</strong>
Text text text
</a>

?

It just seems to me to be a bit over the top to use all that javascript...

Eric DeLabar said:

If I may propose an alternate solution...

HTML:

<div>
<h2><a href="#">About Us</a></h2>
<p><a href="#">How my life story
became a Hallmark movie.</a></p>
</div>

CSS:

div {
width: 200px;
height: 4em;
padding: 0;
border: solid 1px #999;
}
h2 {
width: 190px;
height: 1em;
margin: 0;
padding: 0 5px;
position: relative;
}
p {
width: 190px;
height: 3em;
margin: 0;
padding: 0 5px;
color: #333;
}
h2 a {
color: #B84300;
position: absolute;
display: block;
top: 0;
left: 0;
width: 190px;
height: 3em;
padding: 0 5px;
text-decoration: none;
}
div p a {
color: #333;
text-decoration: none;
}
div:hover {
background-color: #999;
}

It would still need JavaScript for IE6 due to the lack of :hover pseudo-element support on a div (Possibly similar to Suckerfish Dropdowns), but it's not necessary for IE 7 or Firefox. (Sorry, can't test it in Safari right now...)

I guess you could also argue it's a little fragile because you need to know the final height of the box at design time in order to style the h2 a, but I suppose you could fix that with some javascript.

Mrad said:

What about:

About Us

How my life story became a Hallmark movie.


Check it out!

Set the a tag to display block with height and width dimensions, the span to display:none, and position the a tag absolutely over the text, making your button. I think that'll degrade nicely too.

Just a thought.


Mrad said:

Oops. Too early in the morning. I meant this:


<h2>About Us</h2>
<p>How my life story became a Hallmark movie.</p>
<a href=""><span>Check it out!</span></a>

CSS Guy said:

@Kate:

Yes, and that is probably the simplest solution for the examples I've provided. I may not ever need to make any more out of it, and neither might anyone else, but I do wonder if there is ever a scenario where the "intro text" isn't just a paragraph, but an unordered list or some other mix of markup.

@Eric:

div:hover would be nice, wouldn't it? Then we could style the "h2 a" to be the top of the box, and "p a" to be the bottom.

I'm wondering if there could be a need for a block-level link tag.

Eric DeLabar said:

@CSS Guy:

My original thought did not have the div, I put a border on the top and sides of the h2 and the bottom and sides of the p, but when you changed the background-color of the "h2 a:hover" it covered the p. I thought the p, being lower in the document would naturally have a higher z-index than the a, but I was forgetting the fact that the a was absolutely positioned, so it would always be above the p, unless the p was absolutely positioned.

So I tried absolutely positioning the "p a" but in order to do that the p needed to be relatively positioned, which naturally put it higher than the "h2 a", so the "h2 a:hover" no longer fired when hovering over the "p a".

On a different train of thought I also considered the adjacent-sibling-selector to trigger the background change on the p (i.e. h2 a:hover + p) but without a previous-adjacent-sibling-selector I couldn't change the background of the h2. Of course even if it did exist, the + selector doesn't work in IE 6 anyway so Javascript would still be necessary.

Oh well...just a little on my train of thought if you were interested... :)

Michael said:

Great tip, but what about the status bar text?

I'm very much not-JS (somehow my brain just won't understand it), but I'm pro-show-where-the-user-is-going, so a way of showing the url in the status bar, would be very much appreciated.

CSS Guy said:

@Mrad:

I posted your example here. It could work, but there's no hover state. For kicks, I added a hover state to the <a> tag, which shows that the <a> tag does, in fact, encompass the entire box, but changing the text presentation for :hover isn't doable here.

@Eric:

I enjoy reading and following train of thought - particularly somebody's other than mine so I can exercise thinking outside of my own box every once in a while. Adjacent sibling idea is clever, but as stated, doesn't really do the trick for IE6 without an added push with script.

@Michael:

Good observation, and a setback I noticed as well. I frequently use the status bar to keep an eye on where I'm going, and by default, the method I describe above doesn't cut it (without more scripting).

Cliff said:

Thanks, CSS Guy, very interesting way of going about this.

Here's my own perversion of your example, just using CSS and an unordered list, since it's really just a menu. Could be cleaned up, and it's not as pretty without styles, but it makes sense.

CSS Guy said:

@Cliff:

Nice to see it in action. And I think that nails it as the way to go for these examples.

Or, I'm now thinking it could be easy to sneak in a colon right after the strong tag, wrap the colon in a span, and set it to display:none to help those unstyled folks differentiate the headline from the rest of the text. Too much?

So that's that. Well, I had fun with the exercise. Maybe the technique will come in handy for something else.

ben said:

Hi,

As you proposed I use definition lists to achieve the same effect, examples can be seen here:

http://www.ncpta.org.uk/events/100806/100175/ncpta_regional_events/

Another example using an image:

http://html.eval.poptech.coop/compact/news.html

I have been considering adding in the status bar text as well to aid usability, following the comments I think its the right thing to do.

ben

Simon said:

@Eric: With accessibility in mind, linking the story summary isn't great. I believe only the headline should be linked. Otherwise screen readers, in "read page links" mode are reading two links where only one is needed. So...

<div class="linkbox">
  <h2><a href="#">About Us</a></h2>
  <p>How my life story became a Hallmark movie.</p>
</div>

Also better than the original code, which would have screen readers repeating "read more" for each link box, with no context (also not good for SEO).

CSS Guy said:

@ben:

Thanks for listing those links. The "compact" page has a hover effect on the box, but the entire box isn't clickable, which could easily be manipulated if that were a needed effect.

@Simon:

The linked headline makes sense. Thanks for posting those points.

Sharky said:

Firefox reports that in your example that it has 9 javascript errors. I am using this firefox addon: https://addons.mozilla.org/en-US/firefox/addon/249

CSS Guy said:

@Sharky:

I'm using Firebug, but not seeing any reports of errors. Would you mind telling me what the reported errors are? (I'd rather keep my add-ons to a minimum.)

michael said:

Thanks for the interesting project. I played around with floating the a element as an absolutely positioned div, over the top of the box and using alpha transparent pngs as the hover colors. (spacer gifs anyone?) It works in current browsers but is probably even more hacky than the JavaScript solution you came up with.

Then I thought of making the link display block for the whole area of the div, giving it a top padding and an equal minus margin. That sort of works. I put the headline and text in a definition list. The box changes background color over about 70-80% of the area. By making all the elements links. It fires everywhere but flickers. It's also too fragile for a production environment with too many custom sizings.

If I needed to produce this effect, (hopefully not, I'm not a fan) I think I would prefer your original idea of using spans to style the text and wrap the entire area in the link.

What about declaring the box h2 and p as inline elements in the style sheet? Would that make wrapping the entire thing in the a tag kosher?

JD Graffam said:

@michael: declaring <h2> and <p> as inline within the style sheet would not force it to validate. Validation is just not going happen if you wrap an <a> around any tag that is set to display:block; by default.

michael said:

Thanks JD. I've never tried to declare h2 to display inline then wrap the <a> around the block level element. Just curious.

For me the answer seems to make the <a> display block and set the width and height equal to the enclosing element then attach the hover effect to a pseudo element made of the surrounding block. It should work in maybe 30-40% of the browsers out now and could still be styled to look decent in older ones. A majority of visitors should see the effect within the year as IE 7 rolls out. It might be necessary to add links to all the text to get the whole thing to fire reliably but every presented solution is cludgy.

Christian Watson said:

I came up with an alternative for this technique that uses a list to create the block hover effect (based on Veerle's idea). It works pretty well and doesn't require JavaScript.

Christian Watson said:

I came up with an alternative for this technique that uses a list to create the block hover effect (based on Veerle's idea). It works pretty well and doesn't require JavaScript.

Esteban said:

It is as simple as make the a tag display as a block.

Here is the CSS:

a.boxHover {
    display: block;
    color: #333333;
    text-decoration: none;
    padding: 10px;
    border: 1px solid #660000;
    background-color: #dddddd;
  }
  a:hover.boxHover {
    background-color: #ffcccc;
  }

And here is the markup:

<a class="boxHover" href="#" rel="nofollow">
   <h2>About</h2>
   <p>How my life story became a Hallmark movie.</p>
</a>

It is a little buggy with IE about the hover area, which I think it could have a workaround with more CSS for the inside tags. But it is still semantically good marked up and no JS needed.

Dan Knight said:

Clever. I really like this. Have you come up with a way to do this with 2 or 3 side-by-side boxes as in your graphic?

CSS Guy said:

@Esteban:

It's not that simple. Not if you want to have valid HTML. The <a> tag is currently recognized as an inline element, no matter what you change in the CSS file. Nesting block level elements within inline elements will not validate.

@Dan Knight:

Cliff did.

Michael said:

From a stupid-user perspective, this is annoying. Why? When I right-click on it, I don't get the option to "Open in a New Tab." I do that all the time, opening new tabs as I read a page, then switching to those tabs once I'm done here. This system doesn't allow that. Looks cool, but now I hate you a little bit.

The Block Hover effect posted by Christian Watson doesn't require javascript AND it allows opening in a tab, making it the superior solution, I'd say.

CSS Guy said:

@Michael:

Though I don't hate myself, I agree. I prefer Cliff's example to my own.

Thanks.

Marc P said:

Is the example used in this post a good illustration of structure because I think, semantically speaking, the example should be treated as a menu list. Correct me if I'm wrong: the example looks like a menu list. So shouldn't it be treated more like this:

unorderd list > list item > link > title & description

With this in mind, isn't it still valid to wrap all the contents up into an anchor tag and use span tags? I don't think this is spaninitis; I still think this is valid and spanerific!

It seems to me that it doesn't add contextual value to make links have or contain header value. However, the opposite is valid to me: it makes a lot of sense to add a link inside a header tag. But I wouldn't apply an anchor to both the header *and* the paragraph that might proceed it. I would only add it to the header as a method to get to another document.

mishoo said:

Howz about just:

a.blah {
display: block;
width: somefin;
color: #somefin;
text-decoration: none;
}

a.blah strong {
display: block;
font-weight: bold;
color: #somfin;
}

Simpler the better.

MeTaL_oRgY said:

Here's my attempt at this:
My attempt at CSS Link Boxes

It uses pure CSS and XHTML; it's semantic and works. The problem comes with IE6, for which the hover effect and the whole box-link won't work. Instead, I used a small image (an arrow) to show the link. You can see the example here:
Demo of my CSS Link Boxes

Jermayn Parker said:

I was messing around with this effect trying to get it work without knowing of this website and I did not get it work the way I wanted (just used html and css no javascript), thanks for showing me a way of doing it.

I originally wanted the idea for my blog page were the box with the intro text would change colour when hovered. Seeing I could not get it to work, I used a different effect.

So thanks for this and showing me were I went wrong and right :)

matt said:

what will the effect of using em / strong / span tags have w.r.t. to SEO? I've heard that search engines give a certain priority to h tags, so it'd be nice to keep them rather than styling a "lesser" tags ...

bart said:

Hmmm...I like the effect, but am undecided how this should be implemented with respect to semantics. The purpose is to link to another page. As far as I'm concerned a link consists of inline text (usually title of the destination page) or image or a combination of both.

This technique tries to redefine/extend a link to a more complex structure with a descriptive title (hx) and additional details (p) or a destination resource (dt) and it's definition (dd). Or it could be extended in a microformat style. Take the link (a) and extend it with inline elements like so:
<a>
<strong class="title">Title for the destination page/resource</strong>
<span class="description">This page talks about...</span>
<span class="format">(pdf)</>
<a>

I kind of like the microformat idea. Seems most semantic since (hx) to me feels like it belongs to a page section and not a link.

para ödüllü yarışma said:

As you proposed I use definition lists to achieve the same effect, examples can be seen here:

http://www.ncpta.org.uk/events/100806/100175/ncpta_regional_events/

ER said:

While I prefer either Cliff's or Christian's versions since they use no JS code, I did notice that Cliff's version has issues with the IE-Disappearing Bug. I'm sure it's correctable, but for the out-of-the-box people might consider Christian's example.

I'm about to implement this on a site right now, so thanks to all for the work and continued improvements!

Paul said:

Is there anyway to keep the same block linkbox effect, but have the overall box display as an inline element with text wrapping around the outside?

böcek ilaçlama said:

I liked this css codes but codes must develope a lil bit

 

Post a comment