web-dev-qa-db-fra.com

Comment utiliser la feuille Sprite SVG comme image d'arrière-plan CSS tout en conservant le rapport d'aspect et l'évolutivité

TL; DR: Je veux utiliser plusieurs icônes en mosaïque dans une feuille SVG Sprite en tant qu'images d'arrière-plan CSS, qui conservent leur rapport hauteur/largeur et se mettent automatiquement à l'échelle pour remplir l'élément parent, en n'utilisant que SVG et CSS. Pas de JavaScript s'il vous plaît.


J'ai donc une feuille de calcul au format SVG, que j'ai faite avec une combinaison de SVG-Edit et du codage manuel dans Notepad ++. Voici le code source:

<svg version="1.1"
  xmlns:svg="http://www.w3.org/2000/svg"
  xmlns="http://www.w3.org/2000/svg"
  width="600"
  height="400"
  viewBox="0 0 600 400">
  <!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
  <title>chosen_Sprite</title>
  <g>
    <title>Add</title>
    <rect fill="none" stroke-width="10" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" x="5" y="5" width="90" height="90" id="svg_1" stroke="#dcdcdc"/>
    <line id="svg_2" y2="50" x2="70" y1="50" x1="30" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
    <line id="svg_3" y2="30" x2="50" y1="70" x1="50" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
  </g>
  <g>
    <title>Delete</title>
    <rect fill="none" stroke-width="10" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" x="105" y="5" width="90" height="90" id="svg_1" stroke="#dcdcdc"/>
    <line id="svg_2" y2="70" x2="170" y1="30" x1="130" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#ff0000" fill="none"/>
    <line id="svg_3" y2="30" x2="170" y1="70" x1="130" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#ff0000" fill="none"/>
  </g>
  <g>
    <title>Expand Dark</title>
    <rect stroke="#505050" id="svg_1" height="90" width="90" y="5" x="205" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="10" fill="none"/>
    <line fill="none" stroke="#000000" stroke-width="12" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="round" x1="250" y1="65" x2="280" y2="35" id="svg_2"/>
    <line fill="none" stroke="#000000" stroke-width="12" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="round" x1="220" y1="35" x2="250" y2="65" id="svg_3"/>
  </g>
  <g>
    <title>Collapse Dark</title>
    <rect stroke="#505050" height="90" width="90" y="5" x="305" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="10" fill="none" id="svg_4"/>
    <line fill="none" stroke="#000000" stroke-width="12" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="round" x1="350" y1="35" x2="380" y2="65" id="svg_5"/>
    <line fill="none" stroke="#000000" stroke-width="12" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="round" x1="320" y1="65" x2="350" y2="35" id="svg_6"/>
  </g>
  <g>
    <title>Expand Green</title>
    <rect fill="none" stroke-width="10" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" x="405" y="5" width="90" height="90" id="svg_1" stroke="#dcdcdc"/>
    <line id="svg_2" y2="35" x2="480" y1="65" x1="450" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
    <line id="svg_3" y2="65" x2="450" y1="35" x1="420" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
  </g>
  <g>
    <title>Collapse Green</title>
    <rect fill="none" stroke-width="10" stroke-dasharray="null" stroke-linejoin="null" stroke-linecap="null" x="505" y="5" width="90" height="90" id="svg_1" stroke="#dcdcdc"/>
    <line id="svg_2" y2="65" x2="580" y1="35" x1="550" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
    <line id="svg_3" y2="35" x2="550" y1="65" x1="520" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#00a00c" fill="none"/>
  </g>
  <g>
    <title>Search</title>
    <circle id="svg_9" r="32" cy="140" cx="60" stroke-width="8" stroke="#000000" fill="none"/>
    <line id="svg_11" y2="167.5" x2="32.5" y1="190" x1="10" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#000000" fill="none"/>
  </g>
  <g>
    <title>Search 2</title>
    <rect id="svg_10" stroke="#505050" height="90" width="90" y="105" x="105" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="10" fill="none"/>
    <circle r="25" cy="142.5" cx="157.5" stroke-width="8" stroke="#000000" fill="none" id="svg_7"/>
    <line y2="165" x2="135" y1="180" x1="120" stroke-linecap="round" stroke-linejoin="null" stroke-dasharray="null" stroke-width="12" stroke="#000000" fill="none" id="svg_8"/>
  </g>
</svg>

Cela fonctionne bien et ressemble à ce que je veux.

Le problème est le CSS. Définir les cellules dans la feuille de sprites est un peu plus compliqué que je ne le souhaiterais. Voici la page dans laquelle j'affiche ces icônes:

<!DOCTYPE html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<html>
<head>
<style>

* {padding: 0px; margin: 0px; outline: 1px solid rgba(0,0,0,0.1);}

html {width: 100%; height: 100%;}

body {width: 100%; height: 100%;}

.svgSprite {
    background-image: url('./svgicons/form_icons_Sprite.svg');
    background-repeat: no-repeat;
    background-size: 600%;
}

.svgSprite.add {
    background-position: 0px 0px;
    width: 12px;
    height: 12px;
}

.svgSprite.delete {
    background-position: -16px 0px;
    width: 16px;
    height: 16px;
}

.svgSprite.expandDark {
    background-position: -24px 0px;
    width: 12px;
    height: 12px;
}

