108

I am trying to create a text fade-out effect when the amount of text is bigger than the row can handle. I am achieving this with the mixture of max-height, overflow and linear-gradient. Something like this.

max-height:200px;
overflow:hidden;
text-overflow: ellipsis;
background: -webkit-linear-gradient(#000, #fff);

The full fiddle is available. I am trying to achieve effect similar to this one enter image description here

and I am kind of close. The problem is that in my case text start to fade-out from the very beginning and I want it to start fading out only if it is really close to maximum size. Lets say start fading out if it is already 150px. Also I am using only -webkit prefix and I assume that there may be other prefixes that I can add for other rendering engines.

Is there a way to do this in pure CSS?

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • 1
    Detecting when the overflow happens in CSS is something impossible unless we have to use some layout trick in combination with CSS. If you mean the overflow is considered to happen if the height reaches about 150px, then the text should be faded out, here is the solution for you, this uses a gradient layer on top of the text and it works for all browsers supporting linear-gradient, so I think it's better than your solution using `-webkit-background-clip:text` which is supported only by webkit-based browsers (I think): http://jsfiddle.net/b9vtW/1/ – King King Apr 02 '14 at 10:26
  • I've made a few pens similar to the request: [pen 1](https://codepen.io/vsync/pen/poegrqa) & [pen 2](https://codepen.io/vsync/pen/mdEgxwX) – vsync May 12 '21 at 18:29

12 Answers12

138

Looks like your requirement is just to fade out the text beginning at a certain height (about 150px), the text (if any) presenting at that height is considered as overflow. So you can try using some kind of transparent linear gradient layer placed on top of the text area, we can achieve this in a neat way using the pseudo-element :before like this:

.row:before {
  content:'';
  width:100%;
  height:100%;    
  position:absolute;
  left:0;
  top:0;
  background:linear-gradient(transparent 150px, white);
}

Fiddle

King King
  • 61,710
  • 16
  • 105
  • 130
  • 34
    Very nice. I also had to set `position:relative` on the `.row`. One issue though was that the overlaid pseudo-element made it impossible to click on links inside the original element. To fix this I added `pointer-events: none` to the pseudo-element's styling. – joeytwiddle Oct 27 '15 at 07:39
  • @joeytwiddle - thanks for `pointer-events` tip. As a side note, `pointer-events` and `linear-gradients` are supported in IE9+ and `:before` is supported in IE8+, so IE8 users will get the psuedo-element but won't see the gradient and won't be able to click anything below it. Detecting IE8 and removing the psuedo-element could be advisable. – TheCarver Jul 09 '16 at 00:31
  • 7
    If you're wondering why this isn't working on iOS Safari, that's because `transparent` isn't allowed there. Use `rgba(255,255,255,0)` instead, per this SO post: https://stackoverflow.com/questions/16816648/css-gradient-not-working-on-ios – Mark Bao Jul 14 '16 at 18:47
  • 1
    Just wanted to point out a few things: opacity in rgba values (the last value)are from `0 - 1.0` incase you don't want it to fade out completely, and if you want links such as a more link below the text, then you could use the above styling for say, a `p` tag instead of the `.row` – user3791372 Aug 12 '16 at 15:31
  • 1
    This text-overflow: ellipsis; content: ""; Not useful in your class row – Matohawk Oct 08 '17 at 22:11
  • @Matohawk yes, you're right, I did not test that and somehow by chance keeping the 'content' attribute which is usable only on pseudo-elements. Anyway that additional part is irrelevant for the problem asked here. – King King Oct 09 '17 at 01:43
57

I used this method derived from reddit pages & it works fine

.fade {
    -webkit-mask-image: linear-gradient(180deg, #000 60%, transparent);
  }
<div>
    <div class="fade">
    Text text text text<br />
    Text text text text<br />
    Text text text text<br />
    Text text text text<br />
    Text text text text<br />
    Text text text text<br />
    Text text text text<br />
    Text text text text<br />
    Text text text text<br />
    Text text text text<br />
    </div>
</div>
doinghun
  • 591
  • 4
  • 3
  • 4
    Perfect. Super simple. Works on a single div with lots of wrapped text, or single lines as you demonstrate. I guess to be picky, it shows the fade whether the text overflows or not. Changing 60% to 95% seemed to mitigate that a lot. No need for pointer-events: none;. – www-0av-Com Mar 14 '21 at 21:07
  • How do i make it so that this doesn't happen when the element is at scroll bottom? – rolling_codes Sep 09 '22 at 14:00
  • 1
    The official directive is called `mask-image` and the prefix is no longer required. – jnns Mar 09 '23 at 12:04
  • @jnns that doesn't seem to be the case with latest Edge Chromium "unknown property name" – cederlof Aug 31 '23 at 13:14
19

I’d suggest something like this:

Apply the gradient to an absolutely positioned pseudo-element (:after), that get’s positioned at say 160px from top with 40px height – that way, it’ll not be shown at all in shorter boxes (because of their max-height in combination with overflow:hidden). And the gradient itself is from totally transparent (rgba(0,0,0,0)) to solid black.

.row{
    position:relative;
    /* … */
}
.row:after {
    content:"";
    position:absolute;
    top:160px;
    left:0;
    height:40px;
    width:100%;
    background: linear-gradient(rgba(0,0,0,0), #000);
}

http://jsfiddle.net/b9vtW/2/

CBroe
  • 91,630
  • 14
  • 92
  • 150
  • Nice, but if you use `bottom:0;` instead of `top:160px;` then it will be more universal. Gradient will only occupy bottom of the parent element with `height` being height of the gradient. – Nux Jul 18 '17 at 15:44
  • @nux using bottom instead of top won't work as expected if the element has max-height and no height. If you use bottom:0, gradient will be applied even if text only occupies one line when it should just have the gradient on the last line (could 3rd, 4th, etc) – jbdeguzman Mar 06 '18 at 01:57
5

Your code is correct just the liner gradient percent must be set

background: -webkit-linear-gradient(top,#000 70%, #fff);

Try the fiddle link

http://jsfiddle.net/ShinyMetilda/kb4fL/1/

You could alse specfiy it in pixel like this

 background: -webkit-linear-gradient(top,#000 140px, #fff);

Both works the same

ShinyJos
  • 1,487
  • 11
  • 17
5

I think your are looking for something like this, right?

http://jsfiddle.net/QPFkH/

.text {
    position:relative;
    width:200px;
    max-height:10em;
    overflow:hidden;
}
.shadow {
    position:absolute;
    top:8em;
    width:100%;
    height:2em;
    background: -webkit-linear-gradient(transparent, white);
    background: -o-linear-gradient(transparent, white);
    background: -moz-linear-gradient(transparent, white);
    background: linear-gradient(transparent, white);
}
Ripaz
  • 100
  • 5
5

The right one guys

-webkit-mask-image: linear-gradient(180deg, #000 60%, transparent);

Just make the Hight Fixed and apply this, it´s going to work just fine.

4

If you don't need to rely on percentage values, use box-shadow instead of background-image. It makes it possible to let the user interact with the elements behind your fading-thingy, without the need of pointer-events: none (http://caniuse.com/#feat=pointer-events):

box-shadow: 0 0 2em 1em #f00;
height: 0;

But be warned, box-shadow can slow down scrolling:

yckart
  • 32,460
  • 9
  • 122
  • 129
2

I recomend you to use http://www.colorzilla.com/gradient-editor/.

What you are looking for may be:

background: -moz-linear-gradient(top,  rgba(255,255,255,0) 0%, rgba(255,255,255,0) 80%, rgba(0,0,0,1) 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0)), color-stop(80%,rgba(255,255,255,0)), color-stop(100%,rgba(0,0,0,1))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top,  rgba(255,255,255,0) 0%,rgba(255,255,255,0) 80%,rgba(0,0,0,1) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top,  rgba(255,255,255,0) 0%,rgba(255,255,255,0) 80%,rgba(0,0,0,1) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top,  rgba(255,255,255,0) 0%,rgba(255,255,255,0) 80%,rgba(0,0,0,1) 100%); /* IE10+ */
background: linear-gradient(to bottom,  rgba(255,255,255,0) 0%,rgba(255,255,255,0) 80%,rgba(0,0,0,1) 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#000000',GradientType=0 ); /* IE6-9 */

and if not workign as you wish, copy and paste those css in the url (css window) and modifie it at will.

Alvaro Menéndez
  • 8,766
  • 3
  • 37
  • 57
  • The problem is that I need to specify starting point in pixels, not percentage. with percentage if the text is too small it still fades-out. And apparently syntax of commands, you suggested does not allow this. – Salvador Dali Apr 02 '14 at 10:44
  • well. you may use insteed this solution who may work on all browsers (unless pseudo-element after):http://jsfiddle.net/b9vtW/3/.. just add an absolut positioned div with the height you wish inside your wrap align to bottom with the gradiant as backgroud. easy and safe – Alvaro Menéndez Apr 02 '14 at 11:02
2

I had a similar problem with a bootstrap button which has a vertical gradient and also change of gradient on hover. This worked for me.

<button class="btn btn-success" style="width:250px">
      <div class="faderflow">
         SOME TEXT THAT'S TOO LONG FOR THE BUTTON
      </div>
</button>



.faderflow {
    overflow: hidden;

   /* same color as text (white) */
    background: linear-gradient(to right, rgb(255, 255, 255) 80%,rgba(255, 255, 255, 0) 100%);
    background-clip: border-box;
    -webkit-background-clip: text;
    -webkit-text-fill-color: #fff0;

   /* overwrite the bootstrap text shadow  */
    text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.2);
}

https://codepen.io/andyg2/pen/qGmKKN

Andy Gee
  • 3,149
  • 2
  • 29
  • 44
  • Thanks for this answer, it's indeed the correct way when you have image/gradient on the background. The only problem is when you have text in multiple colors... – Adrian Sep 16 '19 at 18:56
  • 2
    got better approach - `mask-image: linear-gradient(to bottom, white, transparent);` – Adrian Sep 16 '19 at 19:05
1

My variant with a gradient appearing with overflowing

.row {
  width: 300px;
  max-height: 200px;
  position: relative;
  display: flex;
  flex-flow: column-reverse wrap;
  overflow: hidden;
}

.content {
  max-height: 100%;
  overflow: hidden;
}

.background {
  width: 100%;
  height: 1px;
  position: relative;
}

.background:before {
  content: '';
  display: block;
  width: 100%;
  height: 150px;
  left: -100%;
  bottom: 0;
  position: absolute;
  background: linear-gradient(transparent, white);
  pointer-events: none
}
<div class="row">
  <div class="content">content</div>
  <div class="background"></div>
</div>

JSFiddle

Behemoth
  • 5,389
  • 4
  • 16
  • 40
0

I used this method to make the bottom transparent.

http://jsfiddle.net/IAMCHIEF/x7qLon18/4/

.row{
    position:relative;
    width: 300px;
    margin-bottom: 5px;
    padding-bottom: 5px;
    border-bottom: 3px solid #777;
    max-height:200px;
    overflow:hidden;
    color:#fff;
    background:#000;
}
.row:after {
  content: "";
position: absolute;
top: 137px;
left: 0;
height: 40px;
width: 100%;
background: -webkit-linear-gradient(rgba(255, 255,255, .4), rgba(255, 255, 255, 1));
}
<div class="row">
 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
<div class="row">
 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
<div class="row">
 Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
</div>
Arun Prasad E S
  • 9,489
  • 8
  • 74
  • 87
0

You need to have a containing outer <div> set to position: realtive; with something like <p>Some text to be faded in here</p> with a position: absolute; top: 0; left: 0;. You also need another <div> inside the outer <div> and at the same level as the <p>, also set with position: absolute; top: 0; left: 0; and a height and width set to match the area you wish to fade. This should also have z-index: 10; background-image: linear-gradient(transparent, rgba(255,255,255,1));. This removes the need for the webkit options.

Robert Yeomans
  • 192
  • 1
  • 4