Comment puis-je mettre à l'échelle une image dans un sprite CSS

157

Dans cet article, http://css-tricks.com/css-sprites/ , il explique comment découper une image plus petite à partir d'une image plus grande. Pouvez-vous me dire si c'est possible / comment je peux rogner une image plus petite et ensuite mettre à l'échelle la zone rognée avant de la mettre en page?

Voici un exemple de cet article:

A
{
  background-image: url(http://www.jaredhirsch.com/coolrunnings/public_images/3deb155981/spriteme1.png);
  background-position: -10px -56px;
}

Je voudrais savoir comment puis-je mettre à l'échelle cette image après l'avoir recadrée à partir de spriteme1.png

Voici l'URL de l'exemple: http://css-tricks.com/examples/CSS-Sprites/Example1After/

Alors je voudrais savoir si je peux réduire les icônes à côté de Item1,2,3,4?

Michael
la source
Comme Stephen l'a demandé, y a-t-il quelque chose qui vous empêche de rendre les images à la taille que vous voulez en premier lieu?
Paul D.Waite
4
Je me suis retrouvé sur cette page car je cherchais une réponse pour la même chose. Dans le monde d'aujourd'hui avec des écrans Retina haute définition, il est courant de créer une image deux fois plus grande que nécessaire, puis d'utiliser les valeurs de hauteur / largeur dans les attributs <img> ou les styles CSS pour la réduire à la moitié de la hauteur / largeur lors de l'affichage. Cela garantit un affichage net sur les smartphones et les tablettes. Mais les sprites PNG sont parfaits pour la mise en cache et le rendu rapide. Il serait préférable non seulement d'utiliser un sprite d'images 2x, mais de le mettre à l'échelle à une taille qui lui donne également un aspect net.
Art Geigel
Comme la question originale n'a jamais reçu de réponse acceptée et qu'il existe une solution assez soignée et rétrocompatible, j'ai créé une nouvelle version de Codepen Stretchy , car le site Web d'origine n'est plus en ligne et maaaaybe il y a encore des gens qui ont besoin d'un retour en arrière solution compatible. J'ai fait le stylo avec l'attribution de l'œuvre originale / auteur.
Tous les bits sont égaux

Réponses:

131

Vous pouvez utiliser background-size , car il est pris en charge par la plupart des navigateurs (mais pas tous http://caniuse.com/#search=background-size )

background-size : 150% 150%;

Ou

Vous pouvez utiliser une combinaison de zoom pour webkit / ie et de transformation: scale pour Firefox (-moz-) et Opera (-o-) pour les ordinateurs de bureau et mobiles multi-navigateurs

[class^="icon-"]{
    display: inline-block;
    background: url('../img/icons/icons.png') no-repeat;
    width: 64px;
    height: 51px;
    overflow: hidden;
    zoom:0.5;
    -moz-transform:scale(0.5);
    -moz-transform-origin: 0 0;
}

.icon-huge{
    zoom:1;
    -moz-transform:scale(1);
    -moz-transform-origin: 0 0;
}

.icon-big{
    zoom:0.60;
    -moz-transform:scale(0.60);
    -moz-transform-origin: 0 0;
}

.icon-small{
    zoom:0.29;
    -moz-transform:scale(0.29);
    -moz-transform-origin: 0 0;
}
aWebDeveloper
la source
3
Fonctionne très bien dans Chrome, fonctionne bien dans FF, IE9 / 10. Produit l'effet désiré pour la plupart.
RCNeil
En utilisant (exemple) background-size: 15%; fonctionne parfaitement pour les sprites tout en conservant le bon rapport hauteur / largeur. C'est une solution simple à utiliser avec des points d'arrêt sur des sites réactifs.
C13L0
1
la propriété background-size ne fonctionnait pas pour mon sprite svg avec une hauteur et une largeur fixes, mais l'échelle a fait l'affaire.
Andre
Pour ajouter la prise en charge à IE8, utilisez l'attribut -ms-zoom comme synonyme de zoom en mode Normes IE8. -ms-zoom: 0,7; Voir le lien ci-dessous pour plus de détails: msdn.microsoft.com/en-us/library/ms531189(v=vs.85).aspx
Amr
2
Mise à jour 2017: la taille de l'arrière-plan est prise en charge par tous les principaux navigateurs, y compris IE9 +. caniuse.com/#search=background-size
Nathan Hinchey
29

Lorsque vous utilisez des sprites, vous êtes limité aux dimensions de l'image dans le sprite. La background-sizepropriété CSS, mentionnée par Stephen, n'est pas encore largement prise en charge et pourrait poser des problèmes avec les navigateurs comme IE8 et les versions antérieures - et étant donné leur part de marché, ce n'est pas une option viable.

Une autre façon de résoudre le problème consiste à utiliser deux éléments et à mettre à l'échelle le sprite en l'utilisant avec une imgbalise, comme ceci:

<div class="sprite-image"
     style="width:20px; height:20px; overflow:hidden; position:relative">
    <!-- set width/height proportionally, to scale the sprite image -->
    <img src="sprite.png" alt="icon"
         width="20" height="80"
         style="position:absolute; top: -20px; left: 0;" />
</div>

De cette façon, l'élément externe ( div.sprite-image) recadre une image 20x20px de la imgbalise, qui agit comme une mise à l'échelle background-image.

Alex Gyoshev
la source
2
Comme Cletus et Quentin Statet ici , ce n'est peut-être pas la meilleure approche. Pour moi, c'est un dealbreaker - je dois attribuer srcpar css.
Jook
-1: vous ne pouvez pas mélanger des éléments de présentation avec du contenu / des données. <img>ne doit être utilisé que s'il fait partie du contenu. à des fins de conception, les images d'arrière-plan sont indispensables.
Shahriyar Imanov
La meilleure réponse (a) fonctionne universellement, (b) est compréhensible par les humains, (c) est brève, ... (z) sépare la présentation du contenu.
Bob Stein
18

Essayez ceci: Stretchy Sprites - Cross-browser, redimensionnement / étirement réactif des images de sprite CSS

Cette méthode met à l'échelle les sprites de manière `` réactive '' afin que la largeur / hauteur s'ajuste en fonction de la taille de la fenêtre de votre navigateur. Il n'est pas utilisé background-size comme support pour cela dans les navigateurs plus anciens, c'est inexistant.

CSS

.stretchy {display:block; float:left; position:relative; overflow:hidden; max-width:160px;}
.stretchy .spacer {width: 100%; height: auto;}
.stretchy .sprite {position:absolute; top:0; left:0; max-width:none; max-height:100%;}
.stretchy .sprite.s2 {left:-100%;}
.stretchy .sprite.s3 {left:-200%;}

HTML

<a class="stretchy" href="#">
  <img class="spacer" alt="" src="spacer.png">
  <img class="sprite" alt="icon" src="sprite_800x160.jpg">
</a>
<a class="stretchy s2" href="#">
  <img class="spacer" alt="" src="spacer.png">
  <img class="sprite" alt="icon" src="sprite_800x160.jpg">
</a>
<a class="stretchy s3" href="#">
  <img class="spacer" alt="" src="spacer.png">
  <img class="sprite" alt="icon" src="sprite_800x160.jpg">
</a>
tobyj
la source
3
Le lien n'explique pas vraiment la théorie ici. Vous utilisez un div avec débordement: masqué en tant que zone de recadrage / fenêtre au-dessus de l'utilisation d'une version à l'échelle de l'image du sprite. C'est pourquoi il n'utilise pas du tout d'image d'arrière-plan. Juste un calque au-dessus d'un autre comme masque.
Simon
1
est-ce que spacer doit être une image ou un simple div peut-il être utilisé à la place?
isapir
4
Voici un exemple CodePen de ceci. Cela semble fonctionner uniquement pour les sprites horizontaux ou verticaux. Pas des grilles.
Wernight
J'ai fait une nouvelle version de Codepen Stretchy , car le site Web d'origine n'est plus en ligne et maaaaybe il y a encore des gens qui ont besoin d'une solution rétrocompatible. J'ai fait le stylo avec l'attribution de l'œuvre originale / auteur
Tous les bits sont égaux
10

transform: scale(); fera que l'élément d'origine conserve sa taille.

J'ai trouvé que la meilleure option était d'utiliser vw. Cela fonctionne comme un charme:

https://jsfiddle.net/tomekmularczyk/6ebv9Lxw/1/

#div1,
#div2,
#div3 {
  background:url('//www.google.pl/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png') no-repeat;
  background-size: 50vw;   
  border: 1px solid black;
  margin-bottom: 40px;
}

#div1 {
  background-position: 0 0;
  width: 12.5vw;
  height: 13vw;
}
#div2 {
  background-position: -13vw -4vw;
  width: 17.5vw;
  height: 9vw;
  transform: scale(1.8);
}
#div3 {
  background-position: -30.5vw 0;
  width: 19.5vw;
  height: 17vw;
}
<div id="div1">
  </div>
  <div id="div2">
  </div>
  <div id="div3">
  </div>

