SVG embutido em CSS

283

É possível usar uma definição SVG embutida em CSS?

Quero dizer algo como:

.my-class {
  background-image: <svg>...</svg>;
}
akaRem
fonte
1
O que você está tentando fazer, adicione a imagem "source" à folha de estilos?
Zuul
1
Cuidado com que as soluções propostas não vai funcionar para imagens CSS, HTML <img>tags e outros casos, se o SVG é uma mistura de várias imagens (a não ser incorporado), consulte SVG imagem de fundo com máscara usando imagem externa não está funcionando , e, especificamente, restrições à SVG usado como uma imagem .
Skippy le Grand Gourou

Respostas:

375

Sim, é possível. Tente o seguinte:

body { background-image: 
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='%23F00'/><stop offset='90%' stop-color='%23fcc'/> </linearGradient><rect fill='url(%23gradient)' x='0' y='0' width='100%' height='100%'/></svg>");
      }

(Observe que o conteúdo SVG precisa ser escapado por URL para que isso funcione, por exemplo, #é substituído por %23.)

Isso funciona no IE 9 (que suporta SVG) . Os URLs de dados também funcionam em versões mais antigas do IE (com limitações), mas não oferecem suporte nativo ao SVG.

Raab
fonte
8
O único navegador em que parece funcionar bem é o Safari (5.1.4). No Opera 11.62, o gradiente é preto, no IE 9 e Firefox 12, branco. No Chrome 19, ele funciona, a menos que você especifique a largura / altura do SVG em% de unidades. Eu diria que é mais uma esquisitice do que uma característica real. É uma descoberta legal embora.
toniedzwiedz
4
Certo ... ainda estou ansioso para ver os rostos dos meus colegas de trabalho quando mostro a eles um monstrinho fofo como esse, então obrigado novamente por mostrar que é possível. Eu só fui para a especificação padrão e afirmou que era praticamente impossível, o que acabou por ser um erro (tipo de)
toniedzwiedz
18
A "incompatibilidade do navegador" aqui é basicamente apenas uma falta de escape de URL adequado; tudo dentro url()deve ser escapado por URL. Veja jsfiddle.net/6WAtQ para um exemplo que funciona bem no Opera, Firefox e Safari.
Erik Dahlström
3
Existe alguma diferença de compatibilidade entre svg codificado em base64 e não-base64? Base64 bloats meu arquivo css, eu estou pensando em só usar SVGs em linha ..
enapupe
4
Observe que a maneira padrão de especificar o conjunto de caracteres é "; charset = UTF-8" em vez de "; utf8". tools.ietf.org/html/rfc2397
Keith Shaw
240

Um pouco tarde, mas se algum de vocês estiver ficando louco tentando usar o SVG embutido como pano de fundo , as sugestões de escape acima não funcionam. Por um lado, ele não funciona no IE e, dependendo do conteúdo do seu SVG, a técnica causará problemas em outros navegadores, como o FF.

Se você base64 codificar o svg (não o URL inteiro, apenas a tag svg e seu conteúdo!), Ele funcionará em todos os navegadores. Aqui está o mesmo exemplo do jsfiddle em base64: http://jsfiddle.net/vPA9z/3/

O CSS agora se parece com isso:

body { background-image: 
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxMCcgaGVpZ2h0PScxMCc+PGxpbmVhckdyYWRpZW50IGlkPSdncmFkaWVudCc+PHN0b3Agb2Zmc2V0PScxMCUnIHN0b3AtY29sb3I9JyNGMDAnLz48c3RvcCBvZmZzZXQ9JzkwJScgc3RvcC1jb2xvcj0nI2ZjYycvPiA8L2xpbmVhckdyYWRpZW50PjxyZWN0IGZpbGw9J3VybCgjZ3JhZGllbnQpJyB4PScwJyB5PScwJyB3aWR0aD0nMTAwJScgaGVpZ2h0PScxMDAlJy8+PC9zdmc+");

Lembre-se de remover qualquer URL que escape antes de converter para base64. Em outras palavras, o exemplo acima mostrou color = '# fcc' convertido em color = '% 23fcc', você deve voltar para #.

O motivo pelo qual o base64 funciona melhor é que elimina todos os problemas com aspas simples e duplas e escape de URL

Se você estiver usando JS, poderá window.btoa()produzir sua base64 svg; e se não funcionar (pode se queixar de caracteres inválidos na string), você pode simplesmente usar https://www.base64encode.org/ .

Exemplo para definir um fundo div:

var mySVG = "<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='#F00'/><stop offset='90%' stop-color='#fcc'/> </linearGradient><rect fill='url(#gradient)' x='0' y='0' width='100%' height='100%'/></svg>";
var mySVG64 = window.btoa(mySVG);
document.getElementById('myDiv').style.backgroundImage = "url('data:image/svg+xml;base64," + mySVG64 + "')";
html, body, #myDiv {
  width: 100%;
  height: 100%;
  margin: 0;
}
<div id="myDiv"></div>

Com o JS, você pode gerar SVGs dinamicamente, alterando até seus parâmetros.

Um dos melhores artigos sobre o uso do SVG está aqui: http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

Espero que isto ajude

Mike

Mike Tommasi
fonte
2
Obrigado cara. A solução com o Base64 funcionou excelente, enquanto eu tive problemas com a resposta aceita.
Marcel
1
Você salvou minha vida. Eu tinha uma imagem de borda SVG que estava funcionando no chrome, mas não no FF. Agora funciona! : D
Papipo 19/11/2014
Também me ajudou (depois de perder tempo tentando a resposta aceita) - essa definitivamente deveria ser a resposta aceita.
21416 Katai
Se isso ainda não estiver funcionando para você - certifique-se de ter um xmlnsatributo definido como svgelemento antes de codificar como base64, como <svg xmlns="http://www.w3.org/2000/svg">...</svg>navegadores às vezes o fazem sem o código quando o svg estiver diretamente em HTML - este não é o caso :)
jave.web
Caso alguém ainda esteja olhando para essa resposta 6 anos ou mais depois: Você provavelmente não deve basear
Volker E.
38

