SVG en ligne en CSS

285

Est-il possible d'utiliser une définition SVG en ligne en CSS?

Je veux dire quelque chose comme:

.my-class {
  background-image: <svg>...</svg>;
}
akaRem
la source
1
Qu'essayez-vous de faire, ajouter l'image "source" à la feuille de style?
Zuul
1
Attention, les solutions proposées ne fonctionneront pas pour les images CSS, les <img>balises HTML et autres cas si le SVG est un mélange de plusieurs images (sauf s'il est incorporé), voir l' image d'arrière - plan SVG avec masque utilisant une image externe ne fonctionne pas , et spécifiquement les restrictions sur SVG utilisé comme une image .
Skippy le Grand Gourou

Réponses:

377

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 l'url pour que cela fonctionne, par exemple, il #est remplacé par %23.)

Cela fonctionne dans IE 9 (qui prend en charge SVG) . Les URL de données fonctionnent également dans les anciennes versions d'IE (avec des limitations), mais elles ne prennent pas nativement en charge SVG.

Raab
la source
8
Le seul navigateur dans lequel il semble fonctionner correctement est Safari (5.1.4). Dans Opera 11.62, le dégradé est noir, dans IE 9 et Firefox 12, il est blanc. Dans Chrome 19, cela fonctionne SAUF si vous spécifiez la largeur / hauteur du SVG en% unités. Je dirais que c'est plus une bizarrerie qu'une vraie fonctionnalité. C'est une trouvaille sympa cependant.
toniedzwiedz
4
Bon ... je suis toujours impatient de voir les regards sur le visage de mes collègues quand je leur montre un petit monstre mignon comme ça, alors merci encore de montrer que c'est possible. Je suis juste allé à la spécification standard et j'ai déclaré que c'était pratiquement impossible, ce qui s'est avéré être une erreur (en quelque sorte)
toniedzwiedz
18
L '"incompatibilité du navigateur" ici est principalement un manque de fuite d'URL appropriée, tout ce qui se trouve à l'intérieur url()doit être échappé par l'url. Voir jsfiddle.net/6WAtQ pour un exemple qui fonctionne très bien dans Opera, Firefox et Safari.
Erik Dahlström
3
Y a-t-il une différence de compatibilité entre le svg encodé en base64 et non-base64? Base64 gonfle mon fichier css, je pense à utiliser simplement des svgs en ligne ..
enapupe
4
Remarque, la manière standard de spécifier le jeu de caractères est d'utiliser "; charset = UTF-8" au lieu de "; utf8". tools.ietf.org/html/rfc2397
Keith Shaw
240

Un peu tard, mais si certains d'entre vous sont devenus fous en essayant d'utiliser le SVG en ligne comme arrière-plan , les suggestions d'échappement ci-dessus ne fonctionnent pas tout à fait. D'une part, cela ne fonctionne pas dans IE, et selon le contenu de votre SVG, la technique causera des problèmes dans d'autres navigateurs, comme FF.

Si vous codez en base64 le svg (pas l'url entière, juste 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 s'échappant avant la conversion en base64. En d'autres termes, l'exemple ci-dessus a montré color = '# fcc' converti en color = '% 23fcc', vous devez revenir à #.

La raison pour laquelle base64 fonctionne mieux est qu'il élimine tous les problèmes avec les guillemets simples et doubles et l'échappement d'url

Si vous utilisez JS, vous pouvez utiliser window.btoa()pour produire votre svg base64; et si cela ne fonctionne pas (il pourrait 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

Mike Tommasi
la source
2
Merci mec. La solution avec Base64 fonctionnait très bien, tandis que je rencontrais des problèmes avec la réponse acceptée.
Marcel
1
Tu m'as sauvé la vie. J'avais une image de bordure SVG qui fonctionnait en chrome mais pas sur FF. Maintenant ça marche! : D
Papipo
Cela m'a aussi aidé (après avoir perdu du temps à essayer la réponse acceptée) - cela devrait certainement être la réponse acceptée.
Katai
Si cela ne fonctionne toujours pas pour vous - assurez-vous que l' xmlnsattribut est défini sur svgelement avant de coder en base64 comme les <svg xmlns="http://www.w3.org/2000/svg">...</svg>navigateurs le coupent parfois sans lui lorsque svg est directement en HTML - ce n'est PAS le cas :)
jave.web
Dans le cas où quelqu'un regarde toujours cette réponse 6+ ans plus tard: Vous ne devriez probablement pas base64 SVG css-tricks.com/probably-dont-base64-svg
Volker E.
38

Pour les personnes qui ont encore des difficultés, j'ai réussi à faire fonctionner cela sur tous les navigateurs modernes IE11 et plus.

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

Il y a trois choses dont vous devez être conscient:

  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 que celles-ci puissent être remplacées par la couleur que je veux. Vous pouvez utiliser n'importe quel convertisseur en ligne pour URL coder le reste de la chaîne. Vous vous retrouverez 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% 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% 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. OMITER LE CHARSET UTF8 DANS L'URL DE DONNÉES Lors de la création de votre URL de données, vous devez omettre le jeu de caractères pour qu'il fonctionne dans IE11.

    PAS d' 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. UTILISER RVB () AU LIEU DES COULEURS HEXES Firefox n'aime pas # dans le code SVG. Vous devez donc remplacer vos valeurs hexadécimales par des valeurs RVB.

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

Dans mon cas, j'utilise SASS pour convertir un hexadécimal donné en une valeur RVB valide. Comme indiqué dans les commentaires, il est préférable de coder l'URL de votre chaîne RVB également (donc la virgule devient% 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 (le SVG en ligne ne l'est jamais dans ce cas), mais pour les icônes plates avec seulement quelques couleurs, cela fonctionne vraiment bien.

J'ai pu omettre un bitmap sprite entier et le remplacer par SVG en ligne dans mon CSS, qui s'est avéré être seulement d'environ 25 Ko après compression. C'est donc un excellent moyen de limiter le nombre de demandes de votre site, sans gonfler votre fichier CSS.

Davy Baert
la source
1
Btw, corrigez-moi si je me trompe mais rgb(255,0,0)devrait devenir rgb(255%2C0%2C0)une fois encodé.
Capsule du
1
Je voulais dire que je n'encode pas la chaîne RVB et cela fonctionne toujours. Mais l'encoder comme vous l'avez mentionné est probablement mieux.
Davy Baert
1
Eh bien, en fait, je viens de tester et %23ff0000fonctionne bien #ff0000dans Firefox
Capsule
1
@Capsule Je ne sais pas ce qui se passe, mais le% 23ff0000 est la SEULE méthode qui fonctionne pour moi sur Chrome et FF. # ff0000 ne fonctionne pas, pas plus que les méthodes RGB (255,0,0) et rgb (255% 2C0% 2C0).
Idéogramme
1
Une méthode (y compris le code SCSS) qui nécessite moins d'encodage: codepen.io/jakob-e/pen/doMoML
Sphinxxx
26

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 simple commande 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 évitez également les URL qui échappent au gâchis.

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

araks
la source
2
Aux lecteurs: veuillez commenter votre opinion au lieu de simplement voter contre, afin que cette réponse puisse être améliorée avec votre collaboration! La collaboration est essentielle dans les sites de questions / réponses comme celui-ci. Je vous remercie!
araks
2
@LorDex le lien que vous avez fourni dans votre commentaire est le même que celui dans ma réponse :)
araks
10

J'ai créé une démo CodePen qui avait le même problème avec l'intégration de SVG en ligne dans CSS. Une solution qui fonctionne avec SCSS consiste à créer une simple fonction de codage d'URL.

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

Ensuite, il suffit de remplacer %, <, >, ", ', avec les %xxcodes:

@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 image-inlinefonction d'assistance 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/

Lea Rosema
la source
1
J'ai également créé un stylo qui vous permet de convertir les chaînes svg en une valeur d'arrière-plan CSS appropriée: s.codepen.io/LukyVj/debug/693cbcc30258bf67b8c30047cce060eb Donc, en gros, vous collez votre fichier<svg><path></svg> dans la zone de texte supérieure, et il affichera directement le chemin aseptisé dans une url()valeur.
LukyVj
1
Cela a très bien fonctionné. Je vous remercie. Une note. Vous devez utiliser; charset = utf8 pour que cela fonctionne dans IE.
Daniel Lefebvre
4

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

Lorsque vous devez réaffecter ces extraits svg à vos autres besoins (image d'arrière-plan en CSS ou élément img en HTML), faites attention à l'espace de noms manquant. Sans l'espace de noms, les navigateurs peuvent refuser d'afficher SVG (quel que soit l'encodage utf8 ou base64).

mp31415
la source
4

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

Fonctionnalités nécessaires pour ce rendu d'icône SVG:

  1. Application d'effets de filtre SVG aux éléments HTML à l'aide de CSS (IE et Edge non pris en charge)
  2. Prise en charge de la charge du fragment feImage (Firefox ne prend pas en charge)

.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 consiste à utiliser le codage 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
la source