web-dev-qa-db-fra.com

SVG en ligne en CSS

Est-il possible d'utiliser une définition SVG intégrée dans CSS?

Je veux dire quelque chose comme:

.my-class {
  background-image: <svg>...</svg>;
}
238
akaRem

Oui c'est possible. Essaye ça:

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

(Notez que le contenu SVG doit être échappé par une URL pour que cela fonctionne. Par exemple, # est remplacé par %23.)

Cela fonctionne dans IE 9 (qui supporte SVG) . Les URL de données fonctionnent également dans les anciennes versions de IE (avec certaines limitations), mais elles ne prennent pas en charge de manière native le SVG.

317
Raab

Un peu tard, mais si certains d'entre vous sont devenus fous en essayant d'utiliser SVG en ligne comme arrière-plan , les suggestions ci-dessus ne fonctionnent pas tout à fait. D'une part, cela ne fonctionne pas dans IE et, en fonction du contenu de votre SVG, cette technique peut poser problème dans les autres navigateurs, comme FF.

Si vous encodez le svg en base64 (pas l’URL complète, mais uniquement la balise svg et son contenu!), Cela fonctionne dans tous les navigateurs. Voici le même exemple jsfiddle en base64: http://jsfiddle.net/vPA9z/3/

Le CSS ressemble maintenant à ceci:

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

N'oubliez pas de supprimer toute URL échappée avant de convertir en base64. En d'autres termes, l'exemple ci-dessus montre que color = '# fcc' est converti en color = '% 23fcc', vous devez donc revenir à #.

La raison pour laquelle base64 fonctionne mieux est qu’elle élimine tous les problèmes de guillemets simples et doubles et d’échappements d’URL.

Si vous utilisez JS, vous pouvez utiliser window.btoa() pour produire votre base64 svg; et si cela ne fonctionne pas (il peut se plaindre de caractères non valides dans la chaîne), vous pouvez simplement utiliser https://www.base64encode.org/ .

Exemple pour définir un arrière-plan 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>

Avec JS, vous pouvez générer des SVG à la volée, même en modifiant ses paramètres.

L'un des meilleurs articles sur l'utilisation de SVG est ici: http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/

J'espère que cela t'aides

Mike

207
Mike Tommasi

Pour les personnes qui luttent encore, j'ai réussi à ce que cela fonctionne sur tous les navigateurs modernes IE11 et plus.

base64 n'était pas une option pour moi parce que je voulais utiliser SASS pour générer des icônes SVG basées sur une couleur donnée. Par exemple: @include svg_icon(heart, #FF0000); De cette façon, je peux créer une certaine icône dans n'importe quelle couleur et ne devoir incorporer qu'une seule fois la forme SVG dans le CSS. (avec base64 vous devez intégrer le SVG dans chaque couleur que vous souhaitez utiliser)

Vous devez être conscient de trois choses:

  1. URL ENCODEZ VOTRE SVG Comme d'autres l'ont suggéré, vous devez encoder l'URL de votre chaîne SVG entière pour qu'elle fonctionne dans IE11. Dans mon cas, j'ai omis les valeurs de couleur dans des champs tels que fill="#00FF00" et stroke="#FF0000" et les ai remplacées par une variable SASS fill="#{$color-rgb}" afin qu'elles puissent être remplacées par la couleur souhaitée. Vous pouvez utiliser tout convertisseur en ligne pour encoder le reste de la chaîne dans une URL. Vous allez vous retrouver avec une chaîne SVG comme celle-ci:

    % 3Csvg% 20xmlns% 3D% 27http% 3A% 2F% 2Fwww.w3.org% 2F2000% 2Fsvg% 27% 20viewBox% 3D% 270% 200% 20494.572% 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% 2041.012% 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. OMIT LE CHARS UTF8 DANS L'URL DE DONNÉES Lorsque vous créez votre URL de données, vous devez omettre le jeu de caractères pour qu'il puisse fonctionner dans IE11.

    PAS image d'arrière-plan: url (données: image/svg + xml; utf-8,% 3Csvg% 2 ....)
    MAIS image d'arrière-plan: url (données: image/svg + xml,% 3Csvg% 2 ....)


  1. UTILISEZ LES COULEURS RGB () AU LIEU DE HEX Firefox n'aime pas # dans le code SVG. Vous devez donc remplacer vos valeurs hexadécimales de couleur par des valeurs RVB.

    PAS remplir = "# FF0000"
    MAIS fill = "rgb (255,0,0)"

Dans mon cas, j'utilise SASS pour convertir un hex donné en une valeur rgb valide. Comme indiqué dans les commentaires, il est préférable de coder également votre chaîne RVB par une adresse URL (la virgule devient alors% 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');
   }
}

