Worn Text using CSS

October 31, 2007

One of my hobbies is letterpress printing, and I wanted to try to include as many elements of that in my site as possible. The problem popped up when I wanted to have a hand-printed / rough look for some of my text. It would be nearly impossible to create graphical headlines by hand, not to mention time consuming and boring. I could use PHP to make the images for the text, but changing fonts would require editing at least two files, and I really don’t like that idea: too many chances to screw up. Well, two, but you get the idea. Plus, that would leave the text unreadable to spiders, bots, and screen readers, and that’s not an option. I’ll be using this effect on header elements, mostly, and that’s prime Googlebot food.

What I really wanted to do is keep the text in place, either hidden or not, and stick some kinda image over it. Totally replacing the header with an image isn’t a whole lot of fun, and some of those techniques are slightly nefarious. I’ve heard rumors that search engines are going to stop indexing text that’s off screen in the future, so that would suck. I was out of ideas, so I went looking on the internet for my answer. What I eventually settled on was first described back in 2005 on Khmerang.com, and it’s a pretty neat technique. I tweaked it a little to be more general and abstract.

The original code looks like:

XHTML

<h2><span></span>Some Worn Text</h2>

CSS

h2 {
    font:3em/1em Times, serif;
    font-weight: bold;
    margin:0;
    position: relative;
    overflow: hidden;
    float: left;
}
h2 span {
    position: absolute;
    width: 100%;
    height: 5em;
    background: url(wornpattern.gif);
}
p {
    clear: left;
}

My number one beef is that this is all forced into using the h2 tag exclusively. I don’t like exclusivity at all. The first thing I did was to add class="worn" to the h2, and that lets me change the CSS to use the class .worn instead of h2. This also lets me use the worn effect on (nearly) any element I want. How cool.

My number two problem is that the p element has clear: left; on it. You should never put unnecessary styling on elements, lest you need to do something different later on, and have to write weird specific rules to select a few elements. So instead of the p, I changed it to .worn + * { clear: left; }. This means that any element that is the next sibling of the .worn element will be cleared left, and that puts everything back into the normal document flow. That, and it applies to exactly what you need and nothing else. Brilliant!

Also, I’m a little bit of a semantic nutcase, so the extra span required to store the image leaves me with a cold-prickly in my stomach. That’s not happy. There’s two ways to get around this, one of them being a CSS psuedo-selector. That would work like so:

.worn:before {
    content: '<span></span>';
}

This is a proper use of CSS to control the presentation layer of the document, but it’s not fully supported yet so it can’t go in a released product. The other option is to use some javascript to insert the span tags. It works like this (using the Prototype library):

window.onload = function () {
    var elements = document.getElementsByClassName('worn');
    elements.each( function (item) {
        new Insertion.Top(item, '<span></span>');
    });
}

The JavaScript isn’t too resource greedy, and it’s acceptable to me, so that’s what I went with. There’s one more minor problem that pops up while using this technique - the image that gets overlaid on the text is a repeating image, and always starts on the top left of the text. If you’re really perceptive, or incredibly detail oriented you could see the repeating pattern. I did, and I couldn’t stand it. So I made a quick change, changing background: url(wornpattern.gif); to background: url(wornpattern.gif) repeat center top; I can’t tell where the repetition is, so I’m happy with it.