CSS3不透明度渐变?

93

我希望创建一个类似这样的效果,但是我的网站具有动态的background-color。请注意,此示例使用白色叠加层,无法与不同的背景配合使用。

p {
    width: 300px;
    overflow: hidden;
    height: 50px;
    line-height: 50px;
    position: relative;
}
p:after {
    content: "";
    width: 100px;
    height: 50px;
    position: absolute;
    top: 0;
    right: 0;
    background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,1));
}

我希望做的是设置CSS不透明度渐变。这个有点作用,但代码太乱了。看着第二个例子,我可以在jQuery中实现它,但是否有任何方式完全使用CSS来实现呢?


我的用例没有动态背景,所以非常感谢您提供的“像这样”的链接。那正是我需要的!(除了垂直方向 :) ) - John Carrell
4个回答

139

CSS中可以使用此方法,但目前仅有Chrome、Safari和Opera的现代版本支持,Firefox仅支持SVG蒙版。 请参见Caniuse获取更多信息。

编辑:除IE外的所有浏览器现在都支持此处提到的mask-属性。

CSS:

p {
    color: red;
    -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, 
    from(rgba(0,0,0,1)), to(rgba(0,0,0,0)));
}

关键是指定一个渐变的蒙版,该蒙版以不可见结束(通过alpha值)

查看具有纯色背景的演示,但您可以将其更改为任何您想要的内容。

演示

还请注意,所有常规的图像属性都可用于mask-image。

p  {
  color: red;
  font-size: 30px;
  -webkit-mask-image: linear-gradient(to left, rgba(0,0,0,1), rgba(0,0,0,0)), linear-gradient(to right, rgba(0,0,0,1), rgba(0,0,0,0));
  -webkit-mask-size: 100% 50%;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: left top, left bottom;
  }

div {
    background-color: lightblue;
}
<div><p>text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p></div>

现在有另一种方法可用,Chrome、Firefox、Safari和Opera都支持这种方法。这个想法是使用:
mix-blend-mode: hard-light;

如果颜色是灰色,那么它会提供透明度。然后,在元素上创建一个灰色覆盖层来实现透明度。

div {
  background-color: lightblue;
}

p {
  color: red;
  overflow: hidden;
  position: relative;
  width: 200px;
  mix-blend-mode: hard-light;
}

p::after {
  position: absolute;
  content: "";
  left: 0px;
  top: 0px;
  height: 100%;
  width: 100%;
  background: linear-gradient(transparent, gray);
  pointer-events: none;
}
<div><p>text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p></div>


6
在 Firefox 中是否有类似于 -webkit-mask-image 的等效属性? - suga_shane
@suga_shane 为大多数现代浏览器添加了等价性。 - vals
我在Firefox中使用第二种方法时遇到了一些问题-它显示了一些故障。最终,我只是使用了:after和线性渐变(从透明到白色)作为背景。 - Almir Sarajčić
@donquixote 嗯,其实不是。我们现在已经让 Opera 正常工作了!(当然,因为他们改变了渲染引擎,但是嘛……) - vals
1
@MikhailKhazov 你想要的最简单的解决方案是将梯度设置为初始步骤 - 即保持不透明直到非0百分比。更困难的方法,但具有更多不同的可能性,是设置多个掩码,我已经添加了一个显示此可能性的代码片段。 - vals
显示剩余6条评论

6
除了使用 css mask(由 @vals 回答),您还可以使用透明度渐变背景并将 background-clip 设置为 text
创建适当的渐变:
background: linear-gradient(to bottom, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0) 100%);

然后用文本剪辑背景:
background-clip: text;
color: transparent;

演示

https://jsfiddle.net/simonmysun/2h61Ljbn/4/

在 Windows 10 下测试通过 Chrome 75。

支持的平台:


5

我认为与此问题相关的“混乱”的第二种方法,可以从这里的另一个问题链接中找到,可能是唯一的纯CSS解决方案。

如果您考虑使用JavaScript,则以下是我的解决方案:

demo: using a canvas element to fade 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 <!--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);
};

非常感谢您提供的信息。您的示例非常酷。 但是,这比我的项目需要的要多得多;-) 我希望有一些内置的CSS技巧我不知道。 我尝试了jQuery实现,但我需要知道背景颜色。 我在我的网站上使用jQuery Themeroller,并有许多可切换的主题,因此我不知道文本的前景或背景颜色。所以您的示例将文本设置为黑色。 - pgee70
我注意到了一个有趣的 bug(特性?);当你选中小描述文本时,它会重新调整大小。 - TylerH

3
我们可以通过CSS来实现这个功能。
body {
  background: #000;
  background-image: linear-gradient(90deg, rgba(255, 255, 255, .3) 0%, rgba(231, 231, 231, .3) 22.39%, rgba(209, 209, 209,  .3) 42.6%, rgba(182, 182, 182, .3) 79.19%, rgba(156, 156, 156, .3) 104.86%);
  
}

3
我想你误解了问题。作者想要文本上的渐变。 - simonmysun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接