Texto transparente cortado do fundo

90

Existe alguma maneira de fazer um corte de texto transparente de um efeito de fundo como o da imagem a seguir, com CSS?
Seria triste perder todo o SEO precioso por causa das imagens substituindo o texto.

Texto transparente cortado do fundo

Primeiro pensei em sombras, mas não consigo descobrir nada ...

A imagem é o fundo do site, uma <img>tag posicionada de forma absoluta

Love Dager
fonte
"perder todo o SEO precioso por causa das imagens substituindo o texto." Também existem técnicas de substituição de imagens, que ainda são TÃO amigáveis. BTW: na verdade, o fundo por trás das letras também precisa ficar transparente, que é o problema aqui ...
feeela
sim, isso seria uma ótima prática, se possível com css ...
Jessica Lingmn
Não vejo razão para <h1><img alt="Some Text" /></h1>ser menos amigável do que SEO <h1>Some Text</h1>. Tradicionalmente, o problema com as imagens é que elas acabam de ser despejadas na página sem nenhuma marcação de suporte.
cimmanon
@cimmanon Sim, você está certo. Provavelmente poderia usar imagens sem perder pontos de SEO, mas você ainda não consegue selecionar o texto, pesquisar na página, a vinculação será mais complicada e será muito mais trabalhoso atualizar o texto ...: /
Love Dager
2
Só para você saber, o Google é totalmente legal com técnicas de substituição de imagens CSS: mezzoblue.com/archives/2008/05/05/image_replac
cimmanon

Respostas:

46

É possível com css3, mas não é compatível com todos os navegadores

Com fundo-clipe: texto; você pode usar um fundo para o texto, mas você terá que alinhá-lo com o fundo da página

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/


Alinhamento Automático

Com um pouco de javascript, você pode alinhar o fundo automaticamente:

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

Gijs
fonte
R vocês são MUITO rápidos: D
Gijs
Oh ótimo! Vou testar o alinhamento automático assim que chegar em casa! Obrigado! : D
Love Dager
você maby precisa alterar um pouco o código, depende da situação, agora pode entrar em conflito com outros elementos e este foi escrito muito rápido, se você tiver alguma dúvida eu irei ouvi-los
Gijs
3
Sem querer desconsiderar a resposta, que é uma solução muito boa, mas background-clip:texté uma opção fora do padrão apenas para Webkit. CSS3 não permite o textvalor para este atributo ( consulte ).
tanius,
1
Esta técnica permite que você veja o fundo do elemento onde o texto normalmente estaria. Estou procurando uma maneira de ver o que está sob o elemento com o texto através do local onde o texto normalmente estaria.
Vince de
49

Embora isso seja possível com CSS, uma abordagem melhor seria usar um SVG embutido com máscara SVG . Essa abordagem tem algumas vantagens sobre CSS:

CodePen Demo: máscara de texto SVG

fundo de recorte de texto transparente

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>

Se você deseja tornar o texto selecionável e pesquisável, você precisa incluí-lo fora da <defs>tag. O exemplo a seguir mostra uma maneira de fazer isso mantendo o texto transparente com a <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>

web-tiki
fonte
2
Esta parece ser a única solução que funciona em vários navegadores hoje: IE11, FF, Chrome, Safari. E não precisa de imagem como pano de fundo como muitas outras soluções fornecidas para o problema em toda a web.
Timo Kähkönen
1
Inspirado nessa resposta, fiz uma animação de quadros-chave, em que o texto SVG transparente em um retângulo arredondado branco gira. O fundo contém texto e imagens. Vá e veja: jsbin.com/nipuqu/3 (O campeonato mundial está chegando :))
Timo Kähkönen
2
Boa solução, mas como "selecionar texto e pesquisar na página" parece estar nos requisitos do OP, você pode querer incluir o <text>lado externo da <defs>peça. (aliás, não tenho certeza de como os rastreadores SE lidam com o conteúdo SVG em defs). Aqui está uma maneira de manter o que o OP deseja, com um terrível exploit de bug do FF: jsfiddle.net/tfneqxxb
Kaiido
E se o texto for dinâmico? Ele não ajusta automaticamente a largura.
Imran Bughio
1
@ImranBughio não, não importa. O texto SVG não funciona como texto HTML simples. Você precisa posicioná-lo. Para mais informações, consulte aqui
web-tiki
16

Uma maneira que funciona na maioria dos navegadores modernos (exceto isto é, borda), embora apenas com um fundo preto, é usar

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

em seu elemento de texto e, em seguida, coloque o plano de fundo desejado atrás dele. Multiply mapeia basicamente o código de cor 0-255 para 0-1 e então multiplica isso pelo que quer que esteja por trás dele, então o preto permanece preto e o branco multiplica por 1 e efetivamente se torna transparente. http://codepen.io/nic_klaassen/full/adKqWX/

Nic
fonte
3
Para fundo branco com cor preta color-dodge, use lightenou screenonmix-blend-mode
Imran Bughio
3

