CSS CSS3 不透明度渐变?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15597167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
CSS3 opacity gradient?
提问by pgee70
I am looking to create an effect like this, but my website has a dynamic background-color
. Note that this example uses a white overlay, which does not work with different backgrounds.
我期待创造一个效果是这样的,但我的网站具有动态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));
}
What I was hoping to do was to set up a CSS opacity gradient. Thissort of works, but the code is too messy. Looking at this second example, I could implement it in jQuery, but is there any way to do this entirely in CSS?
我希望做的是设置一个 CSS 不透明度渐变。这种工作,但代码太乱了。看看第二个例子,我可以在 jQuery 中实现它,但是有什么方法可以完全在 CSS 中做到这一点?
回答by vals
You can do it in CSS, but there isn't much support in browsers other than modern versions of Chrome, Safari and Opera at the moment. Firefox currently only supports SVG masks. See the Caniuseresults for more information.
您可以在 CSS 中完成此操作,但目前除了现代版本的 Chrome、Safari 和 Opera 之外的浏览器没有太多支持。Firefox 目前仅支持 SVG 掩码。有关更多信息,请参阅Caniuse结果。
CSS:
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)));
}
The trick is to specify a mask that is itself a gradient that ends as invisible (thru alpha value)
诀窍是指定一个蒙版,它本身就是一个以不可见(通过 alpha 值)结尾的渐变
See a demo with a solid background, but you can change this to whatever you want.
查看具有纯色背景的演示,但您可以将其更改为您想要的任何内容。
Notice also that all the usual imageproperties are available for mask-image
另请注意,所有常用的图像属性都可用于 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>
Now, another approach is available, that is supported by Chrome, Firefox, Safari and Opera.
现在,可以使用另一种方法,即 Chrome、Firefox、Safari 和 Opera 支持。
The idea is to use
这个想法是使用
mix-blend-mode: hard-light;
that gives transparency if the color is gray. Then, a grey overlay on the element creates the transparency
如果颜色是灰色,它会提供透明度。然后,元素上的灰色叠加层创建透明度
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>
回答by Ana
I think the "messy" second method, which is linked from another question heremay be the only pure CSS solution.
我认为“凌乱”的第二种方法,从另一个问题这里链接可能是唯一的纯 CSS 解决方案。
If you're thinking about using JavaScript, then this was my solution to the problem:
如果您正在考虑使用 JavaScript,那么这是我对问题的解决方案:
demo: using a
canvas
element to fade text against an animated backgroundThe 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 withcanvas
text), but make it completely transparent (withrgba(0,0,0,0)
, in order to have the text visible in IE8 and older - that's because you have noRGBa
support and nocanvas
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); };
演示:使用
canvas
元素在动画背景下淡化文本这个想法是你的元素与文本和
canvas
元素是一个在另一个之上。您将文本保留在元素中(为了允许文本选择,这在文本中是不可能的canvas
),但使其完全透明(使用rgba(0,0,0,0)
, 以便在 IE8 及更早版本中显示文本 - 那是因为您没有RGBa
支持并且不canvas
支持 IE8 及更早版本)。然后,您阅读元素内的文本,并使用相同的字体属性将其写在画布上,以便您在画布上写下的每个字母都覆盖在带有文本的元素中的相应字母上。
该
canvas
元素不支持多行文本,因此您必须将文本分成单词,然后在测试行上继续添加单词,然后进行测量。如果测试线采用的宽度大于一条线的最大允许宽度(通过读取带有文本的元素的计算宽度来获得最大允许宽度),则将其写在画布上,而不是添加最后一个单词,您将测试行重置为最后一个单词,并将下一行的 y 坐标增加一个行高(您也可以从带有文本的元素的计算样式中获得)。对于您编写的每一行,您还可以通过适当的步骤降低文本的不透明度(此步骤与每行的平均字符数成反比)。在这种情况下,您不能轻易做的是对齐文本。这是可以完成的,但它变得有点复杂,这意味着您必须计算每个步骤的宽度并逐字而不是逐行写出文本。
另外,请记住,如果您的文本容器在调整窗口大小时更改宽度,那么您必须清除画布并在每次调整大小时在其上重新绘制文本。
好的,代码:
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); };