从背景中切出的透明文本

Posted

技术标签:

【中文标题】从背景中切出的透明文本【英文标题】:Transparent text cut out of background 【发布时间】:2012-12-05 15:47:12 【问题描述】:

有没有办法使用 CSS 制作从背景中剪切出的透明文本效果,如下图所示? 由于图像替换了文本,失去了所有宝贵的 SEO,这将是可悲的。

我首先想到了阴影,但我什么都想不通……

图片是网站背景,一个绝对定位的<img>标签

【问题讨论】:

“由于图像替换了文本,失去了所有宝贵的 SEO。”还有现有的图像替换技术,它们仍然非常友好。 BTW:实际上字母背后的背景也需要保持透明,这就是这里的问题…… 是的,这将是一个很好的做法,如果可能的话,使用 css... 我看不出<h1><img alt="Some Text" /></h1><h1>Some Text</h1> 更不友好的原因。传统上,图像的问题在于它们只是被转储到没有支持标记的页面上。 @cimmanon 是的,你是对的。我可能可以使用图像而不会失去 SEO 积分,但是您仍然无法选择文本,在页面上搜索,链接会更复杂,并且更新文本将需要更多工作...:/ 如您所知,Google 在 CSS 图像替换技术方面非常出色:mezzoblue.com/archives/2008/05/05/image_replac 【参考方案1】:

恐怕现在无法使用 CSS。

您最好的选择是简单地使用图像(可能是 PNG)并在其上放置良好的 alt/title 文本。

或者,您可以使用 SPAN 或 DIV 并将图像作为背景,并在其中包含您想要用于 SEO 目的的文本,但将其文本缩进屏幕之外。

【讨论】:

是的,你是对的。我可能可以使用图像而不会失去 SEO 积分,但是您仍然不能选择文本,在页面上搜索,链接会更复杂,并且更新文本会做更多的工作......:/【参考方案2】:

我猜你可以达到类似using background-clip 的效果,但我还没有测试过。

看这个例子:http://www.css3.info/wp-content/uploads/2008/03/webkit-backgroundcliptext_color.html (仅限Webkit,我还不知道如何将黑色背景更改为白色)

【讨论】:

【参考方案3】:

可能的,但到目前为止仅适用于基于 Webkit 的浏览器(Chrome、Safari、Rockmelt,任何基于 Chromium 项目的东西。)

诀窍是在白色元素中有一个与正文具有相同背景的元素,然后在内部元素上使用-webkit- background-clip: text;,这基本上意味着“不要将背景扩展到文本之外”并使用透明文本.