Para as pessoas que ainda estão com dificuldades, consegui fazer isso funcionar em todos os navegadores modernos IE11 e superiores.

base64 não era uma opção para mim, porque eu queria usar o SASS para gerar ícones SVG com base em qualquer cor. Por exemplo: @include svg_icon(heart, #FF0000);Dessa forma, posso criar um determinado ícone em qualquer cor e só tenho que incorporar a forma SVG uma vez no CSS. (com base64, você teria que incorporar o SVG em todas as cores que deseja usar)

Você precisa estar ciente de três coisas:

  1. URL codifique seu SVG Como outros sugeriram, você precisa codificar por URL toda a sua sequência SVG para que ela funcione no IE11. No meu caso, eu deixei de fora os valores de cor em áreas como fill="#00FF00"e stroke="#FF0000"e substituiu-os com uma variável SASS fill="#{$color-rgb}"assim que estes podem ser substituídos com a cor que eu quero. Você pode usar qualquer conversor online para codificar por URL o restante da string. Você terminará com uma sequência SVG assim:

    % 3Csvg% 20xmlns% 3D% 27http% 3A% 2F% 2Fwww.w3.org% 2F2000% 2Fsvg% 27% 20viewBox% 3D% 270% 200% 20494,572% 20494,572% 27% 20% 3D% 27512% 27% 20% de altura 3D % 27512% 27% 3E% 0A% 20% 20% 3Cpath% 20d% 3D% 27M257,063% 200C127.136% 200% 2021.808% 20105.33% 2021.808% 20235.266c0% 2041.012% 2010.535% 2079.541% 2028.973% 20113.104L3.825 % 20464.586c345% 2012.797% 2041.813% 2012.797% 2015.467% 200% 2029.872-4.721% 2041.813-12.797v158.184z% 27% 20fill% 3D% 27 # {$ color-rgb} % 27% 2F% 3E% 3C% 2Fsvg% 3E


  1. OMITAR O CHARSET UTF8 NO URL DE DADOS Ao criar seu URL de dados, é necessário deixar de fora o conjunto de caracteres para que ele funcione no IE11.

    NÃO imagem de fundo: url (dados: imagem / svg + xml; utf-8,% 3Csvg% 2 ....)
    MAS imagem de fundo: url (dados: imagem / svg + xml,% 3Csvg% 2 ... .)


  1. USE cores RGB () EM VEZ DE HEX O Firefox não gosta de # no código SVG. Portanto, você precisa substituir os valores hexadecimais da cor pelos RGB.

    NÃO preencher = "# FF0000"
    MAS preencher = "rgb (255,0,0)"

No meu caso, uso o SASS para converter um dado hexadecimal em um valor válido de rgb. Conforme indicado nos comentários, é melhor codificar por URL sua string RGB também (para que a vírgula se torne% 2C)

@mixin svg_icon($id, $color) {
   $color-rgb: "rgb(" + red($color) + "%2C" + green($color) + "%2C" + blue($color) + ")";
   @if $id == heart {
      background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%20494.572%20494.572%27%20width%3D%27512%27%20height%3D%27512%27%3E%0A%20%20%3Cpath%20d%3D%27M257.063%200C127.136%200%2021.808%20105.33%2021.808%20235.266c0%204%27%20fill%3D%27#{$color-rgb}%27%2F%3E%3C%2Fsvg%3E');
   }
}

Sei que essa pode não ser a melhor solução para SVGs muito complexos (o SVG embutido nunca é o caso), mas para ícones planos com apenas algumas cores, isso realmente funciona muito bem.

Consegui deixar de fora um bitmap de sprite inteiro e substituí-lo por SVG embutido no meu CSS, que acabou por ficar em torno de 25kb após a compactação. Portanto, é uma ótima maneira de limitar a quantidade de solicitações que o site precisa fazer, sem inchar o arquivo CSS.

Davy Baert
fonte
1
Btw, corrija-me se eu estiver errado, mas rgb(255,0,0)deve ser rgb(255%2C0%2C0)codificado uma vez.
Capsule
1
Eu quis dizer que não codifico a string RGB e ainda funciona. Mas codificá-lo como você mencionou é provavelmente melhor.
Davy Baert
1
Bem, na verdade, eu só testado e %23ff0000funciona bem para #ff0000no Firefox
Capsule
1
@ Cápsula Não sei o que está acontecendo, mas o% 23ff0000 é o ÚNICO método que funciona para mim no Chrome e no FF. # ff0000 não funciona, nem os métodos RGB (255,0,0) e rgb (255% 2C0% 2C0).
Ideogram
1
Um método (incluindo código SCSS) que requer menos codificação: codepen.io/jakob-e/pen/doMoML
Sphinxxx
26

No Mac / Linux, você pode converter facilmente um arquivo SVG em um valor codificado em base64 para o atributo de plano de fundo CSS com este comando simples do bash:

echo "background: transparent url('data:image/svg+xml;base64,"$(openssl base64 < path/to/file.svg)"') no-repeat center center;"

Testado no Mac OS X. Dessa forma, você também evita a confusão da URL.

Lembre-se de que a base64 que codifica um arquivo SVG aumenta seu tamanho, consulte a publicação no blog css-tricks.com .

araks
fonte
2
Para os leitores: por favor, comente sua opinião em vez de apenas votar, para que esta resposta possa ser melhorada com sua colaboração! A colaboração é essencial em sites de perguntas e respostas como essa. Obrigado!
precisa saber é
2
@LorDex o link fornecido em seu comentário é o mesmo que está na minha resposta :)
Araks
10

