Grow your CSS skills. Land your dream job.

Text Fade Out / Read More Link

Published by Chris Coyier

Reader Rob Young sent in a cool effect seen on Newsweek.com:

The text fades out at the bottom and has a "More..." link. Text fade out is nothing new around here. I've had a demo up for that for ages, which uses a transparent PNG file placed overtop the text. But since this is a slightly different idea and the times-are-a-changin' and we can get a bit more progressive with this idea.

Let's assume these small boxes of text are used in a sidebar, so our HTML markup will be a div with class of sidebar-box. This div can contain any number of paragraph elements, the last of which will have a class name of read-more which contains a link button.

<div class="sidebar-box">
	<p>malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
	<p class="read-more"><a href="#" class="button">Read More</a></p>
</div>

The box will be limited in height by the appropriate property max-height with it's overflow set to hidden. We'll also use relative positioning as we will need that to use absolute positioning on the read-more paragraph, which is locked to the bottom of the box and uses CSS3 gradients to achieve the text fade out.

.sidebar-box {
	max-height: 120px;
	position: relative;
	overflow: hidden;
}
.sidebar-box .read-more { 
	position: absolute; 
	bottom: 0; left: 0;
	width: 100%; 
	text-align: center; 
	margin: 0; padding: 30px 0; 
	
	/* "transparent" only works here because == rgba(0,0,0,0) */ 
	background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, transparent),color-stop(1, black));
        background-image: -webkit-linear-gradient(top, transparent, black);
        background-image: -moz-linear-gradient(top, transparent, black);
        background-image: -ms-linear-gradient(top, transparent, black);
        background-image: -o-linear-gradient(top, transparent, black);
}

Which gives us:

The "Reveal" with jQuery

The simplest way to make this work would be to remove the max-height CSS from the sidebar box on a click. That would let it instantly expand down to the natural height of all contained paragraphs. Theoretically you could do this with CSS3 and :target, but that's temporary and would cause page jump-downs. We can make it more elegant by using JavaScript and the easy animations of jQuery.

var $el, $ps, $up, totalHeight;

$(".sidebar-box .button").click(function() {
			
	totalHeight = 0

	$el = $(this);
	$p  = $el.parent();
	$up = $p.parent();
	$ps = $up.find("p:not('.read-more')");
	
	// measure how tall inside should be by adding together heights of all inside paragraphs (except read-more paragraph)
	$ps.each(function() {
		totalHeight += $(this).outerHeight();
	});
				
	$up
		.css({
			// Set height to prevent instant jumpdown when max height is removed
			"height": $up.height(),
			"max-height": 9999
		})
		.animate({
			"height": totalHeight
		});
	
	// fade out read-more
	$p.fadeOut();
	
	// prevent jump-down
	return false;
		
});

So in Plain English, when a button is clicked inside of a sidebar-box, find all the related players involved (parent elements and such), measure a new ideal height, animate to that new height, and remove the button.

View Demo   Download Files

Quick note about Transparency & Gradients

I had some head-scratchers going on trying to figure out a weird problem using CSS3 gradients and fading from "transparent" to a regular hex color. It seemed like the color was multiplying onto the background. What is actually happening is that the word "transparent" is actually just mapped to "rgba(0,0,0,0)" which means "fully transparent black." So when the gradient is built, the intermediary colors are mixed with not-quite-totally transparent black. To fix this, you'll need to use RGBa colors in both the start and fade to color, even if it's fully transparent. For example, for red to fade from red to transparent:

background-image: -webkit-gradient(
  linear,
  left top,
  left bottom,
  color-stop(0, rgba(255,0,0,0)),
  color-stop(1, rgba(255,0,0,100)));

And don't forget all the other gradient syntaxes. CSS3 Please! is a great resource for getting quick up-to-date CSS3 syntaxes.

Thanks to @foodgoesinmouth, @sebnitu, @maddesigns and others...