Ele é possível, mas até agora apenas com os navegadores Webkit base (Chrome, Safari, RockMelt, qualquer coisa com base no projeto Chromium.)

O truque é ter um elemento dentro do branco que tenha o mesmo fundo que o corpo, então usar -webkit- background-clip: text;no elemento interno que basicamente significa "não estenda o fundo além do texto" e use texto transparente.

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/

Kyle
fonte
Truque legal! Mas agora para alinhar tudo corretamente vai ser uma merda .. -.-
Love Dager 18/12/12
Sim, esse é outro problema com isso. Ainda está em desenvolvimento e espero sinceramente que vejamos algo assim em breve! :)
Kyle
Além disso, você sempre pode colocar uma camada sobre o texto transparente na imagem, de modo que ainda seja selecionável. Mas tenho certeza que é uma má prática para SEO .. Mensagens / palavras-chave escondidas e tal.
Kyle
Tenho certeza de que parece muito bom em navegadores Webkit, mas para todos os outros é uma caixa branca semitransparente em cima de um pouco de grama.
cimmanon
1
Ah, vamos lá pessoal ... Sim, pretendo usá-lo na produção. Mas é claro que não sem um retrocesso! @cimmanon
Love Dager
2

Acabei de descobrir uma nova maneira de fazer isso brincando, não tenho certeza de como funciona (se alguém quiser explicar, por favor, faça).

Parece funcionar muito bem e não requer fundos duplos ou JavaScript.

Aqui está o código: 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>

ChrisBrownie55
fonte
1

Você pode usar uma fonte invertida / negativa / reversa e aplicá-la com a font-face="…"regra CSS. Você pode ter que brincar com o espaçamento das letras para evitar pequenos espaços brancos entre as letras.

Se você não precisa de uma fonte específica, é simples. Baixe um agradável, por exemplo, desta coleção de fontes invertidas .

Se você precisar de uma fonte específica (por exemplo, "Open Sans"), é difícil. Você deve converter sua fonte existente em uma versão invertida. Isso é possível manualmente com Font Creator, FontForge etc., mas é claro que queremos uma solução automatizada. Ainda não consegui encontrar instruções para isso, mas algumas dicas:

Tanius
fonte
1

Você pode usar o plugin jQuery Patternizer de myadzel para obter esse efeito em vários navegadores. No momento, não existe uma maneira entre navegadores de fazer isso apenas com CSS.

Você usa o Patternizer adicionando class="background-clip"elementos HTML onde deseja que o texto seja pintado como um padrão de imagem e especifica a imagem em um data-pattern="…"atributo adicional . Veja a fonte da demonstração . O Patternizer criará uma imagem SVG com texto preenchido com padrão e a subirá ao elemento HTML renderizado de forma transparente.

Se, como na imagem de exemplo da pergunta, o padrão de preenchimento do texto deve ser parte de uma imagem de fundo que se estende além do elemento "padronizado", vejo duas opções (não testado, meu favorito primeiro):

  • Use o mascaramento em vez de uma imagem de fundo no SVG. Como na resposta do web-tiki , ao qual usar o Patternizer ainda adicionará a geração automática do SVG e um elemento HTML invisível no topo que permite a seleção e cópia do texto.
  • Ou use o alinhamento automático da imagem do padrão. Pode ser feito com código JavaScript semelhante ao da resposta de Gijs .
Tanius
fonte
1

basta colocar esse 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;

    }
Rashed
fonte
1

Captura de tela de demonstração

Eu precisava fazer um texto que se parecesse exatamente com o da postagem original, mas não poderia simplesmente fingir alinhando fundos, porque há alguma animação por trás do elemento. Ninguém parece ter sugerido isso ainda, então aqui está o que eu fiz: (tentei tornar a leitura o mais fácil possível).

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

Basta jogá-lo em sua janela.onload, definir o plano de fundo do corpo de acordo com sua imagem e assistir a mágica acontecer!

Pecacheu
fonte
0

Não é possível com CSS agora, infelizmente.

Sua melhor aposta é simplesmente usar uma imagem (provavelmente um PNG) e colocar um bom texto alt / título nela.

Alternativamente, você pode usar um SPAN ou um DIV e ter a imagem como plano de fundo com o texto que deseja para fins de SEO dentro dele, mas com recuo de texto fora da tela.

Billy Moat
fonte
Sim você está certo. Provavelmente poderia usar imagens sem perder pontos de SEO, mas você ainda não consegue selecionar o texto, pesquisar na página, os links serão mais complicados e será muito mais trabalhoso atualizar o texto ...: /
Love Dager
0

mix-blend-mode também é uma possibilidade para esse tipo de efeito.

A mix-blend-modepropriedade CSS define como o conteúdo de um elemento deve se misturar com o conteúdo do pai do elemento e do plano de fundo do elemento.

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>

G-Cyrillus
fonte