Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

So I have a navigation menu that is generated by my CMS:

enter image description here

The menu's HTML is straightforward (edited for clarity):

 <ul>
     <li><a href="...">Journal</a></li>
     <li><a href="...">Art</a></li>
     <li><a href="...">Work</a></li>
   </ul>

I want the items to show up as hand-written text, in keeping with the general theme of the site, using separate PNG files for each menu item.

To do that, I used the CSS content property like so:

#headerNav .nav li a[href="/_site/en/journal/"]  
 { content: url(/path/to/image.png); }

And it worked great! The HTML text of each item was replaced by the correct image:

enter image description here

However, alas, then I learned not every browser supports the content property on selectors other than :before and :after! Chrome and Safari do it, but Firefox doesn. However when I use :before, the HTML node isn't replaced, but the image is added:

enter image description here

How do I work around this?

What didn't work:

  • Making the <a> element display: none removed the :before part as well.
  • Making the <a> element position: absolute and moving it elsewhere won't work either.
  • Making the <a> element width: 0px screws up the layout because the images added through content aren't in the document flow.

What I don't want to do:

  • Of course I can output the images by hand but I want to work with the HTML the CMS is giving me, which is <li>s with text in them.

  • Any solution involving background-image would require me to specify each item's width and height in the style sheet, which I would like to avoid for the purposes of this question.

  • Turning the handwriting into a font is not an option.

  • Using JavaScript to replace the items on the fly is not an option. This needs to work using pure HTML and CSS.

share|improve this question
1  
    
@Blazemonger none of the examples have all green –  mplungjan Jan 17 at 15:33
    
@Blazemonger to use any of them, I'd have to specify a width and height for each item manually in the style sheet, which I'd like to avoid - that's why I used content in the first place. (It's a fair compromise, though, if nothing else comes up, thanks for the reminder.) –  Pekka 웃 Jan 17 at 15:34
    
@mplungjan That page is years old, too. Modern browsers weren't at the time. The last example here was used in HTML5Boilerplate until December 2012. –  Blazemonger Jan 17 at 15:34
    
I don't think there's any way to do CSS image replacement without specifying dimensions, except possibly using :before or :after. –  Blazemonger Jan 17 at 15:35
show 12 more comments

3 Answers 3

up vote 3 down vote accepted

Since you are doing this into a navigation bar you should have a fixed height making the next method possible to work:

  • First insert the image as content on the :before element and make it display:block to push the actual text of the a tag below.

    li a:before {
       content:url(http://design.jchar.com/font/h_1.gif);
       display:block;
    }
    
  • Then hide that text with a fixed height on your a tag:

    li a{
       height:50px;
       overflow:hidden;
    }
    

The Working Demo

share|improve this answer
add comment

Answer was answered before OP added the line

Any solution involving background-image would require me to specify each item's width and height in the style sheet, which I would like to avoid for the purposes of this question.

So if anyone interested in background-image solution can refer this, else can simply skip.


Am not sure how optimum solution I am suggesting is, but surely you can use background-image for each a element, using nth- pseudo, and set the fonts color to transparent, or use text-indent property with overflow: hidden;

So it will be something like

nav ul li {
   display: inline-block;
}

nav ul li:nth-of-type(1) a {
   background-image: url(#);
   display: block;
   width: /* Whatever */ ;
   color: transparent;
   text-indent: -9999px; /* Optional */
   overflow: hidden;
   font-size: 0; /* Optional, some people are really sarcastic for this */

   /* Below properties will be applicable if you are going for sprite methods */
   background-position: /* Depends */ ;
   background-size: /* If required */ ;
}

The reason why I would suggest you is :-

Advantages :

  • Cross browser compatible
  • Can you sprite methods to cut down http requests to request image for each tab
  • Also, you are not losing the text which is between the a tags, which is really good as far as screen readers are concerned.

Disadvantages :

  • Set custom width for each

Note: If you are going for a sprite solution, than background-position is anyways a must property to be used, so be sure you check out the support table first, before opting the sprite method.

enter image description here

Credits - For support table

share|improve this answer
    
I edited, making it clearer why I would like to avoid that. It's a fair way out, though, if no other way comes up. –  Pekka 웃 Jan 17 at 15:36
    
Fair points all, and I didn't think about spriting. I'm going to accept this unless anything else comes up in the next day. –  Pekka 웃 Jan 17 at 15:42
    
@Pekka웃 Sure, take your time, but what you are trying here, is I feel lil cheesy, stick with standard methods... :) –  Mr. Alien Jan 17 at 15:43
1  
I think the method is pretty good for this specific kind of problem - if just it were supported by all browsers... –  Pekka 웃 Jan 17 at 15:45
1  
I will go with this solution too if the need and is possible to manage Sprite Images –  Danko Jan 17 at 16:37
show 2 more comments

I would put PNG images into img tag and then set alt attribute.

<ul>
<li><a href="..." title="Journal"><img src="journal.png" alt="Journal"/></a></li>
<li><a href="..." title="Art"><img src="art.png" alt="Art"/></a></li>
<li><a href="..." title="Work"><img src="work.png" alt="Work"/></a></li>
</ul>
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.