Comments

  1. Theoretically, can’t :target and -webkit-transition be used to achieve the same effect as the one achieved with jQuery?

    Are there any hurdles if the above proposed method is used?

    (By the way, good post Chris)

    • My issue with :target is that is causes jump-downs as you need to use hash-tag links. There are things you can do to make it less jarring, but I feel like its still not ideal. I almost wish there was .preventDefault() possible through CSS alone =)

      However, maybe you could just use like onclick="return false;" on the links and do the rest with pure CSS3…

    • You know, in this case, you could just use pointer-events:none; and you would not need .preventDefault() or onclick=""return false;".

      But then that would not be cross-browser compatible but hey, CSS Gradients aren’t too (yet). So that would fit nicely into the role of .preventDefault() in this case.

      I’m using ‘in this case’ often because pointer-events:none; would only stop the default action on pointer events (like hovering, clicking etc.) . But then it does the required job of .preventDefault in this case.

      Is using pointer-events:none; instead of .preventDefault() going to get (almost) the same result as is shown in the post?

    • pointer-events isn’t going to work because then you can’t click on the button at all, and thus the hash-tag will never change in the URL, and then you can’t use :target.

    • So it’s just doing what the browser does on it’s own in a more aesthetically pleasing way.

  2. Permalink to comment#

    Is this like what you had on the initial release of your previous design of this site, before people revolted, with pitchforks? I never did see it before the mob drove it out of the city. I like it.

  3. Heidi
    Permalink to comment#

    As always you have the best information and I need to know: do you sleep? :)

  4. Unknown
    Permalink to comment#

    What’s the logic?

  5. Some times you kill me Chris :)

    Your knowledge of CSS is always impressive. I do wish there was a 2nd opinion side column that addresses the practicality and usability of any given CSS Trick by someone in the business of usability.

    In fact. I’d be interested in talking about it with you…

    • I think it would be a pretty cool (guest =)) blog post. Take some number of little mini UI examples (out of context) and determine if they are:

      • Bad UX almost no matter what
      • Possibly bad UX depending on context
      • Good UX

      … or some variation of that.

    • You’ve got my email address, shoot me an email to discuss.

  6. As usual… Very nice effect! And I love the new layout of your website :)

  7. Keyamoon
    Permalink to comment#

    Nice effect. I’d rather use the opacity property on the last two lines or so. Gradients wouldn’t work if your background doesn’t have a plain color.

  8. Permalink to comment#

    Problem with this is that if there is a non-solid color background behind the text, the gradient won’t be smooth, however, if you use css mask-image, it is a more flexible solution.

  9. this was a really quality article. In theory I’d like to write like this also – taking time and real effort to make a interesting article… but what can I say… I procrastinate a lot and never seem to get it done

  10. ali
    Permalink to comment#

    Interesting code nesting & formating in jQuery.

  11. Ty
    Permalink to comment#

    Call me stupid but theoretically couldn’t you just use a transparent PNG and fix it to the bottom to achieve somewhat the same effect?

    • That’s not stupid, that’s fine. That just requires an image which is an extra request and harder to update. The idea here was to get a little progressive if we could.

  12. Permalink to comment#

    I bookmarked your site to get more updates. Nice blog design too!

    I really thankful to author for sharing Good information

  13. Nifty effect in FF and Chrome. Not so much in Opera.

  14. Permalink to comment#

    nice effect but really , is this good typographic use?

  15. Permalink to comment#

    Thanks for sharing, very nice as usual

  16. Permalink to comment#

    With your JavaScript, I’d declare the variables (“var $el, $ps, $up, totalHeight;”) inside the click function, so they don’t pollute the global namespace. They’re not needed outside the click event anyways :)

  17. Permalink to comment#

    I have something like that on one of my sites, but it doesn’t have the fade. I think the fade improves usability since it hints there’s more to it.

    Thanks!

  18. Nice visual, thanks for sharing Chris!

  19. Very cool, Chris.

  20. Permalink to comment#

    why don’t you embedding the “read more” inside a gradient-transparent png ?

  21. Permalink to comment#

    Thanks for the post…why dont you use a png with the embeded gradient in it. This would seem like the easiest solution in my view

  22. Thanks for sharing great post. I want to know, will this work in all browsers without using jquery option?

  23. Can we change background color?
    and where?

  24. Hello! How to change direction to fade text from the right side?

  25. John
    Permalink to comment#

    Hi, great blog.

    I only want two boxes and am struggling to center them in the page. Anyone know how to do this?

    Also, is it possible to make this responsive?

    Thanks,

    John

  26. Very cool. It’d be nice if we could toggle the reveal to hide the content again!

  27. Osvaldo Hernán
    Permalink to comment#

    It’s possible to add de button “read less”, to close the text?

    • Joseph Nichols
      Permalink to comment#

      I was wondering the same thing, Osvaldo. Here’s a solution I came up with. This shows the original block of code with a click event added that reverts to original state if you click the paragraph.
      $up
      .css({
      // Set height to prevent instant jumpdown when max height is removed
      "height": $up.height(),
      "max-height": 9999
      })
      .animate({
      "height": totalHeight
      })
      .click(function() {
      //After expanding, click paragraph to revert to original state
      $p.fadeIn();
      $up.animate({
      "height": 120
      });
      });

    • Osvaldo Hernán
      Permalink to comment#

      Very good! I was looking for this.
      Thanks.
      Another question: Its possible to use a white background?

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".