My previous solution to this was built on Phark’s “Accessible Image Replacement” technique. It works by pushing the text really far to the left (9,999 pixels) which makes sure it’s there for screen readers but hidden from users (unless someone has a display that’s able to show nearly 10,000 pixels to the left of the container in question). The problem seems to be that some browsers, like the one on the iPad, render a 9,999px box even though it’s not visible. This affects performance, especially for animations.

Well, there’s a better way. It works similarly, but instead of pushing the textual content so far left that we’re sure it’s outside the visible area, we push it just outside the box to the right. The advantage is that even without knowing how long the text is, we know exactly how far to push it to make sure it’s completely out of the box. So if you’re asking “How do I make a background image clickable?” This is the new answer. It’s easy, just follow these steps and I’ll show you how to make a clickable background image like this:

Range Web Development

Start with just a link exactly as you would make it for any other purpose, and make sure to give the link an id so that we can use that to apply our styles:

<a href="http://ran.ge/" title="Professional WordPress Development" id="range-logo">Range Web Development</a>

That’s all the (X)HTML you’ll need to make your background image clickable. Your link should look something like this:

So, how can we make a background image a clickable link? It turns out it can be done with a clever CSS trick. Let’s get started by adding the background image and make the link the same size as the image (so you can see the whole image). Since an anchor tag isn’t a block level element, we need to force it to display as “block” so that we can specify the size:

#range-logo {
	background-image:url(http://ran.ge/content/uploads/2009/11/logo-trimmed.png);
	display:block;
	height:100px;
	width:460px;
}

At this point it should look something like this: Range Web Development

Now all we need to do is hide the text. This can be done using “text-indent” to indent the text just outside the containing box, using “white-space” set to nowrap to keep the text from wrapping back into the box, and using “overflow” to hide content outside the box like this:

#range-logo {
	background-image:url(http://ran.ge/content/uploads/2009/11/logo-trimmed.png);
	display:block;
	height:100px;
	overflow:hidden;
	text-indent:100%;
	white-space:nowrap;
	width:460px;
}

And the finished product looks like this: Range Web Development

And there you have it – a quick CSS trick with clean markup that turns your background images into clickable links. The best thing is, these don’t adversely affect your SEO and can even be easily used inside of header tags if needed!

Update:
I was asked how to add a border. Here it is with a CSS border:

#range-logo {
	background-image:url(http://ran.ge/content/uploads/2009/11/logo-trimmed.png);
	border:1px solid #CCC;
	display:block;
	height:100px;
	overflow:hidden;
	text-indent:100%;
	white-space:nowrap;
	width:460px;
}

Range Web Development

That obviously works, but the border is too close for my liking and adding padding causes our image to be out of place. Here’s the solution:

#range-logo {
	background-image:url(http://ran.ge/content/uploads/2009/11/logo-trimmed.png);
	background-position:5px 5px;
	background-repeat:no-repeat;
	border:1px solid #CCC;
	display:block;
	height:100px;/*110px if using border-box*/
	overflow:hidden;
	padding:5px; /*Not if using border-box*/
	text-indent:100%;
	white-space:nowrap;
	width:460px;/*470px if using border-box*/
}

Basically we’re adding 5 pixels of padding all around, re-positioning the background image to 5px in from the top and left, then setting the background image to not repeat. Now our border looks nice:
Range Web Development

As a quick note, if you’re using “box-sizing: border-box;” you’ll need to adjust the width and height in the CSS to be the width/height of the image plus the padding, so in this case 470px × 110px.