Tomasz Mularczyk
la source
Bonjour, cela ne répond pas à la question. Vous devez montrer les trois divs avec des échelles différentes de la même image. En quelques mots, il devrait montrer différentes tailles de "police". Peux-tu le réparer?
Robert
salut @Robert. Et maintenant?
Tomasz Mularczyk
PS avez-vous remarqué des comportements en utilisant l'unité de mesure VW?
Robert
Je ne sais pas, quels comportements parlez-vous?
Tomasz Mularczyk
VW VH s'adapte proportionnellement à la taille de la fenêtre. Je ne les ai jamais utilisés jusqu'à présent. C'est juste une curiosité sur votre expérience de leur utilisation. Sont-ils si "magiques" ou y a-t-il des problèmes à considérer (comportements inattendus) dans certaines situations que vous avez peut-être remarquées? merci
Robert
7

Voici ce que j'ai fait pour faire ça. Gardez à l'esprit que cela ne fonctionnera pas sur IE8 et les versions antérieures.

#element {
  width:100%;
  height:50px;
  background:url(/path/to/image.png);
  background-position:140.112201963534% 973.333333333333%;
}

La largeur de l'image d'arrière-plan sera réduite en tant que parent de l' #elementéchelle inférieure. Vous pouvez également faire de même avec sa hauteur si vous convertissez heighten pourcentage. Le seul point délicat est de déterminer les pourcentages background-position.

