Jak mogę przeskalować obraz w sprite'u CSS


157

W tym artykule, http://css-tricks.com/css-sprites/ , jest mowa o tym, jak wyciąć mniejszy obraz z jednego większego obrazu. Czy możesz mi powiedzieć, czy jest to możliwe / jak mogę wyciąć mniejszy obraz, a następnie przeskalować przycięty region, zanim go rozłożę?

Oto przykład z tego artykułu:

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

Chciałbym wiedzieć, jak skalować ten obraz po przycięciu go z pliku spriteme1.png

Oto adres URL przykładu: http://css-tricks.com/examples/CSS-Sprites/Example1After/

Chciałbym więc wiedzieć, czy mogę zmniejszyć ikony obok pozycji 1, 2, 3, 4?


Jak zapytał Stephen, czy jest coś, co powstrzymuje cię przed renderowaniem obrazów w pożądanym rozmiarze?
Paul D. Waite

4
Skończyłem na tej stronie, ponieważ szukałem odpowiedzi na to samo. W dzisiejszym świecie z wyświetlaczami Retina o wysokiej rozdzielczości zwyczajowo buduje się obraz dwa razy większy niż powinien, a następnie używa wartości wysokości / szerokości w atrybutach <img> lub stylach CSS, aby zmniejszyć go do połowy wysokości / szerokości podczas wyświetlania. Zapewnia to wyraźny obraz na smartfonach i tabletach. Ale sprite'y PNG świetnie nadają się do szybkiego buforowania i renderowania. Najlepiej byłoby nie tylko użyć sprite'a 2x obrazu, ale następnie przeskalować go do rozmiaru, który sprawi, że będzie wyglądał ostro.
Art Geigel

Ponieważ pierwotne pytanie nigdy nie uzyskało akceptowanej odpowiedzi i istnieje całkiem zgrabne i kompatybilne wstecz rozwiązanie, stworzyłem nową wersję Codepen Stretchy , ponieważ oryginalna strona internetowa nie jest już online i może nadal są ludzie, którzy potrzebują wstecznego kompatybilne rozwiązanie. Zrobiłem Pióro z podaniem oryginalnego dzieła / autora.
Wszystkie bity są równe

Odpowiedzi:


131