Garfoi uma demonstração do CodePen que teve o mesmo problema ao incorporar SVG embutido no CSS. Uma solução que funciona com o SCSS é criar uma função simples de codificação de URL.

Uma função de substituição de string pode ser criada a partir das funções internas de str-slice e str-index (consulte CSS-Tricks , graças a Hugo Giraudel).

Em seguida, basta substituir %, <, >, ", ', com os %xxcódigos:

@function svg-inline($string){
  $result: str-replace($string, "<svg", "<svg xmlns='http://www.w3.org/2000/svg'");
  $result: str-replace($result, '%', '%25');
  $result: str-replace($result, '"', '%22');
  $result: str-replace($result, "'", '%27');
  $result: str-replace($result, ' ', '%20');
  $result: str-replace($result, '<', '%3C');
  $result: str-replace($result, '>', '%3E');
  @return "data:image/svg+xml;utf8," + $result;
}

$mySVG: svg-inline("<svg>...</svg>");

html {
  height: 100vh;
  background: url($mySVG) 50% no-repeat;
}

Também existe uma image-inlinefunção auxiliar disponível no Compass, mas como ela não é suportada no CodePen, essa solução provavelmente pode ser útil.

Demonstração no CodePen: http://codepen.io/terabaud/details/PZdaJo/