Le premier pourcentage correspond à la largeur de la zone ciblée de l'image-objet lorsqu'elle est à la largeur normale divisée par la largeur totale de l'image-objet et multipliée par 100.

Le deuxième pourcentage correspond à la hauteur de la zone ciblée de l'image-objet avant d'être mise à l'échelle divisée par la hauteur totale de l'image-objet et multipliée par 100.

Le libellé de ces deux équations est un peu bâclé, alors faites-moi savoir si vous avez besoin de moi pour mieux l'expliquer.


la source
6

Cela semble fonctionner pour moi.

Si les sprites sont dans la grille, définissez le background-sizenombre de sprites sur 100% et le nombre de sprites vers le bas à 100%. Ensuite, utilisez background-position -<x*100>% -<y*100>%où x et y sont le sprite basé sur zéro

En d'autres termes, si vous voulez que le 3e sprite à partir de la gauche et la 2e rangée soit 2 au-dessus et 1 en bas, donc

background-position: -200% -100%;

Par exemple, voici une feuille de sprite sprites 4x2

entrez la description de l'image ici

Et voici un exemple

div {
  margin: 3px;
  display: inline-block;
}
.sprite {
  background-image: url('https://i.stack.imgur.com/AEYNC.png');
  background-size: 400% 200%;  /* 4x2 sprites so 400% 200% */
}
.s0x0 { background-position:    -0%   -0%; }
.s1x0 { background-position:  -100%   -0%; }
.s2x0 { background-position:  -200%   -0%; }
.s3x0 { background-position:  -300%   -0%; }
.s0x1 { background-position:    -0%  -100%; }
.s1x1 { background-position:  -100%  -100%; }
.s2x1 { background-position:  -200%  -100%; }
.s3x1 { background-position:  -300%  -100%; }
<div class="sprite s3x1" style="width: 45px; height:20px"></div>
<div class="sprite s3x1" style="width: 128px; height:30px"></div>
<div class="sprite s3x1" style="width: 64px; height:56px"></div>
<div class="sprite s2x1" style="width: 57px; height:60px"></div>
<div class="sprite s3x0" style="width: 45px; height:45px"></div>
<div class="sprite s0x1" style="width: 12px; height:100px"></div>