Możesz użyć rozmiaru tła , ponieważ jest obsługiwany przez większość przeglądarek (ale nie wszystkie http://caniuse.com/#search=background-size )

background-size : 150% 150%;

Lub

Możesz użyć kombinacji powiększenia dla webkit / ie i transform: scale for Firefox (-moz-) i Opera (-o-) dla komputerów stacjonarnych i mobilnych z różnymi przeglądarkami

[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;
}

3
Świetnie działa w Chrome, działa dobrze w FF, IE9 / 10. W większości daje pożądany efekt.
RCNeil

Używając (przykład) background-size: 15%; działa idealnie dla duszków przy zachowaniu prawidłowego współczynnika proporcji. Jest to proste rozwiązanie do stosowania z punktami przerwania w responsywnych witrynach.
C13L0

1
właściwość background-size nie działała dla mojego sprite'a SVG ze stałą wysokością i szerokością, jednak skala załatwiła sprawę.
Andre

Aby dodać obsługę przeglądarki IE8, użyj atrybutu -ms-zoom jako synonimu powiększenia w trybie standardów IE8. -ms-zoom: 0,7; Aby uzyskać więcej informacji, zobacz poniższe łącze: msdn.microsoft.com/en-us/library/ms531189(v=vs.85).aspx
Amr

2
Aktualizacja 2017: rozmiar tła jest obsługiwany przez wszystkie główne przeglądarki, w tym IE9 +. caniuse.com/#search=background-size
Nathan Hinchey

29

Kiedy używasz duszków, jesteś ograniczony do wymiarów obrazu w duszku. Właściwość background-sizeCSS, o której wspomniał Stephen, nie jest jeszcze szeroko obsługiwana i może powodować problemy z przeglądarkami takimi jak IE8 i starszymi - a biorąc pod uwagę ich udział w rynku, nie jest to opłacalna opcja.

Innym sposobem rozwiązania problemu jest użycie dwóch elementów i przeskalowanie duszka, używając go z imgtagiem, na przykład:

<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>

W ten sposób zewnętrzny element ( div.sprite-image) przycina obraz o wymiarach 20x20px z imgtagu, który działa jak przeskalowany background-image.


2
Jak cletus i Quentin statet tutaj , to może nie być najlepszym rozwiązaniem. Dla mnie to łamanie umowy - muszę przypisać srcprzez css.
Jook

-1: Nie możesz mieszać elementów prezentacji z treścią / danymi. <img>należy używać tylko wtedy, gdy jest częścią treści. do celów projektowych obrazy tła są koniecznością.
Shahriyar Imanov

Najlepsza odpowiedź (a) działa uniwersalnie, (b) jest zrozumiała dla ludzi, (c) jest krótka, ... (z) oddziela prezentację od treści.
Bob Stein

18

Spróbuj tego: Rozciągliwe Sprites - Cross-browser, responsywna zmiana rozmiaru / rozciąganie obrazków CSS

Ta metoda skaluje duszki „responsywnie”, dzięki czemu szerokość / wysokość dostosowuje się do rozmiaru okna przeglądarki. Nie jest używany, background-size ponieważ obsługa tego w starszych przeglądarkach nie istnieje.

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>

3
Link tak naprawdę nie wyjaśnia tej teorii. Używasz elementu div z przepełnieniem: ukryty jako obszar kadrowania / okno ponad skalowaną wersją obrazka sprite. Dlatego w ogóle nie używa obrazu tła. Tylko jedna warstwa na drugą jako maska.
Simon

1
czy odstępnik musi być obrazem, czy zamiast tego można użyć prostego elementu div?
isapir

4
Oto przykład CodePen . Wydaje się, że działa tylko dla sprite'ów poziomych lub pionowych. Nie siatki.
Wernight,

Stworzyłem nową wersję Codepen Stretchy , ponieważ oryginalna strona internetowa nie jest już online i może nadal są ludzie, którzy potrzebują rozwiązania kompatybilnego wstecz. Zrobiłem Pióro z podaniem oryginalnego dzieła / autora
All Bits Equal

10

transform: scale(); sprawi, że oryginalny element zachowa swój rozmiar.

Uważam, że najlepszą opcją jest użycie vw. Działa jak marzenie:

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>


Witam, to nie odpowiada na pytanie. Powinieneś pokazać trzy elementy div z różnymi skalami tego samego obrazu. Krótko mówiąc, powinien pokazywać różne rozmiary „czcionki”. Czy możesz to naprawić?
Robert

cześć @Robert. A teraz?
Tomasz Mularczyk

PS Czy zauważyłeś zachowania przy użyciu jednostki miary VW?
Robert

Nie jestem pewien, jakie zachowania masz na myśli?
Tomasz Mularczyk

VW VH skalują się proporcjonalnie do rozmiaru widocznego obszaru. Do tej pory nigdy ich nie używałem. To tylko ciekawostka dotycząca Twojego doświadczenia z ich użyciem. Czy są tak „magiczne”, czy też są jakieś problemy do rozważenia (nieoczekiwane zachowania) w niektórych sytuacjach, które mogłeś zauważyć? dziękuję
Robert

7

Oto, co zrobiłem, aby to zrobić. Pamiętaj, że nie będzie działać w IE8 i starszych.

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

Szerokość obrazu tła zostanie zmniejszona, gdy element macierzysty #elementskalowania w dół. Możesz zrobić to samo z jego wysokością, konwertując heightna procent. Jedynym trudnym zadaniem jest obliczenie wartości procentowych dla background-position.

Pierwsza wartość procentowa to szerokość docelowego obszaru duszka przy normalnej szerokości podzielona przez całkowitą szerokość duszka i pomnożona przez 100.

Drugi procent to wysokość docelowego obszaru duszka przed skalowaniem podzielona przez całkowitą wysokość duszka i pomnożona przez 100.

Sformułowanie tych dwóch równań jest trochę niechlujne, więc daj mi znać, jeśli chcesz, abym lepiej to wyjaśnił.


6

To wydaje się działać dla mnie.

Jeśli duszki są w siatce, ustaw na background-size100% liczbę duszków w poprzek i 100% liczbę duszków w dół. Następnie użyj, background-position -<x*100>% -<y*100>%gdzie x i y to sprite od zera

Innymi słowy, jeśli chcesz, aby trzeci duszek od lewej i drugi rząd to 2 powyżej i 1 w dół

background-position: -200% -100%;

Na przykład oto sprite arkusza sprite'ów 4x2

wprowadź opis obrazu tutaj

A oto przykład

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>

Jeśli duszki mają różne rozmiary, musisz ustawić background-sizedla każdego duszka procent, tak aby szerokość duszka wynosiła 100%

Innymi słowy, jeśli obraz ma szerokość 640 pikseli, a sprite wewnątrz tego obrazu ma szerokość 45 pikseli, to aby uzyskać ten 45 pikseli, aby miał 640 pikseli

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

Następnie musisz ustawić przesunięcie. Komplikacja przesunięcia polega na tym, że 0% jest wyrównane do lewej, a 100% do prawej.

wprowadź opis obrazu tutaj

Jako programista grafiki spodziewałbym się, że przesunięcie 100% przesunie tło o 100% w poprzek elementu, innymi słowy całkowicie z prawej strony, ale nie to oznacza 100% w przypadku użycia z backgrouhnd-position. background-position: 100%;oznacza wyrównanie do prawej. Więc forumla do wzięcia tego pod uwagę po skalowaniu to

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

Załóżmy, że przesunięcie wynosi 31 pikseli

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

Oto obraz 640x480 z 2 duszkami.

  1. w rozmiarze 31x 27y 45w 32h
  2. przy 500x 370y rozmiar 105w 65h

wprowadź opis obrazu tutaj

Zgodnie z powyższą matematyką dla duszka 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>


Jak obliczyłeś wartości offsetX i offsetY?
TryHarder

5

Stary post, ale oto, co zrobiłem, używając background-size:cover;(wskazówka do @Ceylan Pamir) ...

PRZYKŁAD ZASTOSOWANIA
Płetwa w kształcie koła poziomego (najedź na obraz z przodu, obróć do tyłu z innym obrazem).

PRZYKŁAD SPRITE
480px x 240px

PRZYKŁADOWY ROZMIAR KOŃCOWY
Pojedynczy obraz o wymiarach 120 x 120 pikseli

KOD OGÓLNY
.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;}

