3

I want a <div> element (the whole element, contents and everything) to fade out towards the bottom. It's to truncate a news post that has to fit into a very restrictive space (and can contain unpredictably sized elements).

Everything I've been able to find is for using a transparency gradient on a background color. Which would be fine except behind the news post is a background image, so I can't just put a color gradient over top of the bottom of the content.

I'd put an image gradient over top of the content but the background moves behind the content as the user scrolls.

So imagine this existed:

opacity: -webkit-linear-gradient( ... );

graduating the actual opacity of the element is the only thing that will work. Is it possible?

Carson Myers
  • 34,352
  • 35
  • 118
  • 164
  • as far as I'm aware this is not possible, would love to know if you find a solution. – kalpaitch Sep 30 '12 at 19:22
  • I've made a guess that we've understood a different meaning in having a 'fixed' background - if when scrolling content the background stays still and the foreground moves seperately -- then my added version should work. hope it helps. – Pebbl Oct 02 '12 at 13:28
  • I believe this answer will work for you: https://stackoverflow.com/a/51557089/271351 – cjbarth Dec 13 '18 at 21:04
  • Does this answer your question? [CSS3 opacity gradient?](https://stackoverflow.com/questions/15597167/css3-opacity-gradient) – user Apr 08 '20 at 15:46

6 Answers6

5

2015 Update

There have been improvements in the browser world towards this ability using masks, however, as far as I can see none of it is completely standardised across browsers (in a nice way) yet. So whatever you implement it gets messy. For further information on recent enhancements, the following is a good post:

https://css-tricks.com/clipping-masking-css/

Chrome seems to win out in terms of support and speed, with Safari not far behind. Sadly Firefox does not support much of the linked to page, save for anything that relies on SVG. Luckily it is the SVG examples that show fading and seem to work across Chrome, Safari and Firefox (at least the latest versions of).

So perhaps the best route for now is to implement an SVG mask — based on a rectangle with a gradient applied — and assign it using mask: url(#maskid);. However, I tend to find these solutions get confused by SVG viewBox and dimensional sizing issues — and can go very odd when not applied to "media" elements — so will hold off on giving a water tight example for now.

Basic principal

The only way to currently achieve this is to layer a gradient fading to the background colour "on top" of the element you want to fade using position absolute. So using the gradients from the other answers above, but apply this to a floating element on top of the text.

This gets the best effect when you have a solid background colour, but it is doable with background images as well, as long as the background is fixed in position.

css

.container {
  position: relative;
  overflow: hidden;
  height: 50px; /* some fixed height that you need you content to fix to */
}

.fadeout {
  position: absolute;
  width: 100%;
  height: 1em;
  /* you can use a premade png fade out or a dynamic gradient here*/
  background: ...;
}

markup

<div class="container">
  <p>
    This is my long text that goes on for paragraphs and paragraphs, 
    far longer than the container....
  </p>
  <div class="fadeout"></div>
</div>


Update

After spotting Carson Myers further comments around this question I'm making a guess that the following could work. When I stated above that the background has to be fixed - I mean that it had to be fixed in terms of background-attachment. So if the background has been implemented in this way you can use the following 'hack' to get things to work. Bear in mind that floating absolute layers on top of content can cause usability problems.. and having many transparent layers can slow older browsers down:

jsfiddle

http://jsfiddle.net/kthPT/30

The code below is an example with an outer layer set to scroll it's content (to represent the outer page or body), and with inner "news" areas that have a limited height and fade out the rest of their content. Both uses of background: url('...') need to filled out with the same background image path. Because the background image is 'fixed' in both locations in all the modern browsers I've tested it calculates the background to the same position. So the floating layers on top have the same graphics as the layer below.

The resulting markup is a little horrible bulky, so you could feasibly convert this to be generated by javascript on browsers that supported opacity - and possibly using any "height" of fade out. The current version supports only 20px of fade.

css

.outer {
    background: url('...') repeat fixed;
    height: 200px;
    overflow: auto;
}

.news {
    position: relative;
    width: 300px;
    height: 100px;
    overflow: hidden;
}

.news .fadeout {
    position: absolute;
    bottom: 0;
    width: 100%;
}

.news .fadeout .fadeline {
    height: 2px;
    background: url('...') repeat fixed;
}

/* a good idea to add vendor prefixed versions of opacity here */
.news .fadeout .o09 { opacity: 0.9; }
.news .fadeout .o08 { opacity: 0.8; }
.news .fadeout .o07 { opacity: 0.7; }
.news .fadeout .o06 { opacity: 0.6; }
.news .fadeout .o05 { opacity: 0.5; }
.news .fadeout .o04 { opacity: 0.4; }
.news .fadeout .o03 { opacity: 0.3; }
.news .fadeout .o02 { opacity: 0.2; }
.news .fadeout .o01 { opacity: 0.1; }

markup

<div class="outer">
    <div class="news">
        <h4>News</h4>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut 
          suscipit dui ac lacus convallis dapibus. In cursus arcu at 
          arcu mollis vestibulum. Morbi ac quam sed nisl vulputate 
          aliquam in ac velit. Curabitur ac feugiat justo. Fusce 
          imperdiet, arcu non dignissim vulputate, leo odio ultricies 
          mauris, in consectetur risus odio malesuada sapien. 
          Nam sagittis convallis dictum. Duis eget lectus
        </p>
        <div class="fadeout">
            <div class="fadeline o01"></div>
            <div class="fadeline o02"></div>
            <div class="fadeline o03"></div>
            <div class="fadeline o04"></div>
            <div class="fadeline o05"></div>
            <div class="fadeline o06"></div>
            <div class="fadeline o07"></div>
            <div class="fadeline o08"></div>
            <div class="fadeline o09"></div>
            <div class="fadeline o10"></div>
            <div class="fadeline o10"></div>
            <div class="fadeline o10"></div>
            <div class="fadeline o10"></div>
        </div>
    </div>
    <div class="news">
        <h4>News</h4>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut 
          suscipit dui ac lacus convallis dapibus. In cursus arcu at 
          arcu mollis vestibulum. Morbi ac quam sed nisl vulputate 
          aliquam in ac velit. Curabitur ac feugiat justo. Fusce 
          imperdiet, arcu non dignissim vulputate, leo odio ultricies 
          mauris, in consectetur risus odio malesuada sapien. 
          Nam sagittis convallis dictum. Duis eget lectus
        </p>
        <div class="fadeout">
            <div class="fadeline o01"></div>
            <div class="fadeline o02"></div>
            <div class="fadeline o03"></div>
            <div class="fadeline o04"></div>
            <div class="fadeline o05"></div>
            <div class="fadeline o06"></div>
            <div class="fadeline o07"></div>
            <div class="fadeline o08"></div>
            <div class="fadeline o09"></div>
            <div class="fadeline o10"></div>
            <div class="fadeline o10"></div>
            <div class="fadeline o10"></div>
            <div class="fadeline o10"></div>
        </div>
    </div>
    <div class="news">
        <h4>News</h4>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut 
          suscipit dui ac lacus convallis dapibus. In cursus arcu at 
          arcu mollis vestibulum. Morbi ac quam sed nisl vulputate 
          aliquam in ac velit. Curabitur ac feugiat justo. Fusce 
          imperdiet, arcu non dignissim vulputate, leo odio ultricies 
          mauris, in consectetur risus odio malesuada sapien. 
          Nam sagittis convallis dictum. Duis eget lectus
        </p>
        <div class="fadeout">
            <div class="fadeline o01"></div>
            <div class="fadeline o02"></div>
            <div class="fadeline o03"></div>
            <div class="fadeline o04"></div>
            <div class="fadeline o05"></div>
            <div class="fadeline o06"></div>
            <div class="fadeline o07"></div>
            <div class="fadeline o08"></div>
            <div class="fadeline o09"></div>
            <div class="fadeline o10"></div>
            <div class="fadeline o10"></div>
            <div class="fadeline o10"></div>
            <div class="fadeline o10"></div>
        </div>
    </div>
</div>
Pebbl
  • 31,117
  • 6
  • 57
  • 63
  • Sadly, the background isn't fixed. But at least I know it's not possible now haha. – Carson Myers Sep 30 '12 at 19:24
  • That is awesome! I didn't realize there was a specific hack for when it's `fixed` in this way, so I wish I had been more explicit. The background isn't stationary with respect to the viewport _or_ the content, but rather moves at a slower rate than the user scrolls to create a parallax effect. – Carson Myers Oct 03 '12 at 03:12
  • Ah... sounds like you're making things difficult for yourself ;) Your only hope is the same as above *(or a canvas-powered version)* that is updated *(i.e. shifting the background offset)* using javascript at the same time you handle your parallax scrolling... but that amount of processing is likely to interfere with the user's experience... and jurky scrolling is no fun. Maybe they'll introduce proper masks and alpha maps in CSS 4 :) – Pebbl Oct 03 '12 at 08:00
  • It's not me making it difficult :P I think you're right, canvas/javascript is the only way and that's way too expensive to be running on every _scroll_. I've just got a "..." attached to the bottom right of the `div` for now, I may wind up leaving it that way, claiming technical impossibility to the customer. – Carson Myers Oct 03 '12 at 22:30
  • I'm accepting this answer because, while what I want appears impossible, this is the closest. – Carson Myers Oct 03 '12 at 22:35
2

Try this handy tool, it'll generate alpha colours for you, you're basically trying to use an rgba value, but of course gotta be aware that this will only be supported by newer browsers...

http://www.colorzilla.com/gradient-editor/

This is what it came up with for a black to 100% alpha gradient: background: url(IMAGE_URL) linear-gradient(to bottom, rgba(0,0,0,1) 0%,rgba(255,255,255,0) 100%);

kalpaitch
  • 5,095
  • 10
  • 40
  • 64
  • Neat tool, but it's for background gradients. I'm asking if it's possible to apply a gradient to an element's opacity property, not the opacity of a background gradient. – Carson Myers Sep 30 '12 at 19:11
  • in short no, but whats the difference. if you want to have a background image as well, then do what SidMS says and put it on a parent wrapper – kalpaitch Sep 30 '12 at 19:14
  • I need the contents of the div to fade out as well. Sorry if that wasn't clear, I've updated the question a bit to better convey that – Carson Myers Sep 30 '12 at 19:16
  • I think you want this (answer updated to accomodate) - http://stackoverflow.com/questions/2504071/is-it-possible-to-combine-a-background-image-and-css3-gradients - if you want the text inside the div to fade out as well then I don't think theres an answer yet, maybe CSS4 – kalpaitch Sep 30 '12 at 19:16
  • Hmm, didn't know you could do this with images. Unfortunately it won't work in my situation :/ – Carson Myers Sep 30 '12 at 19:24
2

If you are ok with using JavaScript for this, then you could do it using a canvas element

demo: fading text against an animated background

The idea is that your element with the text and the canvas element are one on top of the other. You keep the text in your element (in order to allow text selection, which isn't possible with canvas text), but make it completely transparent (with rgba(0,0,0,0), in order to have the text visible in IE8 and older - that's because you have no RGBa support and no canvas support in IE8 and older).

You then read the text inside your element and write it on the canvas with the same font properties so that each letter you write on the canvas is over the corresponding letter in the element with the text.

The canvas element does not support multi-line text, so you'll have to break the text into words and then keep adding words on a test line which you then measure. If the width taken by the test line is bigger than the maximum allowed width you can have for a line (you get that maximum allowed width by reading the computed width of the element with the text), then you write it on the canvas without the last word added, you reset the test line to be that last word, and you increase the y coordinate at which to write the next line by one line height (which you also get from the computed styles of your element with the text). With each line that you write, you also decrease the opacity of the text with an appropriate step (this step being inversely proportional to the average number of characters per line).

What you cannot do easily in this case is to justify text. It can be done, but it gets a bit more complicated, meaning that you would have to compute how wide should each step be and write the text word by word rather than line by line.

Also, keep in mind that if your text container changes width as you resize the window, then you'll have to clear the canvas and redraw the text on it on each resize.

OK, the code:

HTML:

<article>
  <h1>Interacting Spiral Galaxies NGC 2207/ IC 2163</h1>
  <em class='timestamp'>February 4, 2004 09:00 AM</em>
  <section class='article-content' id='art-cntnt'>
    <canvas id='c' class='c'></canvas>In the direction of the <!--and so on-->  
  </section>
</article>

CSS:

html {
  background: url(moving.jpg) 0 0;
  background-size: 200%;
  font: 100%/1.3 Verdana, sans-serif;
  animation: ani 4s infinite linear;
}
article {
  width: 50em; /* tweak this ;) */
  padding: .5em;
  margin: 0 auto;
}
.article-content {
  position: relative;
  color: rgba(0,0,0,0);
  /* add slash at the end to check they superimpose *
  color: rgba(255,0,0,.5);/**/
}
.c {
  position: absolute;
  z-index: -1;
  top: 0; left: 0;
}
@keyframes ani { to { background-position: 100% 0; } }

JavaScript:

var wrapText = function(ctxt, s, x, y, maxWidth, lineHeight) {
  var words = s.split(' '), line = '', 
      testLine, metrics, testWidth, alpha = 1, 
      step = .8*maxWidth/ctxt.measureText(s).width;
  
  for(var n = 0; n < words.length; n++) {
    testLine = line + words[n] + ' ';
    metrics = ctxt.measureText(testLine);
    testWidth = metrics.width;
    if(testWidth > maxWidth) {
      ctxt.fillStyle = 'rgba(0,0,0,'+alpha+')';
      alpha  -= step;
      ctxt.fillText(line, x, y);
      line = words[n] + ' ';
      y += lineHeight;
    }
    else line = testLine;
  }
  ctxt.fillStyle = 'rgba(0,0,0,'+alpha+')';
  alpha  -= step;
  ctxt.fillText(line, x, y);
  return y + lineHeight;
}

window.onload = function() {
  var c = document.getElementById('c'), 
      ac = document.getElementById('art-cntnt'), 
      /* use currentStyle for IE9 */
      styles = window.getComputedStyle(ac),
      ctxt = c.getContext('2d'), 
      w = parseInt(styles.width.split('px')[0], 10),
      h = parseInt(styles.height.split('px')[0], 10),
      maxWidth = w, 
      lineHeight = parseInt(styles.lineHeight.split('px')[0], 10), 
      x = 0, 
      y = parseInt(styles.fontSize.split('px')[0], 10), 
      text = ac.innerHTML.split('</canvas>')[1];
  
  c.width = w;
  c.height = h;
  ctxt.font = '1em Verdana, sans-serif';
  wrapText(ctxt, text, x, y, maxWidth, lineHeight);
};
Community
  • 1
  • 1
Ana
  • 33,368
  • 6
  • 74
  • 119
  • How'd I miss this before!? very cool. It looks a little messed up in my browser, but the text still fades out over the animated background. I'll have to look into this more closely – Carson Myers Jan 17 '13 at 06:55
1

It is possible, without specifing an height for the container.

Check this working demo, and try to add/remove contents from #contents

HTML

<div id="container">
    <div id="contents">
        Some contents goes here
    </div>
    <div id="gradient">
    </div>
</div>

CSS

#container {
    position:relative;
}
#contents {
    background:red;
}
#gradient {
    position:absolute;
    z-index:2;
    right:0; bottom:0; left:0;
    height:200px; /* adjust it to your needs */
    background: url(data:image/svg+xml;base64,alotofcodehere);
    background: -moz-linear-gradient(top,  rgba(255,255,255,0) 0%, rgba(255,255,255,1) 70%);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0)), color-stop(70%,rgba(255,255,255,1)));
    background: -webkit-linear-gradient(top,  rgba(255,255,255,0) 0%,rgba(255,255,255,1) 70%);
    background: -o-linear-gradient(top,  rgba(255,255,255,0) 0%,rgba(255,255,255,1) 70%);
    background: -ms-linear-gradient(top,  rgba(255,255,255,0) 0%,rgba(255,255,255,1) 70%);
    background: linear-gradient(to bottom,  rgba(255,255,255,0) 0%,rgba(255,255,255,1) 70%);
}​