<br/>
<div class="sprite s0x0" style="width: 45px; height:20px"></div>
<div class="sprite s1x0" style="width: 128px; height:45px"></div>
<div class="sprite s2x0" style="width: 64px; height:56px"></div>
<div class="sprite s3x0" style="width: 57px; height:60px"></div>
<br/>
<div class="sprite s0x1" style="width: 45px; height:45px"></div>
<div class="sprite s1x1" style="width: 12px; height:50px"></div>
<div class="sprite s2x1" style="width: 12px; height:50px"></div>
<div class="sprite s3x1" style="width: 12px; height:50px"></div>

Si les sprites sont de tailles différentes, vous devez définir le background-sizepour chaque sprite sur un pour cent de sorte que la largeur de ce sprite devienne 100%

En d'autres termes, si l'image a une largeur de 640 pixels et que le sprite à l'intérieur de cette image a une largeur de 45 pixels, alors pour obtenir que 45 pixels soit 640 pixels

xScale = imageWidth / spriteWidth
xScale = 640 / 45
xScale = 14.2222222222
xPercent = xScale * 100
xPercent = 1422.22222222%

Ensuite, vous devez définir le décalage. La complication du décalage est que 0% est aligné à gauche et 100% est aligné à droite.

entrez la description de l'image ici

En tant que programmeur graphique, je m'attendrais à un décalage de 100% pour déplacer l'arrière-plan de 100% à travers l'élément, en d'autres termes entièrement du côté droit, mais ce n'est pas ce que 100% signifie lorsqu'il est utilisé backgrouhnd-position. background-position: 100%;signifie aligné à droite. Donc, le forum pour prendre cela en compte après la mise à l'échelle est

xOffsetScale = 1 + 1 / (xScale - 1)              
xOffset = offsetX * offsetScale / imageWidth

Supposons que le décalage est de 31 px

xOffsetScale = 1 + 1 / (14.222222222 - 1)
xOffsetScale = 1.0756302521021115
xOffset = offsetX * xOffsetScale / imageWidth
xOffset = 31 * 1.0756302521021115 / 640
xOffset = 0.05210084033619603
xOffsetPercent = 5.210084033619603

Voici une image 640x480 avec 2 sprites.

  1. à 31x 27y taille 45w 32h
  2. à 500x 370y taille 105w 65h

entrez la description de l'image ici

Suivre les maths ci-dessus pour le sprite 1

xScale = imageWidth / spriteWidth
xScale = 640 / 45
xScale = 14.2222222222
xPercent = xScale * 100
xPercent = 1422.22222222%

xOffsetScale = 1 + 1 / (14.222222222 - 1)
xOffsetScale = 1.0756302521021115
xOffset = offsetX * xOffsetScale / imageWidth
xOffset = 31 * 1.0756302521021115 / 640
xOffset = 0.05210084033619603
xOffsetPercent = 5.210084033619603

yScale = imageHeight / spriteHEight
yScale = 480 / 32
yScale = 15
yPercent = yScale * 100
yPercent = 1500%

yOffsetScale = 1 + 1 / (15 - 1)
yOffsetScale = 1.0714285714285714
yOffset = offsetY * yOffsetScale / imageHeight
yOffset = 27 * 1.0714285714285714 / 480
yOffset = 0.06026785714285714
yOffsetPercent = 6.026785714285714

