Transparent text cut out of background

CssSvgFontsCss Shapes

Css Problem Overview


Is there any way to make a transparent text cut out of a background effect like the one in the following image, with CSS?
It would be sad to lose all precious SEO because of images replacing text.

Transparent text cut out of background

I first thought of shadows but I can't figure anything out...

The image is the site background, an absolute positioned <img> tag

Css Solutions


Solution 1 - Css

It's possible with css3 but it's not supported in all browsers

With background-clip: text; you can use a background for the text, but you will have to align it with the background of the page

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/


Automatic Alignment

With a little javascript you can align the background automatically:

$(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/

Solution 2 - Css

Although this is possible with CSS, a better approach would be to use an inline SVG with SVG masking. This approach has some advantages over CSS :

CodePen Demo : SVG text mask

transparent text clipping background

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

<svg viewbox="0 0 100 60">
  <defs>
    <mask id="mask" x="0" y="0" width="100" height="50">
      <rect x="0" y="0" width="100" height="40" 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" width="90" height="30" mask="url(#mask)" fill-opacity="0.5"/>    
</svg>

If you aim on making the text selectable and searchable, you need to include it outside the <defs> tag. The following example shows a way to do that keeping the transparent text with the <use> tag:

body,html{height:100%;margin:0;padding:0;}
body{
  background:url('https://farm9.staticflickr.com/8760/17195790401_94fcf60556_c.jpg');
  background-size:cover;
  background-attachment:fixed;
}
svg{width: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" width="100" height="50">
      <rect x="0" y="0" width="100" height="40" fill="#fff"/>
      <use xlink:href="#text" />
    </mask>
  </defs>
  <rect x="5" y="5" width="90" height="30" mask="url(#mask)" fill-opacity="0.5"/>
  <use xlink:href="#text" mask="url(#mask)" />
</svg>

Solution 3 - Css

One way that works on most modern browsers is to use

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

for transparent text on a black background, or

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

for transparent text on a white background.

enter image description here

For this to work in chrome, you also need to set any background colour on the html element.

Put these styles on your text element and then put whatever background you want behind that. Multiply basically maps the 0-255 color code to 0-1 and then multiplies that by whatever is behind it, so black stays black and white multiplies by 1 and effectively becomes transparent. Screen is effectively the opposite for this case. http://codepen.io/nic_klaassen/full/adKqWX/

Solution 4 - Css

It is possible, but so far only with Webkit based browsers (Chrome, Safari, Rockmelt, anything based on the Chromium project.)

The trick is to have an element within the white one that has the same background as the body, then use -webkit- background-clip: text; on the inner element which basically means "don't extend the background beyond the text" and use transparent 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/

Solution 5 - Css

just put that 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;

    }

Solution 6 - Css

I just discovered a new way to do this while messing around, I'm not entirely sure how it works ( if someone else wants to explain please do ).

It seems to work very well, and requires no double backgrounds or JavaScript.

Here's the code: 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;
}

<div></div>

Solution 7 - Css

In the near future we can use element() to achieve this

>The element() function allows an author to use an element in the document as an image. As the referenced element changes appearance, the image changes as well ref

The trick is to create a common div with text then use element() combined with mask.

Here is a basic example that works only on the latest version Firefox for now.

#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>

It will produce the following:

CSS transparent text over background image

It's reponsive since we rely on basic background properties and we can easily update the text using basic CSS.

We can consider any kind of content and also create patterns:

#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>

CSS text mask over background

And why not some animation to create an infinite scrolling text:

#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>

animated text using CSS mask

Solution 8 - Css

I guess you could achieve something like that using background-clip, but I haven't tested that yet.

See this example:
http://www.css3.info/wp-content/uploads/2008/03/webkit-backgroundcliptext_color.html<br /> (Webkit only, I don't know yet how to change the black background to a white one)

Solution 9 - Css

You can use myadzel's Patternizer jQuery plugin to achieve this effect across browsers. At this time, there is no cross-browser way to do this with just CSS.

You use Patternizer by adding class="background-clip" to HTML elements where you want the text to be painted as an image pattern, and specify the image in an additional data-pattern="ā€¦" attribute. See the source of the demo. Patternizer will create an SVG image with pattern-filled text and underlay it to the transparently rendered HTML element.

If, as in the question's example image, the text fill pattern should be a part of a background image extending beyond the "patternized" element, I see two options (untested, my favourite first):

  • Use masking instead of a background image in the SVG. As in web-tiki's answer, to which using Patternizer will still add automatic generation of the SVG and an invisible HTML element on top that allows text selection and copying.
  • Or use automatic alignment of the pattern image. Can be done with JavaScript code similar to the one in Gijs's answer.

Solution 10 - Css

You can use an inverted / negative / reverse font and apply it with the font-face="ā€¦" CSS rule. You might have to play with letter spacing to avoid small white gaps between letters.

If you do not require a specific font, it's simple. Download a likeable one, for example from this collection of inverted fonts.

If you require a specific font (say, "Open Sans"), it's difficult. You have to convert your existing font into an inverted version. This is possible manually with Font Creator, FontForge etc., but of course we want an automated solution. I could not find instructions for that yet, but some hints:

Solution 11 - Css

Demo Screenshot

I needed to make text that looked exactly like it does in the original post, but I couldn't just fake it by lining up backgrounds, because there's some animation behind the element. Nobody seems to have suggested this yet, so here's what I did: (Tried to make it as easy to read as possible.)

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;
}

Just throw that in your window.onload, set the body's background to your image, and watch the magic happen!

Solution 12 - Css

mix-blend-mode is also a possibility for that kind of effect . >The mix-blend-mode CSS property sets how an element's content should blend with the content of the element's parent and the element's background.

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}

<h1>ABCDEFGHIJKLMNOPQRSTUVWXYZ</h1>

Solution 13 - Css

This worked for me mix-blend-mode: color-dodge on the container with opposite colors.

.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>

Solution 14 - Css

Not possible with CSS just now I'm afraid.

Your best bet is to simply use an image (probably a PNG) and and place good alt/title text on it.

Alternatively you could use a SPAN or a DIV and have the image as a background to that with your text you want for SEO purposes inside it but text-indent it off screen.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLove DagerView Question on Stackoverflow
Solution 1 - CssGijsView Answer on Stackoverflow
Solution 2 - Cssweb-tikiView Answer on Stackoverflow
Solution 3 - CssNicView Answer on Stackoverflow
Solution 4 - CssKyleView Answer on Stackoverflow
Solution 5 - CssRashedView Answer on Stackoverflow
Solution 6 - CssAndriaView Answer on Stackoverflow
Solution 7 - CssTemani AfifView Answer on Stackoverflow
Solution 8 - CssfeeelaView Answer on Stackoverflow
Solution 9 - CsstaniusView Answer on Stackoverflow
Solution 10 - CsstaniusView Answer on Stackoverflow
Solution 11 - CssPecacheuView Answer on Stackoverflow
Solution 12 - CssG-CyrillusView Answer on Stackoverflow
Solution 13 - Csscozmik05View Answer on Stackoverflow
Solution 14 - CssBilly MoatView Answer on Stackoverflow