Quick Tip: Nonintrusive CSS Text Gradients
Tutorial Details
- Topic: CSS Text Gradients
- Difficulty: Moderate
- Tutorial Format: Video
Though not completely cross browser compatible, there are ways to nonintrusively create pure CSS text-gradients with a bit of trickery. The key is to use a mix of attribute selectors, webkit-specific properties, and custom HTML attributes.
Final Simple HTML
Hello World
By using custom attributes, we can then hook into these values from within our stylesheet by using the attr() function.
Final CSS
/* Select only h1s that contain a 'data-text' attribute */
h1[data-text] {
position: relative;
color: red;
}
h1[data-text]::after {
content: attr(data-text);
z-index: 2;
color: green;
position: absolute;
left: 0;
-webkit-mask-image: -webkit-gradient(
linear,
left top, left bottom,
from(rgba(0,0,0,1)),
color-stop(40%, rgba(0,0,0,0))
);
Note: Paul referenced an even more succinct method in the comments. Be sure to check that out as well!

thanks for this!!!!
Cool video. But I have to say… this is more a love-letter for VIM than anything else. Holycow… that guy is crazy fast with his VIM.
haha – It’s not me specifically. Once you learn how to use Vim, anyone can be lightning fast.
Good tut. Only thing is the demo looks goofy on the iPad lol
Hehe – probably because I used a massive 200px font size. :)
You have to be careful that your browser window is wide enough. When I first loaded the demo, the actual text was wrapped, and the :after text started on the second line.
Yeah – but that’s not a fault of this technique. It’s just the result of using a crazy massive font size for the demo. :)
The gradient syntax is outdated! =(
http://www.webkit.org/blog/1424/css3-gradients/
-webkit-linear-gradient(rgba(0,0,0,1), rgba(0,0,0,0) 40%)
-moz-linear-gradient(rgba(0,0,0,1), rgba(0,0,0,0) 40%)
Not for mobile browsers that still use older versions of webkit.
Nice follow up, simple idea with a lot of possibilities, You might want to change up the font-size on the demo, it breaks the effect on smaller resolutions when the text breaks to the next line.
When the text jumps to a new line (for instance if the display is too narrow the hi-light jumps down on Chrome. To prevent this you can use…
white-space: nowrap;
Here’s another fun oddity. I was able to fake a 3d effect by dropping the font size of the overlay slightly. It takes some finessing and experimenting with sizes and margins but it could come in handy.
<link href=’http://fonts.googleapis.com/css?family=Luckiest Guy’ rel=’stylesheet’ type=’text/css’>
<style type=”text/css”>
body{
background: #888;
}
/* Select only h1s that contain a ‘data-text’ attribute */
h1[data-text] {
font-family: “Luckiest Guy” ,sans-serif;
position: relative;
color: #569;
font-size: 101px;
text-shadow: -4px 4px 2px rgba(0,0,0,0.2);
white-space: nowrap;
letter-spacing:2px;
}
h1[data-text]::after {
content: attr(data-text);
z-index: 2;
font-size: 96px;
margin: 1px 0 0 2px;
letter-spacing: 5px;
color: white;
position: absolute;
left: 0;
-webkit-mask-image: -webkit-gradient(
linear,
left top, left bottom,
from(rgba(0,0,0,0.2)),
color-stop(43%, rgba(0,0,0,0.1)),
color-stop(43.1%, rgba(0,0,0,0)),
to(rgba(0,0,0,0.4))
);
</style>
while white-space: nowrap; does indeed stop the line jump, it also clips the text if the font-size is large.
What plugin do you use for CSS completion in vim?
good tut
as usual :)
em…pretty funny
Is it me or the text is not selectable either way?
Nice tip anyway.
Ya, the text is not selectable, it cause by h1[data-text]::after cause when u turn off h1[data-text]::after, the text become selectable again.
It actually is selectable, but you have to highlight a bit below the text to “find” it. I think there’s a way around this — but I haven’t figured it out yet.
I dont know why there is no effect in my firefox browser. Just with #666 background and #a6a6a6 the text color.
Webkit only.
webkit – ‘-webkit-’ safari and chrome
moz – ‘-moz-’ firefox
hope this clears up
Great tutorial, again, Jeffery! I always love your tutorials, and they are always so helpful!
Thanks, Josh!
Why dont you add a before element to your CSS, which also calls the content of data-text, and prepend it:
h1::before{
content: attr(data-text);
}
This way you dont ever have to duplicate text. The isn’t selectable, but your version I believe is the same.
Ryan
Sorry if I’m missing something – but what’s the difference in your version compared to mine?
Instead of parsing the same data between the tags, and in the data-text attribute, you just pass it to the data-text attribute. Eg:
Instead of:
Hello World
Jeff – is there a reason you didn’t do something along the lines of
h1 {
background-image: -webkit-gradient(
linear,
left top, left bottom,
from(rgba(0, 0, 0, 1)),
to(rgba(0, 0, 255, 1))
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
};
Essentially what this does is it makes the background of the h1 tag just be the text and when you make the text transparent it shows through.
I do really like the grabbing an attr from ::after. I had no idea you could do that.
-Paul
That’s definitely a cool idea that I haven’t played around with yet. :) Will check it out this weekend.
Okay – so that’s an excellent technique, after playing around with it! The only thing I noticed is that you, of course, can’t then use things like shadows on the text.
But other than that – much cleaner than my method!!
The shadows don’t work like normal but they can create some really fun bevel effects if used properly.
text-shadow: 2px 2px 2px rgba(0,0,0,0.05),-2px -2px 2px rgba(255,255,255,0.05);
One reason to use Jeffrey’s method is because you get an extra background to use. You can set the background on the h1 if needed, which you can’t with the method above (∞) as it’s needed for the gradient itself.
You can get around the no background issue by assigning a background to a pseudo element and giving it a z-index of -1
h1::before {
content: “”;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: red;
z-index: -1;
}
The key is the z-index to put the pseudo element behind the text which mostly replaces the background of the h1. Not exactly the same but I think it covers most situations.
Quick little note on this — if the background declaration comes *after* the -webkit stuff, it won’t work. It must come before.
thanks Jeffrey , very helpful indeed.
Thanks for the ideea. How about using a transparent png gradient for :after ? I think that would work in fireworks too, I have to try this …
Hello Jeff,
i see that webkit-mask-image works only Chrome. About IEE,Firefox,Safari is any solution.
Thanks you
Rzv
It works in Chrome and Safari — or all webkit-based browsers.
Nice VIM setup Jeffry, guess I need to fix mine so it runs better :/
Hello Jeffrey,
i attached the next css:
body{
background:#CCC;
}
h1{
font-size:400px;
color:#green;
position:relative;
font-family:sans-serif;
}
h1::after{
content:”Text”;
color:yellow;
position:absolute;
left:0px;
-webkit-mask-image: -webkit-gradient(linear, right top, right bottom, from(rgba(0,0,0,0)),to(rgba(0,0,0,0)),color-stop(50%,rgba(0,0,0,1)));
-webkit-mask-position: 10 0;
)
}
It works only Chrome, in Firefox,IE,Safari,Opera takes the color 100%:yellow;
Where is the problem with this ?
Thank you ,
RZV
RZV – webkit gradients only work in webkit browsers such as Chrome and Safari. They will not work in Firefox, IE, or Opera. There may be alternative solutions, such as -moz-mask-image but I’m not an expert on that, maybe someone else can chime in.
A quick, semi-hack fix for not being able to select the text is by giving the h1 selector a z-index property of -1, and remove the z-index property from the “h1::after” selector. Don’t ask me why this works.
What’s the use of this ::after.
Hello Jeffrey,
I am looking forward to hearing your solution for css(-webkit-mask-image) i wrote upper.
Thank you ,
Rzv
Thanks for the tip. Very useful to me.
I’m pretty fond of the cross-browser use of the white .png gradient overlay on top of text on top of a white bg. Works beautifully on white bg’s.
Thanks for providing this great tut :)
Nice idea but with only Webkit supported it’s too limited to be more than a nice, little goodie for “progressive” users.
I want to learn css slide show.
This is brilliant. Very clever stuff. I’ve never worked with the before and after selectors. Theres some good home work for me to do over the weekend to get me up to speed. Thanks.
What are you using for auto completion in Vim?
I like it! I’ll use it on my next projket :)
Thank you