71 thoughts on “CSS Trick: Turning a background image into a clickable link – Take 2

  1. Pingback: » CSS Trick: Turning a background image into a clickable link » BlueDog

  2. I have been trying to make the image have a css border as well, although the border always ends up around the text off to the side.

  3. I have a issue on how to make the top image clickable …. any thoughts? Also maybe you can help with a solution to an additional issue. I have the bottom image set to no-repeat, yet it still repeats on x… and thoughts?

    .footerzig{background: url(“http://www.iselaespanadesignstudio.com/wp-content/themes/twentytenchild/images/zigzagf.png’”), repeat-x scroll 0 0 transparent;
    clear: both;
    height: 154px;
    }
    .footerzigover{background: url(“http://www.iselaespanadesignstudio.com/wp-content/themes/twentytenchild/images/idea.png’”), no-repeat scroll 0 0 transparent;
    clear: both;
    height: 154px;

    }

  4. I have a issue on how to make the top image clickable …. any thoughts? Also maybe you can help with a solution to an additional issue. I have the bottom image set to no-repeat, yet it still repeats on x… and thoughts?

    .footerzig{background: url(“http://www.iselaespanadesignstudio.com/wp-content/themes/twentytenchild/images/zigzagf.png’”), repeat-x scroll 0 0 transparent;
    clear: both;
    height: 154px;
    }
    .footerzigover{background: url(“http://www.iselaespanadesignstudio.com/wp-content/themes/twentytenchild/images/idea.png’”), no-repeat scroll 0 0 transparent;
    clear: both;
    height: 154px;

    }

  5. Thank you for the great css trick! The only thing that makes the text appear again, is searching for it (ctrl+f). But i think no one would do that…

  6. Great trick Aaron! It did the job fine on my drupal site in Firefox.
    In all the other browsers the link kept showing at the right end of the backgroundpicture.

    Nevertheless, thanks so much for sharing!

  7. Hey Aaron,
    Thanks for the code.

    I got a small problem here.
    My idea is to have this:
    BODY
    IMAGE (Clickable)
    WRAPPER (margin: 0 auto)
    Page Contents…

    But my background image link is not working.
    I guess its because of the #wrapper code with “margin: 0 auto” which comes immediately below it.
    z-index changes aint working either.
    Any ideas? This thing is getting on my nerves.
    Thanks in advance… :)

  8. Great solution, thank you!

    If you want to get this to work also in IE6 and IE7, the background image style should not (only) be applied to the a tag, but (also) to a surrounding div container.

  9. This is very nice. I have a question: is it possible to add a _blank “target” in the CSS so that the new page opens in a new window? :)

    • There are CSS properties in the proposed CSS3 spec that are supposed to do this:

      .external-link {
      	target-name: new;
      	target-new: window;
      }

      However, as far as I know this isn’t supported by any browsers yet.

      You can add target=”_blank” to the HTML or add some JavaScript to handle it.

  10. Great trick. I’m trying to use this to have 5 icons in a row but I can’t seem to control their placement. I want to be able to center them in a div, but can’t figure out how.

    Sincerely,
    A css-learner

  11. I prise the Lord for You and Google – thank you Aaron. After a whole day to figure out the problem, you safe me. I have only to use a class instead of an ID in my case and it works wonderful in IE FF and Chrome.

    Best regards
    Marcus

  12. Hi Aaron

    Sorry if this is low level stuff but Ive just created an Image and used Css to display it. No HTML yet.

    }
    #body .header ul{
    background: url(“images/get in touch.jpg”) no-repeat 790px 0px;
    }

    the href in the html is

    href=”contact.html”>

    All id like to do is make the image clickable to this ref.

    Any easy way of adding to the css ?

    Any feedback appreciated
    Bryan

    • First, those CSS rules wouldn’t work without HTML. Specifically you need a ul inside an element with the class header inside an element with the ID body.

      Second, semantically it makes sense to use a link to link something.

      Lastly, you can’t do that with just CSS. You’ll need HTML or JavaScript to link the element that has the images as the background.

      • Thanks for response got around by doing
        this:

        	<div style="position:absolute; top:145px; left:1030px">
                  <a href="contact.html" rel="nofollow"><img border="0" src="images/get in touch.jpg"></a>
        	  </div>

        Was wondering if you knew what was missing from this search code. I desperately want a basic site search field on my site but have had no luck so far. Any feedback would be really appreciated. And once again sorry if its low level stuff but Im literally a nube and teaching myself but this codes got me stumped.

        }

        Go

        }

  13. Instead of using the “text-indent” and “overflow” CSS to hide my text I just did not include any text in my link:

    <a href="home.html" rel="nofollow"></a>

    The image is still clickable and no extraneous text!

    Only tested on IE 8. Maybe I missed the point of the text in the first place? But figured I would share anyways.

    • Forgot to say Thank You! for posting this in the first place. It helped me out a lot.
      Also, I guess I can’t post html in the comment box. I will try again:

      [/lang]

      Simply showing the lack of text within the link.

    • The reason for the text is so that screen readers (and search engines) have text to process so they know what the link is about. Imagine being blind, having the site read to you, and having no text at all for the link in question.

        • Hi, Brett
          Yes, it’s the absolute positioning — it throws off the use of % in test-indent. If you duplicate your width info here, it works again. E.g.:
          width: 364px; text-indent: 364px;
          HTH, Rupert

  14. Hi Aaron, I much appreciated effort of putting up info on a web.

    Any possible thoughts for 4 level dropdown menu based on graphic buttons? Your tip haven’t resolved issue.

    Many thanks in advance for any possibility thoughts.

    Michal.

    • I think I found a possible solution:   Sometimes just needs to talk to yourself and the solutions appears as the answer of UNIVERSE :-) Thank you for inspiration.

  15. I so wish I’d have found your site earlier, love the way you build the code incrementally and add the highlights, so easy to follow. Thanks for posting.

  16. Thanks for the tutorial! It worked like a charm.

    Made one adjustment, as I’m working within several layers of wrappers. In order to correct my positioning, I added the following before the background-image line.
    margin-top:-10px;
    margin-left:10px;

  17. Thank you so much! I was almost losing hope that there is a solution for this problem but yours is working perfectly! Plus a good explanation!

  18. Wouldn’t it be simpler to use the div style=”visibility:hidden” tag for the text instead of shoving it around the screen? Or am I missing something?

  19. i have my backgroundimage of orbit and its planets,how can i made those planet to act as a link…though it is in circular way

  20. This is offering some great ideas for a related issue I have, but I have a suggestion regarding hiding the link text.

    Instead of moving the text way off to the side, or at all, why not just set the font size to 0px? I tested it with firebug on this very page, on the step where you show the text still visible over the image. It disappears just fine, and the link still works.

    • People can set a minimum font size in their browser which will override your 0px setting. In FireFox, go to preferences -> Content -> Advanced and you’ll see that you can change the “Minimum font size”.

  21. I need to apply this to my particular code in WP. The categories show in a widget with the category name above the thumb image for the featured article of that category, followed by an excerpt below that. I don’t need to vanish the text, but do need to have a different bg image for each category listed, as there are three of these categories across the page from left to right. Idk now to specify the css to do that. The code looks like this for each category box:

    Category 21 Name

    and changes only for the data-catid and actual name.

    How do I target just this link for this category so it will have a unique bg image? I know it has to be for the container of the link, which appears to be just the h3. Below this span4 is a ul listing more articles in that category, and nothing else. Any ideas?

    • Sorry, idk how to mark the code so it own digest like that. Lets try leaving off the first
      h3 class=”category-title color-none”>
      a class=”tab_title active” data-catid=”21″ href=”http://www.domainNameHere.com/category/earthstar-traveler/”>EarthStar Traveler
      /h3>

      • Almost. Here’s the html minus the opening angle brackets:

        div class=”span4″>
        h3 class=”category-title color-none”>
        a class=”tab_title active” data-catid=”21″ href=”http://www.domainNameHere.com/category/category-21-name/”>Category 12 Name
        /h3>

  22. Pingback: Dudes, I am That Fucking Good | tess mackenzie

  23. This might be a long shot but I’m hoping you can help me! I’m trying to implement your technique with a full screen background image… but no luck. Can you peek at my code and tell me if/how it can be done?

    HTML:

    CSS:
    html, body {
    overflow: hidden;
    height: 100%;
    width: 100%;
    padding: 0;
    margin: 0;
    }

    #full-screen-background-image {
    z-index: -999;
    min-height: 100%;
    min-width: 1024px;
    width: 100%;
    height: auto;
    position: fixed;
    top: 0;
    left: 0;
    }

    Thanks in advance if you can offer any solutions! I’ve been working on this for 2 days now, trying various things I’m finding online, but nothing has worked yet.

    Sherry

    • Hey Sherry, this isn’t really the right technique for a full-page background image. Most of those use javascript to listen for clicks on the body that originated outsize the content area, and CSS only for adding the background image to the body or html tag.

  24. hi Aaron

    So i am trying to get the clickable background image to have 4 separate links.

    HdrUserControl.acsx provides the id’s

    And then the Master.css is as follows

    div div#headerContainer
    {
    position: relative;
    padding: 10px 0 15px;
    }

    #headerContainer img
    {
    display: block;
    width: 320px;
    margin-bottom: 28px;
    }

    .headerLinks
    {
    position: absolute;
    right: 0;
    bottom: 15px;

    }

    .headerLinks ul { float: right; }

    .headerLinks li
    {
    float: left;
    margin: 0;
    padding: 38px 15px 0;
    font-size: 12px;
    background: url(../Images/master02.jpg) no-repeat -689px 0;
    }

    .headerLinks li.headerLinksPrint { background: url(../Images/master02.jpg) no-repeat -800px 0; }
    .headerLinks li.headerLinksEnquiry { background: url(../Images/master02.jpg) no-repeat -927px 0; }
    .headerLinks li.headerLinksContact { background: url(../Images/master02.jpg) no-repeat -1030px 0; }

    Am not sure how to add the ids to the image sections that are already defined?

    thanks
    Mark

    • Unfortunately, what you need is going to be pretty different from what this tutorial does. Look at breaking the image up or possible putting it on a container and then layering the links over the top (still using the text-indent to hide the text from the links)

  25. I’ve found another solution to this problem. replace ] with >
    This will hide the text, from users but still leave it for screen readers, while replacing the block with an image. I used an animated gif sprite. It flashes on hover. Pretty nifty if I say so myself.
    The image is 2 blocks high and has 2 frames. In the first frame of the animation I have 2 buttons, one on top of another both exactly the same. In the second frame, I have the same thing but the bottom button is slightly brighter. When you hover over the button it appears to flash. When the button is in its normal state, it’s still animated but doesn’t appear to be since the top half of both frames are the same. In essence I have 3 buttons exactly the same (top-left, bottom-left, top-right) while the last one (bottom-right) is different.

    Here’s the code.

    HTML:
    [a class="button" id="listen" title="Listen" href="javascript:void()" target="_self" style="text-decoration: none"][span id="center" title="Listen"]Listen[/span][/a]

    CSS:
    #center { text-align: center; margin: auto; }
    /*– Hide the link text –*/
    .button span
    { display: none; }

    .button
    {
    text-align: center;
    display: block;
    width: 117px;
    height: 30px;
    background-position: 0 0;
    background-repeat:no-repeat;
    }
    /*– Button Hover –*/
    .button#listen:hover { background-position: 0 -30; }

    /*– Button Image –*/
    .button#listen { background-image:url(‘../images/buttons/Grunge_css_listen.gif’); }

Leave a Reply

Your email address will not be published. Required fields are marked *