section

    background: url(http://norcaleasygreen.com/wp-content/uploads/2012/11/turf-grass1.jpg);
    width: 100%;
    height: 300px;


div

    background: rgba(255, 255, 255, 1);
    color: rgba(255, 255, 255, 0);

    width: 60%;
    heighT: 80%;
    margin: 0 auto;
    font-size: 60px;
    text-align: center;


p

    background: url(http://norcaleasygreen.com/wp-content/uploads/2012/11/turf-grass1.jpg);
    -webkit-background-clip: text;

​

http://jsfiddle.net/BWRsA/

【讨论】:

是的,这是另一个问题。它仍在开发中,我真诚地希望我们能尽快看到这样的东西! :) 此外,您始终可以在图像上的透明文本上叠加,使其仍然可以选择。但我确信这对 SEO 来说是不好的做法。隐藏消息/关键字等。 我确信它在 Webkit 浏览器中看起来非常漂亮,但对其他人来说,它是一些草顶上的半透明白盒子。 如果没有优雅的回退,这在生产中是 100% 无用的。不像box-shadowborder-radius,如果浏览器不支持这些属性,页面仍然可用,只是看起来不那么漂亮。这个属性不是这样的。 啊,伙计们……是的,我打算在生产中使用它。但当然不是没有后备! @cimmanon【参考方案4】:

css3 可以,但并非所有浏览器都支持

带背景剪辑:文本;您可以为文本使用背景,但您必须将其与页面背景对齐

body 
    background: url(http://www.color-hex.com/palettes/26323.png) repeat;
    margin:10px;

h1  
    background-color:#fff;
    overflow:hidden;
    display:inline-block; 
    padding:10px; 
    font-weight:bold;
    font-family:arial;
    color:transparent;
    font-size:200px;

span  
    background: url(http://www.color-hex.com/palettes/26323.png) -20px -20px repeat;
    -webkit-text-fill-color: transparent;
    -webkit-background-clip: text;
    display:block;
<h1><span>ABCDEFGHIKJ</span></h1>

http://jsfiddle.net/JGPuZ/1337/


自动对齐

使用一点 javascript,您可以自动对齐背景:

$(document).ready(function()
  //Position of the header in the webpage
  var position = $("h1").position();
  var padding = 10; //Padding set to the header
  var left = position.left + padding;
  var top = position.top + padding;
  $("h1").find("span").css("background-position","-"+left+"px -"+top+"px"); 
);
body 
    background: url(http://www.color-hex.com/palettes/26323.png) repeat;
    margin:10px;

h1  
    background-color:#fff;
    overflow:hidden;
    display:inline-block; 
    padding:10px; 
    font-weight:bold;
    font-family:arial;
    color:transparent;
    font-size:200px;

span  
    background: url(http://www.color-hex.com/palettes/26323.png) -20px -20px repeat;
    -webkit-text-fill-color: transparent;
    -webkit-background-clip: text;
    display:block;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1><span>ABCDEFGHIKJ</span></h1>
​​​

http://jsfiddle.net/JGPuZ/1336/

【讨论】:

你可能需要稍微修改一下代码,视情况而定,现在它可能与其他元素发生冲突,而且这个写得非常快,如果你有任何问题我会听到的 是的,但我对 jQuery 的了解就像我的手掌一样(好吧.. 差不多吧)。我可能会为它制作一个漂亮的小插件!也谢谢你,标记为正确! 不要忽视答案,这是一个非常好的解决方案,但 background-clip:text 是一个仅限 Webkit 的非标准选项。 CSS3 不允许此属性 (see) 使用 text 值。 确认这很遗憾在 Firefox 中不起作用 这种技术可以让你看到文本通常所在的元素的背景。我正在寻找一种方法来通过文本通常所在的位置查看带有文本的元素下的内容。【参考方案5】:

虽然这可以通过 CSS 实现,但更好的方法是使用 inline SVG 和 SVG masking。这种方法比 CSS 有一些优势:

更好的浏览器支持:IE10+、chrome、Firefox、safari... 这不会影响 SEO,因为蜘蛛可以抓取 SVG 内容 (google indexes SVG content since 2010)

CodePen 演示:SVG text mask

body,htmlheight:100%;margin:0;padding:0;
body
  background:url('https://farm9.staticflickr.com/8760/17195790401_94fcf60556_c.jpg');
  background-size:cover;
  background-attachment:fixed;

svgwidth:100%;
<svg viewbox="0 0 100 60">
  <defs>
    <mask id="mask" x="0" y="0"  >
      <rect x="0" y="0"   fill="#fff"/>
      <text text-anchor="middle" x="50" y="18" dy="1">SVG</text>
      <text text-anchor="middle" x="50" y="30" dy="1">Text mask</text>
    </mask>
  </defs>
  <rect x="5" y="5"   mask="url(#mask)" fill-opacity="0.5"/>    
</svg>

如果您的目标是使文本可供选择和搜索,则需要将其包含在&lt;defs&gt; 标记之外。以下示例显示了一种使用 &lt;use&gt; 标签保留透明文本的方法:

body,htmlheight:100%;margin:0;padding:0;
body
  background:url('https://farm9.staticflickr.com/8760/17195790401_94fcf60556_c.jpg');
  background-size:cover;
  background-attachment:fixed;

svgwidth:100%;
<svg viewbox="0 0 100 60">
  <defs>
    <g id="text">
      <text text-anchor="middle" x="50" y="18" dy="1">SVG</text>
      <text text-anchor="middle" x="50" y="30" dy="1">Text mask</text>
    </g>
    <mask id="mask" x="0" y="0"  >
      <rect x="0" y="0"   fill="#fff"/>
      <use xlink:href="#text" />
    </mask>
  </defs>
  <rect x="5" y="5"   mask="url(#mask)" fill-opacity="0.5"/>
  <use xlink:href="#text" mask="url(#mask)" />
</svg>

【讨论】:

这似乎是当今唯一适用于跨浏览器的解决方案:IE11、FF、Chrome、Safari。并且不需要图像作为背景,就像网络上针对该问题提供的许多其他解决方案一样。 受这个答案的启发,我制作了一个关键帧动画,其中白色圆角矩形上的透明 SVG 文本旋转。背景有文字和图像。去看看:jsbin.com/nipuqu/3(世锦赛来了:)) 不错的解决方案,但由于“选择文本并在页面上搜索”似乎是 OP 的要求,您可能希望在 &lt;defs&gt; 部分之外包含 &lt;text&gt;。 (顺便说一句,我不确定 SE 爬虫如何处理 defs 中的 SVG 内容)。这是一种通过可怕的 FF 漏洞利用来保持 OP 想要的方法:jsfiddle.net/tfneqxxb 如果文本是动态的呢?它不会自动调整宽度。 @ImranBughio 不,它没有。 SVG 文本不像纯 HTML 文本。你需要定位它。有关更多信息,请参阅here【参考方案6】:

你可以使用myadzel的PatternizerjQuery插件来实现跨浏览器的效果。目前,还没有跨浏览器的方式仅使用 CSS 来完成此操作。

您可以通过将class="background-clip" 添加到您希望将文本绘制为图像模式的HTML 元素来使用Patternizer,并在附加的data-pattern="…" 属性中指定图像。请参阅demo 的来源。 Patternizer 将创建一个带有图案填充文本的 SVG 图像,并将其放置在透明呈现的 HTML 元素上。

如果如问题的示例图像中那样,文本填充图案应该是超出“图案化”元素的背景图像的一部分,我会看到两个选项(未经测试,我最喜欢的第一个):

在 SVG 中使用蒙版而不是背景图像。 与 web-tiki's answer 一样,使用 Patternizer 仍会自动生成 SVG 并在顶部添加一个不可见的 HTML 元素,以允许文本选择和复制。 或者使用图案图像的自动对齐。可以使用类似于Gijs's answer 中的 JavaScript 代码来完成。

【讨论】:

【参考方案7】:

您可以使用倒置/负/反转字体并通过font-face="…" CSS 规则应用它。您可能需要调整字母间距以避免字母之间出现小的白色间隙。

如果您不需要特定字体,这很简单。下载一个喜欢的,例如从这个collection of inverted fonts。

如果您需要特定的字体(例如“Open Sans”),这很困难。您必须将现有字体转换为反转版本。这可以通过 Font Creator、FontForge 等手动实现,但我们当然想要一个自动化的解决方案。我还没有找到相关说明,但有一些提示:

How to convert a bitmap font into a TrueType font(加上 yet another way 来做到这一点)。首先使用 ImageMagick 命令将字体字形渲染为高分辨率光栅图像并反转它们,然后按照上述说明将它们转换回 TrueType 字体。 Is it possible to invert a font with FontForge or another PGM? Creating a reverse (white on black) font

【讨论】:

【参考方案8】:

适用于大多数现代浏览器的一种方法是使用

background: black;
color: white;
mix-blend-mode: multiply;

对于黑色背景上的透明文本,或

background: white;
color: black;
mix-blend-mode: screen;

用于白色背景上的透明文本。

为了在 chrome 中工作,您还需要在 html 元素上设置任何背景颜色。

将这些样式放在您的文本元素上,然后在其后面放置您想要的任何背景。 Multiply 基本上将 0-255 颜色代码映射到 0-1,然后将其乘以它后面的任何内容,因此黑色保持黑色,白色乘以 1 并有效地变为透明。对于这种情况,屏幕实际上是相反的。 http://codepen.io/nic_klaassen/full/adKqWX/

【讨论】:

对于带有黑色的白色背景,使用 color-dodgelightenscreen mix-blend-mode @ZachSaucier 谢谢,我已经更新了答案,提到您现在需要在 html 元素上设置背景才能在 Chrome 中工作。【参考方案9】:

我需要使文本看起来与原始帖子中的完全一样,但我不能只是通过排列背景来伪造它,因为元素后面有一些动画。似乎还没有人提出这个建议,所以这就是我所做的:(试图使其尽可能易于阅读。)

var el = document.body; //Parent Element. Text is centered inside.
var mainText = "THIS IS THE FIRST LINE"; //Header Text.
var subText = "THIS TEXT HAS A KNOCKOUT EFFECT"; //Knockout Text.
var fontF = "Roboto, Arial"; //Font to use.
var mSize = 42; //Text size.

//Centered text display:
var tBox = centeredDiv(el), txtMain = mkDiv(tBox, mainText), txtSub = mkDiv(tBox),
ts = tBox.style, stLen = textWidth(subText, fontF, mSize)+5; ts.color = "#fff";
ts.font = mSize+"pt "+fontF; ts.fontWeight = 100; txtSub.style.fontWeight = 400;

//Generate subtext SVG for knockout effect:
txtSub.innerHTML =
"<svg xmlns='http://www.w3.org/2000/svg' width='"+stLen+"px' height='"+(mSize+11)+"px' viewBox='0 0 "+stLen+" "+(mSize+11)+"'>"+
    "<rect x='0' y='0' width='100%' height='100%' fill='#fff' rx='4px' ry='4px' mask='url(#txtSubMask)'></rect>"+
    "<mask id='txtSubMask'>"+
        "<rect x='0' y='0' width='100%' height='100%' fill='#fff'></rect>"+
        "<text x='"+(stLen/2)+"' y='"+(mSize+6)+"' font='"+mSize+"pt "+fontF+"' text-anchor='middle' fill='#000'>"+subText+"</text>"+
    "</mask>"+
"</svg>";

//Relevant Helper Functions:
function centeredDiv(parent) 
    //Container:
    var d = document.createElement('div'), s = d.style;
    s.display = "table"; s.position = "relative"; s.zIndex = 999;
    s.top = s.left = 0; s.width = s.height = "100%";
    //Content Box:
    var k = document.createElement('div'), j = k.style;
    j.display = "table-cell"; j.verticalAlign = "middle";
    j.textAlign = "center"; d.appendChild(k);
    parent.appendChild(d); return k;

function mkDiv(parent, tCont) 
    var d = document.createElement('div');
    if(tCont) d.textContent = tCont;
    parent.appendChild(d); return d;

function textWidth(text, font, size) 
    var canvas = window.textWidthCanvas || (window.textWidthCanvas = document.createElement("canvas")),
    context = canvas.getContext("2d"); context.font = size+(typeof size=="string"?" ":"pt ")+font;
    return context.measureText(text).width;

只需将其放入您的 window.onload 中,将主体的背景设置为您的图像,然后观看奇迹发生!

【讨论】:

【参考方案10】:

把那个css放上去

    .banner-sale-1 .title-box .title-overlay 
      font-weight: 900;
      overflow: hidden;
      margin: 0;
      padding-right: 10%;
      padding-left: 10%;
      text-transform: uppercase;
      color: #080404;
      background-color: rgba(255, 255, 255, .85);

      /* that css is the main think (mix-blend-mode: lighten;)*/
      mix-blend-mode: lighten;

    

【讨论】:

【参考方案11】:

我刚刚发现了一种新的方法来解决这个问题,我不完全确定它是如何工作的(如果其他人想解释,请做)。

它似乎工作得很好,并且不需要双重背景或 JavaScript。

代码如下: JSFIDDLE

body 
  padding: 0;
  margin: 0;


div 
  background: url(http://www.color-hex.com/palettes/26323.png) repeat;
  width: 100vw;
  height: 100vh;


body::before 
  content: '$ALPHABET';
  left: 0;
  top: 0;
  position: absolute;
  color: #222;
  background-color: #fff;
  padding: 1rem;
  font-family: Arial;
  z-index: 1;
  mix-blend-mode: screen;
  font-weight: 800;
  font-size: 3rem;
  letter-spacing: 1rem;
&lt;div&gt;&lt;/div&gt;

【讨论】:

【参考方案12】:

mix-blend-mode 也有可能产生这种效果。

mix-blend-mode CSS 属性设置元素的内容应如何与元素的父级内容和元素背景混合。

h1 
background:white;
mix-blend-mode:screen;

/* demo purpose from here */
padding:0.25em;
mix-blend-mode:screen;



html 
background:url(https://i.picsum.photos/id/1069/367/267.jpg?hmac=w5sk7UQ6HGlaOVQ494mSfIe902cxlel1BfGUBpEYoRw)center / cover ;
min-height:100vh;
display:flex;

body margin:auto;
h1:hover border:dashed 10px white;background-clip:content-box;box-shadow:inset 0 0 0 2px #fff, 0 0 0 2px #fff
&lt;h1&gt;ABCDEFGHIJKLMNOPQRSTUVWXYZ&lt;/h1&gt;

【讨论】:

【参考方案13】:

在不久的将来我们可以使用element()来实现这一点

element() 函数允许作者将文档中的元素用作图像。随着引用元素外观的变化,图像也会发生变化ref

诀窍是创建一个带有文本的通用 div,然后使用 element() 结合 mask

这是一个基本示例,目前仅适用于最新版本的 Firefox。

#text 
  font-size:35px;
  font-weight:bold;
  color:#000;
  font-family:sans-serif;
  text-transform: uppercase;
  white-space:nowrap;
  /* we hide it */ 
  position:fixed;
  right:200vw;
  bottom:200vh



body 
  background:url(https://picsum.photos/id/1018/800/800) center/cover; 


.main 
  margin:50px;
  height:100px;
  background:red;
  -webkit-mask:
    -moz-element(#text) center/contain no-repeat, /* this behave like a background-image*/
    linear-gradient(#fff 0 0);
  mask-composite:exclude;
<div id="text">
You can put your text here
</div>

<div class="main">

</div>

它将产生以下内容:

它是响应式的,因为我们依赖于基本的背景属性,并且我们可以使用基本的 CSS 轻松更新文本。

我们可以考虑任何类型的内容,也可以创建模式:

#text 
  font-size:30px;
  font-weight:bold;
  color:#000;
  font-family:sans-serif;
  text-transform: uppercase;
  white-space:nowrap;
  padding:20px;
  /* we hide it */ 
  position:fixed;
  right:200vw;
  bottom:200vh

#text span 
  font-family:cursive;
  font-size:35px;



body 
  background:url(https://picsum.photos/id/1018/800/800) center/cover; 


.main 
  margin:50px;
  height:100px;
  background:red;
  -webkit-mask:
    -moz-element(#text) 0 0/20% auto, /* this behave like a background-image*/
    linear-gradient(#fff 0 0);
  mask-composite:exclude;
<div id="text">
Your <span>text</span> here ?
</div>

<div class="main">

</div>

为什么不用动画来创建无限滚动文本:

#text 
  font-size:30px;
  font-weight:bold;
  color:#000;
  font-family:sans-serif;
  text-transform: uppercase;
  white-space:nowrap;
  padding:20px 5px;
  /* we hide it */ 
  position:fixed;
  right:200vw;
  bottom:200vh



body 
  background:url(https://picsum.photos/id/1018/800/800) center/cover; 


.main 
  margin:50px;
  height:100px;
  padding-right:calc(50% - 50px);
  background:red;
  -webkit-mask:
    -moz-element(#text) 0 50%/200% auto content-box, /* this behave like a background-image*/
    linear-gradient(#fff 0 0);
  mask-composite:exclude;
  animation:m 5s linear infinite;


@keyframes m
  to -webkit-mask-position:200% 50%
<div id="text">
Srolling repeating text here 
</div>

<div class="main">

</div>

【讨论】:

【参考方案14】:

这对我有用 mix-blend-mode: color-dodge 在颜色相反的容器上。

.main
 background: url('https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__340.jpg');
 height: 80vh;
 width: 100vw;
 padding: 40px;


.container
   background-color: white;
   width: 80%;
   height: 50px;
   padding: 40px;
   font-size: 3em;
   font-weight: 600;
   mix-blend-mode: color-dodge;


.container span
  color: black;
<div class="main">
<div class="container">
<span>This is my text</span>
</div>
</div>

【讨论】:

以上是关于从背景中切出的透明文本的主要内容,如果未能解决你的问题,请参考以下文章

透明的空心或切出的圆圈

Sketch 如何快速切出背景透明且留边的切图?

Python:如何从图像中切出具有特定颜色的区域(OpenCV,Numpy)

Android - 从方形位图中切出一个圆圈

MATLAB / Octave:从图像中切出很多圆圈

如何在 Java 中从 ArrayList 中切出 ArrayList?