SKRÓCONA OBUDOWA FIDDLE
http://jsfiddle.net/zuhloobie/133esq63/2/


4

spróbuj użyć rozmiaru tła: http://webdesign.about.com/od/styleproperties/p/blspbgsize.htm

czy jest coś, co powstrzymuje Cię przed renderowaniem obrazów w pożądanym rozmiarze?


Czy mogę użyć kombinacji JavaScript i CSS, aby rozwiązać ten problem? Wypróbowałem rozmiar tła; własność. Nie mogę sprawić, żeby to zadziałało. Z jakiegoś powodu nie skaluje obrazu.
michael

1
background-sizejest CSS 3 i nie jest jeszcze szeroko obsługiwany.
janmoesen

4
Jest teraz obsługiwany przez większość wersji przeglądarek. Sprawdź to caniuse.com/#search=background-size
kiranvj Kwietnia

4

Zajęło mi trochę czasu, zanim stworzyłem rozwiązanie tego problemu, z którego byłem zadowolony:

Problem:

  • Sprite SVG z ikonami - powiedzmy 80px x 3200px

  • Chcemy skalować każde ich użycie w selektorach treści (: przed /: po) w różnych miejscach w różnych rozmiarach bez ponownego definiowania współrzędnych każdego duszka na podstawie używanego rozmiaru.

To rozwiązanie pozwala więc na użycie tych samych współrzędnych sprite'a w <button>a, <menuitem>podczas gdy nadal go skalujesz .

[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%;
}

Używając wartości procentowych (do 2 miejsc po przecinku) w pozycji tła, a nie rozmiaru tła, jak sugerują inni tutaj, możesz skalować tę samą deklarację ikony do dowolnego rozmiaru, bez konieczności ponownego deklarowania.

Wartość procentowa pozycji-y to oryginalna wysokość / wysokość ikony duszka w% - w naszym przypadku tutaj 80px * 100 / 3200px == każdy duszek jest reprezentowany przez pozycję y na poziomie 2,5%.

Jeśli masz stany najechania / najechania myszą, możesz podwoić szerokość sprite i określić we współrzędnej position-x.

Wadą tego podejścia jest to, że dodanie większej liczby ikon w późniejszym terminie zmieni wysokość sprite'a, a więc pozycję y%, ale jeśli tego nie zrobisz, współrzędne sprite'a będą wymagały zmiany dla każdej wymaganej skalowanej rozdzielczości.


2

Cóż, myślę, że znalazłem prostsze rozwiązanie do skalowania obrazów: przykład - powiedzmy, że istnieje obraz z 3 sprite'ami o jednakowych rozmiarach, których chciałbyś użyć, użyj CSS do skalowania obrazu

background-size : 300% 100%;

a następnie określ niestandardową wysokość i szerokość, które należy zastosować do elementu HTML, np .:

 width :45%;
 height:100px;

Przykładowy kod wyglądałby mniej więcej tak:

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

Jestem całkiem nowy w css, a stylizacja nie jest moim najlepszym obszarem, może to być zły sposób robienia tego .. ale zadziałało dla mnie w Firefox / Chrome / Explorer 10, mam nadzieję, że działa też w starszych wersjach ..


2

Użyj transform: scale(...);i dodaj dopasowanie, margin: -...pxaby skompensować wolną przestrzeń od skalowania. (możesz użyć, * {outline: 1px solid}aby zobaczyć granice elementów).


2

2018 tutaj. Użyj rozmiaru tła z wartością procentową.

ARKUSZ:

Zakłada się pojedynczy rząd duszków. Szerokość twojego arkusza powinna być liczbą podzielną po równo przez 100 + szerokość jednego duszka . Jeśli masz 30 sprite'ów o wymiarach 108x108 pikseli, dodaj dodatkowe puste miejsce na końcu, aby uzyskać końcową szerokość 5508 pikseli (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>


0

Ustaw szerokość i wysokość, aby otoczyć element obrazu sprite. Użyj tego css.

{
    background-size: cover;
}

1
Nie rozumiem, dlaczego głosowano w dół. Pracował dla mnie. Opublikuję moją metodę jako odpowiedź.
chris

Zgadzam się z Chrisem tutaj. To rozwiązuje również problem w moim przypadku. Nie jestem pewien, dlaczego został odrzucony!
ShellZero

3
Nie działa z duszkiem (patrz tytuł pytania), dlatego to rozwiązanie jest odrzucane.
Dimko Desu

-8

Łatwe ... Używanie dwóch kopii tego samego obrazu o różnej skali na arkuszu duszka. Ustaw współrzędne i rozmiar w logice aplikacji.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.