Lea Rosema
fonte
1
Também criei uma caneta que permite converter seqüências de caracteres svg em um valor de fundo css adequado: s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb Então, basicamente, cole-a <svg><path></svg>na área de texto superior e ela produzirá diretamente o caminho higienizado dentro de um url()valor.
LukyVj
1
Isso funcionou demais. Obrigado. Uma nota. Você precisa usar; charset = utf8 para que isso funcione no IE.
Daniel Lefebvre
4

SVG embutido proveniente de fontes de terceiros (como gráficos do Google) pode não conter o atributo de espaço para nome XML (xmlns="http://www.w3.org/2000/svg" ) no elemento SVG (ou talvez seja removido depois que o SVG é renderizado - nem o inspetor do navegador nem os comandos jQuery do console do navegador mostram o espaço para nome no elemento SVG).

Quando você precisar redefinir esses trechos svg para suas outras necessidades (imagem de plano de fundo em CSS ou elemento img em HTML), observe o espaço para nome ausente. Sem o namespace, os navegadores podem se recusar a exibir SVG (independentemente da codificação utf8 ou base64).

mp31415
fonte
4

Encontrei uma solução para SVG. Mas é trabalho apenas para o Webkit, eu só quero compartilhar minha solução alternativa com você. No meu exemplo é mostrado como usar o elemento SVG do DOM como plano de fundo através de um filtro (background-image: url ('# glyph') não está funcionando).

Recursos necessários para a renderização deste ícone SVG:

  1. Aplicando efeitos de filtro SVG a elementos HTML usando CSS (o IE e o Edge não são compatíveis)
  2. Suporte ao carregamento de fragmento feImage (o Firefox não suporta)

.test {
  /*  background-image: url('#glyph');
    background-size:100% 100%;*/
    filter: url(#image); 
    height:100px;
    width:100px;
}
.test:before {
   display:block;
   content:'';
   color:transparent;
}
.test2{
  width:100px;
  height:100px;
}
.test2:before {
   display:block;
   content:'';
   color:transparent;
   filter: url(#image); 
   height:100px;
   width:100px;
}
<svg style="height:0;width:0;" version="1.1" viewbox="0 0 100 100"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
 <defs>
     <g id="glyph">
          <path id="heart" d="M100 34.976c0 8.434-3.635 16.019-9.423 21.274h0.048l-31.25 31.25c-3.125 3.125-6.25 6.25-9.375 6.25s-6.25-3.125-9.375-6.25l-31.202-31.25c-5.788-5.255-9.423-12.84-9.423-21.274 0-15.865 12.861-28.726 28.726-28.726 8.434 0 16.019 3.635 21.274 9.423 5.255-5.788 12.84-9.423 21.274-9.423 15.865 0 28.726 12.861 28.726 28.726z" fill="crimson"/>
     </g>
    <svg id="resized-glyph"  x="0%" y="0%" width="24" height="24" viewBox="0 0 100 100" class="icon shape-codepen">
      <use xlink:href="#glyph"></use>
    </svg>
     <filter id="image">
       <feImage xlink:href="#resized-glyph" x="0%" y="0%" width="100%" height="100%" result="res"/>
       <feComposite operator="over" in="res" in2="SourceGraphic"/>
    </filter>
 </defs>
</svg>
<div class="test">
</div>
<div class="test2">
</div>

Mais uma solução, é usar codificação de URL

var container = document.querySelector(".container");
var svg = document.querySelector("svg");
var svgText = (new XMLSerializer()).serializeToString(svg);
container.style.backgroundImage = `url(data:image/svg+xml;utf8,${encodeURIComponent(svgText)})`;
.container{
  height:50px;
  width:250px;
  display:block;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: contain;
}
<svg  height="100" width="500" xmlns="http://www.w3.org/2000/svg">
    <ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" />
</svg>
<div class="container"></div>

Alex Nikulin
fonte