Je me rends compte que ce n'est peut-être pas la meilleure solution pour les SVG très complexes (les SVG en ligne ne le sont jamais), mais pour les icônes plates avec seulement quelques couleurs, cela fonctionne vraiment bien.

J'ai pu omettre un bitmap entier de Sprite et le remplacer par du SVG intégré dans mon CSS, ce qui s'est avéré ne représenter que 25 Ko environ après compression. C'est donc un excellent moyen de limiter le nombre de requêtes que votre site doit faire, sans gonfler votre fichier CSS.

32
Davy Baert

Sur Mac/Linux, vous pouvez facilement convertir un fichier SVG en une valeur encodée en base64 pour l'attribut d'arrière-plan CSS avec cette commande simple bash:

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

Testé sur Mac OS X. De cette façon, vous éviterez également le désordre qui échappe aux URL.

Rappelez-vous que l'encodage en base64 d'un fichier SVG augmente sa taille, voir article de blog de css-tricks.com .

24
araks

J'ai lancé une démonstration de CodePen qui rencontrait le même problème d'intégration de SVG intégré dans CSS. Une solution qui fonctionne avec SCSS consiste à créer une fonction de codage d’URL simple.

Une fonction de remplacement de chaîne peut être créée à partir des fonctions intégrées str-slice, str-index (voir css-tricks , grâce à Hugo Giraudel).

Ensuite, remplacez simplement _%_, _<_, _>_, _"_, _'_, par les codes _%xx_:

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

Il existe également une fonction d'assistance image-inline disponible dans Compass, mais comme elle n'est pas prise en charge dans CodePen, cette solution pourrait probablement être utile.

Démo sur CodePen: http://codepen.io/terabaud/details/PZdaJo/

10
Lea Rosema

Les SVG en ligne provenant de sources tierces (telles que les graphiques Google) peuvent ne pas contenir d'attribut d'espace de nom XML (xmlns="http://www.w3.org/2000/svg") dans l'élément SVG (ou peut-être qu'il est supprimé une fois que SVG est rendu - ni les commandes Inspecteur du navigateur ni jQuery à partir de la console du navigateur affichent l'espace de nom. dans l'élément SVG).

Lorsque vous avez besoin de réutiliser ces extraits svg pour vos autres besoins (image d'arrière-plan dans CSS ou élément img dans HTML), surveillez l'espace de noms manquant. Sans les espaces de noms, les navigateurs peuvent refuser d’afficher SVG (quel que soit le codage utf8 ou base64).

4
mp31415

J'ai trouvé une solution pour SVG. Mais cela ne fonctionne que pour Webkit, je veux juste partager ma solution de contournement avec vous. Dans mon exemple, il est montré comment utiliser un élément SVG de DOM comme arrière-plan via un filtre (background-image: url ('# glyph') ne fonctionne pas).

Fonctionnalités nécessaires pour le rendu de cette icône SVG:

  1. Application d'effets de filtre SVG aux éléments HTML à l'aide de CSS (IE et Edge ne sont pas pris en charge)
  2. feImage fragment supportant (firefox pas supporte)
.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>

Une autre solution, est d'utiliser url encoder

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>
3
Alex Nikulin