div {
  margin: 3px;
  display: inline-block;
}
.sprite {
  background-image: url('https://i.stack.imgur.com/mv9lJ.png');
}
.s1 {
  background-size:      1422.2222% 1500%;
  background-position:  5.210084033619603% 6.026785714285714%;
}
.s2 {
  background-size:      609.5238095238095% 738.4615384615385%;
  background-position:  93.45794392523367% 89.1566265060241%;
}
<div class="sprite s1" style="width: 45px; height:20px"></div>
<div class="sprite s1" style="width: 128px; height:30px"></div>
<div class="sprite s1" style="width: 64px; height:56px"></div>
<div class="sprite s1" style="width: 57px; height:60px"></div>
<div class="sprite s1" style="width: 45px; height:45px"></div>
<div class="sprite s1" style="width: 12px; height:50px"></div>
<div class="sprite s1" style="width: 50px; height:40px"></div>
<hr/>
<div class="sprite s2" style="width: 45px; height:20px"></div>
<div class="sprite s2" style="width: 128px; height:30px"></div>
<div class="sprite s2" style="width: 64px; height:56px"></div>
<div class="sprite s2" style="width: 57px; height:60px"></div>
<div class="sprite s2" style="width: 45px; height:45px"></div>
<div class="sprite s2" style="width: 12px; height:50px"></div>
<div class="sprite s2" style="width: 50px; height:40px"></div>

gman
la source
Comment avez-vous calculé les valeurs de offsetX et offsetY?
TryHarder
5

Ancien post, mais voici ce que j'ai fait en utilisant background-size:cover;(pointe du chapeau à @Ceylan Pamir) ...

EXEMPLE D'UTILISATION
Flipper de cercle horizontal (survolez l'image du recto, bascule vers l'arrière avec une image différente).

EXEMPLE SPRITE
480px x 240px

EXEMPLE TAILLE FINALE
Image unique @ 120px x 120px

