1. Skip to primary content
  2. Skip to secondary content

Sam Rayner

Span-Free Gradient Text Effect

Earlier today, the talented Mr Nick La posted a clever little technique for overlaying a gradient onto text.

CSS Gradient Text Preview

Whilst it isn’t entirely new, Nick’s method uses an empty span to stretch a background image over a heading:

<h1><span></span>Heading Sample</h1>

h1 span { background: url(gradient.png) repeat-x; position: absolute; display: block; width: 100%; height: 30px; }

This works great, even in IE6, but that empty span doesn’t necessarily have to be there.

If you stretch the gradient PNG to be the maximum width of your heading, rather than 1px wide, you can then use an :after pseudo element applied to the heading to achieve the same effect:

<h1>Heading Sample</h1>

h1:after { content: url(stretched-gradient.png); display: block; /* drop beneath text */ margin-top: -1em; /* shift up over text */ }

Granted, this method will not work in IE6 or 7 but it does remove that pesky span from the markup. It’s a trade-off, as always.

If you want to gloss over a linked heading, you’ll just need to make the a block-level with display: block; and apply the :after to that rather than the heading element.

Of course, the same limitations apply as with the original method—the trick is only suitable on solid-colour backgrounds and text will not be selectable if your gradient image is too tall.

Make sure you check out Nick’s demo to see what your fancy text will look like, and download the source files to try out the span-free alternative if you like.

Your Thoughts?

* Required

Options

Some basic HTML allowed. Please keep all comments constructive, polite and on-topic. Any spam or offensive comments will be deleted.

Gravatar Preview

Comments (Post One)

#1 Josh(ua/y)’s Gravatar Josh(ua/y) (1 year, 5 months ago)

I have to say, I think I prefer your method to Nick’s, not only because I you don’t have to add those cumbersome empty span tags but because you don’t have to worry about the IE png hack thingies. The image just won’t be displayed in browsers that can’t display it properly.

#2 Sam Rayner’s Gravatar Sam Rayner (1 year, 5 months ago)

Indeed, that is another benefit of this method, as long as you don’t mind visitors using Internet Explorer just seeing plain old text.

#3 Tobias’s Gravatar Tobias (1 year, 5 months ago)

Nice tip, glad I found my way in to your site...I rather do it with :after than using span in that way, **** IE!

#4 Siegfried’s Gravatar Siegfried (1 year, 5 months ago)

Good idea. I tried something similar. Your idea does not work, nor does mine. With your code the heading text still flows above the gradient png. But to achieve the effect the gradient png must flow above the text. Tested with Firefox.

But indeed to keep semantic markup and avoid presentational markup something with generated content is necessary.

#5 Sam Rayner’s Gravatar Sam Rayner (1 year, 5 months ago)

Hi Siegfried,

I’ve tested the technique in Firefox 2.0.0.11, Opera 9.25 and Safari 3.0.4 on Mac and it works fine in all of them. The gradient certainly flows over the text.

Are you sure you stretched the gradient PNG in an image editing program so that it is wide enough to cover the text? If it’s not that, make sure you’ve included margin-top: -1em; in the CSS.

Hope that helps you get it working.

#6 Siegfried’s Gravatar Siegfried (1 year, 5 months ago)

Hi,

i’ve made up a test page: http://www.rorkvell.de/prj/test/gradient.html

And it does not work. The text is positioned above the gradient png. And width and height styles do not have any effect. Neither do position: absolute nor position: relative. Only display: block works.

#7 Sam Rayner’s Gravatar Sam Rayner (1 year, 5 months ago)

Your test page works perfectly well in the three aforementioned browsers as well as Firefox 2.0.0.11 in Windows.

The only thing I can think of is that you’re having a hard time seeing the effect of the gradient on the text. If you decrease the margin-top further (to something like -1.4em) so that it starts half way up the heading or, better yet, set the background colour of your test page to green, you can clearly see that it is overlaying the text. Alternatively, making the PNG opaque should hide half of the heading completely.

Giving the pseudo-element a height or width will have no effect and it doesn’t matter whether it is positioned relatively or absolutely as long as its z-index is higher, although I recommend removing it from the document flow.

If it’s definitely not working, perhaps it’s down to browser support. What are you viewing it in?

#8 Siegfried’s Gravatar Siegfried (1 year, 5 months ago)

The only difference here is, that i’m using Firefox 2.0.0.11 on Linux, not Windows. And in the past i indeed had some rendering problems with Firefox specific to Linux.

The x and y positions of the text and the gradient png are o.k., but for me it seems as if the z-position is not as intended. Hmmm, i have to experiment more.

#9 Siegfried’s Gravatar Siegfried (1 year, 5 months ago)

I did some more experimenting. Now I moved the gradient bar slightly more up and now it is visible indeed that the gradient png is overflowing the text.

Then i did more experimenting and found this style still working:

h1:after {
content: url("gradient_green_short.png");
display: block;
margin-top: -1.2em;
}

Positioning seems not to work on generated content. By display: block; you’re putting the bar under the heading. By the negative margin-top you then push it up again. Positioning thus is irrelevant for this technique. Just the 3 lines above are enough. And no special styling for the heading itself.

It might be a good idea to use h1:before if you plan to apply the gradient fading to the top of the heading instead to the bottom. Then you still would apply display: block; to the generated content, but then the heading itself, which is pushed down by that generated content, will need a push up by some negative margin-top.

Regards, and thanks for the help
Siegfried

#10 Siegfried’s Gravatar Siegfried (1 year, 5 months ago)

..and a still shorter version (without display: block):

h1:after {
content: url("gradient_green_short.png");
margin-left: -800px;
}

Where 800px is the width of the gradient bar I used.

#11 Sam Rayner’s Gravatar Sam Rayner (1 year, 5 months ago)

Thanks for looking into it further Siegfried, I’ve removed position: absolute; from the code.

Good idea setting a negative margin-left, I hadn’t thought of that. I think I’ll leave the code example as-is for now though so that the same styling can be applied to multiple elements even if the gradient PNGs used on them vary in length.

#12 Mark Abucayon’s Gravatar Mark Abucayon (1 year, 5 months ago)

Wow, thanks for the information you’ve listed that was so nice and helpful. Thank you.

#13 peex’s Gravatar peex (1 year, 3 months ago)

Thanks for the tip :)

#14 Maxwell Scott-Slade’s Gravatar Maxwell Scott-Slade (1 year, 2 months ago)

You could use 8 bit pngs, exported from fireworks. Alpha channels in 8bit pngs are ignored by unsupporting browsers rather than leaving the ugly grey background in place of transparency. I use this method all the time now.

#15 Sam Rayner’s Gravatar Sam Rayner (1 year, 2 months ago)

I hear you Max but one of the nice things about this technique is that browsers that don’t support PNG alpha transparency are also unlikely to support the :after pseudo element. You don’t need to work around any transparency issues because the browser simply won’t overlay anything.

Post a Comment