This will work almost in any browser which supports opacity (including IE9), and here's the IE8 "rgba" fallback (untested):

filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ffffff',GradientType=0 );

To generate your own gradient, visit Colorzilla.

The first stop (0%) must have opacity 0 ( rgba(255,255,255,0); ), then around 70% - do some tests to find what's good for you - add another stop with opacity 1 ( rgba(255,255,255,1); ).

You've to know the background of the page/container to make it work obviously...

Giona
  • 18,857
  • 4
  • 48
  • 68
1

There is currently no elegant one-line CSS solution that would allow you to do this across all browsers. You can either use the non-standard -webkit-mask-image property (demo) or an SVG mask (demo). The most complete cross-browser solution that I've seen so far is from Christian Schaefer's tutorial, "CSS Masks – How To Use Masking In CSS Now".

sigalor
  • 542
  • 8
  • 18
thdoan
  • 15,024
  • 1
  • 46
  • 40
0

Is this what you are looking for?

Take a look at my jsfiddle.

I'm not sure what you want because your description is not satisfactory. Can you make a jsfiddle of what the problem is?

Ilan Biala
  • 3,093
  • 5
  • 32
  • 45
  • Thank you for the effort, but I don't know what was unclear about my description. I want the contents of the div to fade out, and I mentioned that graduating the actual opacity of the element is the only thing that will work due to various circumstances (as opposed to tricks using background gradients). – Carson Myers Oct 01 '12 at 02:45
  • So you want the text to go from black to background color? – Ilan Biala Oct 02 '12 at 02:59
  • To transparent. the background is an image that moves when the user scrolls (but it's not `fixed`, it moves at a different rate than the user scrolls to create a parallax effect) – Carson Myers Oct 03 '12 at 22:33