CODE GÉNÉRIQUE
.front {width:120px; height:120px; background:url(http://www.example.com/images/image_240x240.png); background-size:cover; background-repeat:no-repeat; background-position:0px 0px;}

.back {width:120px; height:120px; background:url(http://www.example.com/images/image_240x240.png); background-size:cover; background-repeat:no-repeat; background-position:-120px 0px;}

CAS ABRÉVIÉ FIDDLE
http://jsfiddle.net/zuhloobie/133esq63/2/

Chris
la source
4

essayez d'utiliser la taille de l'arrière-plan: http://webdesign.about.com/od/styleproperties/p/blspbgsize.htm

y a-t-il quelque chose qui vous empêche de rendre les images à la taille que vous voulez en premier lieu?

stephenmurdoch
la source
Puis-je utiliser JavaScript et CSS en combinaison pour résoudre ce problème? J'ai essayé la taille de fond; propriété. Je ne peux pas le faire fonctionner. Il ne met pas l'image à l'échelle pour une raison quelconque.
michael
1
background-sizeest CSS 3 et n'est pas encore largement pris en charge.
janmoesen
4
Il est maintenant pris en charge par la plupart des versions de navigateur. Vérifiez ceci caniuse.com/#search=background-size
kiranvj
4

Il m'a fallu un certain temps pour créer une solution à ce problème dont j'étais satisfait:

Problème:

  • Un sprite SVG d'icônes - disons 80px x 3200px

  • Nous voulons mettre à l'échelle chaque utilisation d'entre eux dans les sélecteurs de contenu (: avant /: après) à divers endroits sur différentes tailles sans redéfinir les coordonnées de chaque sprite en fonction de la taille utilisée.

Donc, cette solution vous permet d'utiliser les mêmes coordonnées de sprite dans un <button>comme un <menuitem>tout en le redimensionnant.

[data-command]::before {
    content: '';
    position: absolute;
    background-image: url("images/sprite.svgz");
    background-repeat: no-repeat;
    background-size: cover;
}

button[data-command]::before {
  width: 32px;
  height: 32px;
}

menuitem[data-command]::before {
  width: 24px;
  height: 24px;
}

[data-command="cancel"]::before {
  background-position: 0% 35%;
}

[data-command="logoff"]::before {
  background-position: 0% 37.5%;
}

En utilisant des pourcentages (à 2 décimales) dans la position de l'arrière-plan plutôt que la taille de l'arrière-plan comme suggéré par d'autres ici, vous pouvez mettre à l'échelle la même déclaration d'icône à n'importe quelle taille, sans avoir besoin de la redéclarer.

Le pourcentage de position-y est la hauteur d'origine du sprite / hauteur de l'icône en% - dans notre cas ici 80px * 100 / 3200px == chaque sprite est représenté par une position y de 2,5%.

Si vous avez des états de survol / survol de la souris, vous pouvez doubler la largeur du sprite et spécifier dans la coordonnée position-x.

L'inconvénient de cette approche est que l'ajout d'icônes à une date ultérieure modifiera la hauteur du sprite et donc la position y%, mais si vous ne le faites pas, vos coordonnées de sprite devront être modifiées pour chaque résolution mise à l'échelle dont vous avez besoin.

Neil
la source
2

Eh bien, je pense que j'ai trouvé une solution plus simple pour la mise à l'échelle des images: exemple - disons qu'il y a une image avec 3 sprites de taille égale que vous voudriez utiliser, utilisez CSS pour redimensionner l'image

background-size : 300% 100%;

puis spécifiez la hauteur et la largeur personnalisées qui doivent être appliquées à votre élément html, par exemple:

 width :45%;
 height:100px;

Un exemple de code ressemblerait à ceci:

.customclass {
    background: url("/sample/whatever.png") 0 0 no-repeat ;
    background-size : 300% 100%;
    width :45%;
    height:100px;
}

Je suis assez nouveau en css, et le style n'est pas mon meilleur domaine, cela pourrait être une mauvaise façon de le faire .. mais cela a fonctionné pour moi dans Firefox / Chrome / Explorer 10, j'espère que cela fonctionne aussi dans les anciennes versions ..

Dasith
la source
2

Utilisez transform: scale(...);et ajoutez une correspondance margin: -...pxpour compenser l'espace libre de la mise à l'échelle. (vous pouvez utiliser * {outline: 1px solid}pour voir les limites des éléments).

adyry
la source
2

2018 ici. Utilisez background-size avec pourcentage.

FEUILLE:

Cela suppose une seule ligne de sprites. La largeur de votre feuille doit être un nombre divisible par 100 + la largeur d'un sprite . Si vous avez 30 sprites de 108 x 108 pixels, ajoutez un espace vide supplémentaire à la fin pour obtenir la largeur finale de 5508 pixels (50 * 108 + 108).

CSS:

.icon{
    height: 30px;  /* Set this to anything. It will scale. */
    width: 30px; /* Match height. This assumes square sprites. */
    background:url(<mysheeturl>);
    background-size: 5100% 100%; /*  5100% because 51 sprites. */
}

/* Each image increases by 2% because we used 50+1 sprites. 
   If we had used 20+1 sprites then % increase would be 5%. */

.first_image{
    background-position: 0% 0;
}

.ninth_image{
    background-position: 16% 0; /* (9-1) x 2 = 16 */
}

HTML:

<div class ="icon first_image"></div>
<div class ="icon ninth_image"></div>
user984003
la source
1

Utilisez transform: scale(0.8);avec la valeur dont vous avez besoin au lieu de 0,8

Miguel Ballén
la source
0

Définissez la largeur et la hauteur de l'élément wrapper de l'image de sprite. Utilisez ce css.

{
    background-size: cover;
}
Ceylan Pamir
la source
1
Je ne comprends pas pourquoi ce vote est à la baisse. A travaillé pour moi. Publiera ma méthode comme réponse.
chris
Je suis d'accord avec Chris ici. Cela résout le problème dans mon cas aussi. Je ne sais pas pourquoi il a été rejeté!
ShellZero
3
Cela ne fonctionne pas avec le sprite (regardez le titre de la question), c'est pourquoi cette solution est rejetée.
Dimko Desu
-8

Facile ... Utiliser deux copies de la même image avec une échelle différente sur la feuille du sprite. Définissez les coordonnées et la taille sur la logique de l'application.

makubex
la source