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.