By Love Dager


2012-12-18 12:24:09 8 Comments

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

11 comments

@Gijs 2012-12-18 12:49:35

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 automatic:

$(document).ready(function(){
  var position = $("h1").position(); //Position of the header in the webpage
  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/

@Gijs 2012-12-18 12:53:35

A you people are TOO fast :D

@Love Dager 2012-12-18 13:26:45

Oh great! I will test the auto alignment as fast as I get home! Thank you! :D

@Gijs 2012-12-18 13:32:26

you maby need to alter the code a bit, depends on the situation, now it could conflict with other elements and this one was written really fast, if you have any questions i will hear them

@Love Dager 2012-12-18 22:38:16

Yeah sure, but I know jQuery like the palm of my hand (okay.. let's say almost). I will probably make a nifty little plugin for it! Also thank you, marked as correct!

@tanius 2015-10-17 14:49:07

Not to disregard the answer, which is a really nice solution, but background-clip:text is a Webkit-only, non-standard option. CSS3 does not allow the text value for this attribute (see).

@larpo 2016-10-14 11:08:48

Confirmed that this unfortunately does not work in firefox

@Vince 2017-02-20 04:06:17

This technique allows you to see the background of the element where the text would normally be. I'm looking for a way to see what's under the element with the text through the place where the text would normally be.

@wizzwizz4 2018-10-20 13:47:37

@larpo Works in my Firefox... Perhaps the standard's changed?

@Pecacheu 2016-11-23 08:34:21

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!

@ChrisBrownie55 2018-01-10 06:30:44

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>

@Rashed 2017-09-22 06:29:32

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;

    }

@web-tiki 2015-04-20 12:18:52

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>

@Timo Kähkönen 2015-04-27 21:18:11

This seems to be the only solution which works cross browser today: IE11, FF, Chrome, Safari. And doesn't need image as a background as many other solutions provided to the problem all around the web.

@Timo Kähkönen 2015-04-27 21:53:26

Inspired from this answer I made a keyframes animation, where transparent SVG-text on white rounded rectangle rotates. The background has text and images. Go and see: jsbin.com/nipuqu/3 (The World championship is coming:))

@Kaiido 2016-01-22 11:49:26

Nice solution, but since "select text and search on page" seem to be in OP's requirements, you may want to include the <text> outside of the <defs> part. (btw I'm not sure how SE crawlers do deal with SVG content in defs). Here is a way to keep what OP wants, with an horrible FF bug exploit : jsfiddle.net/tfneqxxb

@Imran Bughio 2016-04-11 07:29:54

What if the text is dynamic? It dosesn't auto adjust the width.

@web-tiki 2016-04-11 12:40:16

@ImranBughio no it doesn't. SVG text doesn't act like plain HTML text. You nee to position it . For more in for info see here

@limeandcoconut 2017-03-09 17:27:57

This should be the accepted answer

@Nic 2016-01-30 22:27:15

One way that works on most modern browsers (except ie, edge), although only with a black background, is to use

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

in 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. http://codepen.io/nic_klaassen/full/adKqWX/

@Imran Bughio 2016-04-11 07:36:52

For white background with black color use color-dodge , lighten or screen on mix-blend-mode

@tanius 2015-10-17 15:05:47

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.

@tanius 2015-10-17 15:23:47

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:

@Kyle 2012-12-18 12:37:43

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/

@Love Dager 2012-12-18 12:47:28

Cool trick! But now to align everything properly will be a bitch.. -.-

@Kyle 2012-12-18 12:48:13

Yeah, that's another problem with it. It's still in development and I sincerely hope we see something like this soon! :)

@Kyle 2012-12-18 12:56:27

Also, you can always layer over transparent text on the image, so that it's still selectable. But I am sure that it's bad practice for SEO.. Hidden messages/keywords and such.

@Gijs 2012-12-18 13:11:41

aligned the easy way jsfiddle.net/BWRsA/2

@cimmanon 2012-12-18 13:45:21

I am sure it is looks very nice in Webkit browsers, but for everyone else it is a semi-transparent white box on top of some grass.

@Kyle 2012-12-18 13:46:55

That's why I said it only works in webkit....

@cimmanon 2012-12-18 13:54:43

Without a graceful fallback, this is 100% useless in production. It's not like box-shadow or border-radius where if the browser doesn't support those properties the page is still usable, it just doesn't look as pretty. That's not the case with this property.

@Kyle 2012-12-18 13:57:51

The OP's question was "is it possible." Yes, it is. In Webkit browsers only. It is in development and I hope it becomes a standard feature sometime. But to use this in production would not be a great idea.

@cimmanon 2012-12-18 14:02:29

The fact that he is worried about SEO implies that his plan is to use it in production. There's also a large number of designers out there who think Webkit is the only browser that matters: glazman.org/weblog/dotclear/index.php?post/2012/02/09/…

@Kyle 2012-12-18 14:09:15

Aye. It may have most of the market share, but there are still millions of users using other browsers, it's folly to only support one.

@Love Dager 2012-12-18 22:41:25

Ah, come on guys... Yes I plan on using it in production. But of course not without a fallback! @cimmanon

@feeela 2012-12-18 12:37:08

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
(Webkit only, I don't know yet how to change the black background to a white one)

@Love Dager 2012-12-18 12:48:08

Yeah, that might work! Thanks, now to align everything correctly.. Damn.. -.-

@Billy Moat 2012-12-18 12:27:11

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.

@Love Dager 2012-12-18 12:46:12

Yeah, you're right. I could probably use images without losing SEO points, but you can't still select text, search on page, linking will be more complicated, and it will be a lot more work to update the text... :/

Related Questions

Sponsored Content

30 Answered Questions

[SOLVED] Hide text using css

  • 2009-01-23 01:19:06
  • Micah
  • 595554 View
  • 296 Score
  • 30 Answer
  • Tags:   css

21 Answered Questions

[SOLVED] Vertically align text next to an image?

42 Answered Questions

[SOLVED] How to disable text selection highlighting

16 Answered Questions

28 Answered Questions

[SOLVED] How do I give text or an image a transparent background using CSS?

  • 2009-04-30 09:00:02
  • Stijn Sanders
  • 1512089 View
  • 2206 Score
  • 28 Answer
  • Tags:   html css opacity

15 Answered Questions

[SOLVED] Replacing H1 text with a logo image: best method for SEO and accessibility?

  • 2009-03-20 04:57:45
  • Andrew
  • 218143 View
  • 232 Score
  • 15 Answer
  • Tags:   css xhtml image seo

2 Answered Questions

[SOLVED] transparent strikethrought on text

Sponsored Content