.svgSprite.collapseDark {
    background-position: -36px 0px;
    width: 12px;
    height: 12px;
}

.svgSprite.expandGreen {
    background-position: -48px 0px;
    width: 12px;
    height: 12px;
}

.svgSprite.collapseGreen {
    background-position: -60px 0px;
    width: 12px;
    height: 12px;
}

.svgSprite.search {
    background-position: 0px -12px;
    width: 12px;
    height: 12px;
}

.svgSprite.search2 {
    background-position: -16px -16px;
    width: 16px;
    height: 16px;
}

</style>
</head>

<body>
<div class="svgSprite add"></div>
<div class="svgSprite delete"></div>
<div class="svgSprite expandDark"></div>
<div class="svgSprite collapseDark"></div>
<div class="svgSprite expandGreen"></div>
<div class="svgSprite collapseGreen"></div>
<div class="svgSprite search"></div>
<div class="svgSprite search2"></div>
</body>

</html>

Fondamentalement, je veux savoir s'il existe un moyen plus simple de définir les cellules dans la feuille de sprites et de simplifier le CSS que j'utilise pour dire à chaque div quelle icône afficher à partir de la feuille de sprites.

Je préférerais que cette solution soit strictement SVG et CSS; Je ne suis pas intéressé à utiliser des bibliothèques JavaScript. Je vise à l'amener à un point où je peux simplement définir les cellules et avoir l'icône particulière que je vise à mettre à l'échelle automatiquement pour s'adapter à son conteneur, tout en conservant son rapport d'aspect. Actuellement, pour que l'icône s'adapte à son conteneur parent, sa largeur et sa hauteur doivent être définies explicitement et correspondre à la largeur et à la hauteur du conteneur parent. Si je modifie la largeur et la hauteur du conteneur parent, je dois également modifier les tailles de position d'arrière-plan.

Ensuite, il y a le problème de la mise à l'échelle. Avec cette configuration, le SVG s'adapte à la taille appropriée pour être dessiné à l'écran, mais si je décide de zoomer en utilisant le zoom de mon navigateur, il pixellise. Ce n'est pas ainsi que SVG est censé fonctionner.

Je suppose que je pourrais simplement mettre chaque icône dans son propre fichier, car cela semble fonctionner à merveille, mais j'aime vraiment vraiment utiliser les sprites; non seulement cela me sauve plusieurs demandes de serveur, mais c'est tout simplement cool.

Je connais SVG Icon Loader . C'est plutôt cool, mais c'est un autre fichier JavaScript sur lequel je préfère ne pas compter.

J'ai déjà lu les documents SVG w3, les documents SVG MDN et les threads suivants sur SO:

SVG et feuilles de sprites

Ajustez <svg> à la taille du conteneur <object>

tilisation de SVG comme image de fond

... mais même après tout ça, je n'ai pas réussi à trouver de solution.

EDIT: J'ai oublié de mentionner, cela doit fonctionner dans IE9. C'est un peu un problème, j'en suis sûr, mais le support SVG d'IE9 est décent, c'est pourquoi j'ai choisi SVG pour ce projet.

26
Adrian

Fondamentalement, je veux savoir s'il existe un moyen plus simple de définir les cellules dans la feuille de sprites et de simplifier le CSS que j'utilise pour dire à chaque div quelle icône afficher à partir de la feuille de sprites.

Non, vous ne pouvez pas le faire plus facilement.

Essayez cet article

Ensuite, il y a le problème de la mise à l'échelle. Avec cette configuration, le SVG s'adapte à la taille appropriée pour être dessiné à l'écran, mais si je décide de zoomer en utilisant le zoom de mon navigateur, il pixellise. Ce n'est pas ainsi que SVG est censé fonctionner.

Dans Chromium 18, il semble assez bien - pas de pixellisation du tout.

Dans ma liste de navigateurs de test (FF3.6 Opera 9.2 IE6), je n'ai pas vu ce que j'ai vu dans Chromium

Et à propos d'IE9, peut-être un problème dans moteur

3
b1_

Si vos icônes ont la même taille, vous pouvez procéder comme suit:

  1. Emballez vos icônes dans Sprite horizontalement (utilisez svg-Sprite si les icônes sont dans des fichiers séparés).
  2. Ensemble background-size: auto 100%; pour votre sélecteur de cible.
  3. Définissez les éléments cibles _ width, height ou font-size pour l'échelle.
.icon {
    background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="64" height="16" viewBox="0 0 64 16"> <circle fill="blue" cx="8" cy="8" r="8"/> <circle fill="red" cx="24" cy="8" r="8"/> <circle fill="yellow" cx="40" cy="8" r="8"/> <circle fill="green" cx="56" cy="8" r="8"/> </svg>');
    background-repeat: no-repeat;
    background-size: auto 100%;
    display: inline-block;
}
.icon.small {
    height: 1em;
    width: 1em;
}
.icon.medium {
    height: 2em;
    width: 2em;
}
.icon.large {
    height: 4em;
    width: 4em;
}
.icon_1 {
    background-position: 0 0;
}
.icon_2 {
    background-position: 33.33% 0;
}
.icon_3 {
    background-position: 66.67% 0;
}
.icon_4 {
    background-position: 100% 0;
}
<span class="icon icon_1 small"></span>
<span class="icon icon_1 medium"></span>
<span class="icon icon_2 large"></span>
7