Web Designer Pro Bundle - $500 of Site Templates, Stock Photos, Code, Graphics and more for only $20
Quick Tip: Nonintrusive CSS Text Gradients
videos

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!

Add Comment

Discussion 50 Comments

  1. Rommel says:

    thanks for this!!!!

  2. Randito says:

    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.

  3. Christophor S. Wilson says:

    Good tut. Only thing is the demo looks goofy on the iPad lol

  4. Michael P. says:

    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.

  5. Webkitz says:

    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%)

  6. Barry says:

    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.

  7. DNABeast says:

    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>

    • Mudassir says:

      while white-space: nowrap; does indeed stop the line jump, it also clips the text if the font-size is large.

  8. NoName says:

    What plugin do you use for CSS completion in vim?
    good tut
    as usual :)

  9. 小豪 says:

    em…pretty funny

  10. Raspo says:

    Is it me or the text is not selectable either way?

    Nice tip anyway.

    • devlim says:

      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.

    • Jeffrey Way says:

      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.

  11. I dont know why there is no effect in my firefox browser. Just with #666 background and #a6a6a6 the text color.

  12. Josh says:

    Great tutorial, again, Jeffery! I always love your tutorials, and they are always so helpful!

  13. Ryan Maughan says:

    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

  14. Paul Grock says:

    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

    • Jeffrey Way says:

      That’s definitely a cool idea that I haven’t played around with yet. :) Will check it out this weekend.

      • Jeffrey Way says:

        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!!

      • DNABeast says:

        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);

    • Chris Coyier says:

      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.

      • Paul Grock says:

        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.

    • Jeffrey Way says:
      Author

      Quick little note on this — if the background declaration comes *after* the -webkit stuff, it won’t work. It must come before.

  15. Sleeman says:

    thanks Jeffrey , very helpful indeed.

  16. 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 …

  17. RZV says:

    Hello Jeff,

    i see that webkit-mask-image works only Chrome. About IEE,Firefox,Safari is any solution.
    Thanks you
    Rzv

  18. dan says:

    Nice VIM setup Jeffry, guess I need to fix mine so it runs better :/

  19. RZV says:

    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

    • M Burke says:

      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.

  20. Tim says:

    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.

  21. Dinesh Verma says:

    What’s the use of this ::after.

  22. RZV says:

    Hello Jeffrey,

    I am looking forward to hearing your solution for css(-webkit-mask-image) i wrote upper.

    Thank you ,
    Rzv

  23. Thanks for the tip. Very useful to me.

  24. w1sh says:

    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.

  25. Alex Devine says:

    Thanks for providing this great tut :)

  26. Chris says:

    Nice idea but with only Webkit supported it’s too limited to be more than a nice, little goodie for “progressive” users.

  27. arafat says:

    I want to learn css slide show.

  28. 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.

  29. What are you using for auto completion in Vim?

  30. I like it! I’ll use it on my next projket :)
    Thank you

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.