Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc

Przyspieszamy ASP.NET - CSS Sprites

Zwykle na bogaty interfejs graficzny witryny składa się wiele obrazków. Nawet, gdy każdy z nich zajmuje po klika kilobajtów, to czas ich pobierania może zacząć dominować przy ładowaniu strony. W końcu załadowanie każdej grafiki wymaga nawiązania oddzielnego połączenia z serwerem. A gdyby tak dało się przesłać wszystkie obrazki w ramach jednego żądania do serwera… Da się i technika ta nazywa się CSS Sprites!

Koncepcja, którą przedstawię w tym wpisie, nie jest w żaden sposób powiązana z ASP.NET – można ją stosować na dowolnej stronie HTML, niezależnie, jaka technologia znajduje się na serwerze. Stanowi ona jeden z ważniejszych sposobów optymalizacji witryn WWW, dlatego uważam, iż nie można o niej zapomnieć, pracując nad wydajnością aplikacji ASP.NET.

W czym problem?

Przeanalizujmy pewien przykład:
http://demos.telerik.com/ribbonbardemo/Examples/Client/ClientMockup.aspx 
Na powyższej stronie znajduje się bardzo ciekawy przykład aplikacji ASP.NET, która wykorzystuje interfejs graficzny z Office 2007 i została zrealizowana przez jednego z użytkowników kontrolek Telerika. Z tą stroną jest jednak pewien problem – zobaczmy, jak wygląda jej pierwsze załadowanie:

  Ilość żądań Czas [s] Rozmiar [KB]
Obrazki 112 (81%) 3,96 (77%) 122 (29%)
Pozostałe
(HTML, JS, CSS)
26 (19%) 1,21 (23%) 298 (71%)

Do jej załadowania przeglądarka musi wysłać aż 138 żądań do serwera, z czego aż 112 przypada na obrazki. Paradoksalnie, choć rozmiar wszystkich obrazków stanowi jedynie 29% całego transferu, to na ich pobranie poświęcanych jest aż 77% czasu.

“Duszki” CSS

Technika CSS Sprites polega na zastąpieniu wielu małych obrazków jednym dużym. Takie rozwiązanie ma kilka zalet:

  1. Redukcja ilości żądań do serwera – jeden obrazek to jedno połączenie.
  2. Mniejszy transfer - jeden zbiorczy obrazek zajmuje mniej przestrzeni niż wiele mniejszych.
  3. Układ graficzny strony pojawia się od razu, a nie ładuje w kawałkach.
  4. Brak efektu “doładowywania” się grafik od dynamicznych elementów interfejsu graficznego (np. krawędzi menu pojawiającego się po kliknięciu).

Jak to wygląda w rzeczywistości? Zobaczmy sprite z biblioteki jQuery UI:

sprite

Jeden obrazek
Żądania do serwera: 1
Rozmiar: 8 KB

Oddzielne obrazki
Żądania do serwera: 173
Rozmiar: 28 KB

Teraz przejdźmy do meritum – jak sprawić, żeby zamiast dużego obrazka pokazał się jego wycinek? Zabawa sprowadza się do manipulacji 5 ustawieniami CSS:

  • width – szerokość elementu (obrazka)
  • height – wysokość elementu (obrazka)
  • background-image – obrazek tła
  • background-position – przesunięcie obrazka tła
  • background-repeat – powtarzanie obrazka tła
Przypadek 1: Sprite w elemencie blokowym

Jeżeli chcemy wstawić sprite w elemencie blokowym (np. <div>, <p> lub inny z ustawionym stylem “display: block”), to sprawa jest prosta. Przykładowo, żeby wyświetlić kopertę z powyższego obrazka (7 rząd, 6 kolumna) potrzebny jest następujący kod CSS i HTML:

   1: <style type="text/css">
   2: .icon-mail 
   3: {
   4:     width: 16px; /*szerokość sprite'a*/
   5:     height: 16px; /*wysokość sprite'a*/
   6:     background-image: url(sprite.png); /*obrazek zbiorczy*/
   7:     background-position: -80px -96px; /* -(6-1)*16px -(7-1)*16px */
   8:     background-repeat: no-repeat;
   9: }
  10: </style>
  11: ...
  12: <div class="icon-mail"></div>

Krótkie słowo wyjaśnienia, skąd wzięły się wartości w background-position:

  • -80px – gdyż obrazek zbiorczy trzeba przesunąć o 5*16px w lewo, aby ikonka koperty znalazła się tuż przy jego lewej krawędzi.
  • -96px – gdyż obrazek zbiorczy trzeba przesunąć o 6*16px do góry, aby ikonka koperty znalazła się tuż przy jego górnej krawiędzi.

Oczywiście, znacznie wygodniej jest utworzyć sobie kilka klas obsługujących cały obrazek, np.

   1: <style type="text/css">
   2: .icon16x16
   3: {
   4:     width: 16px; 
   5:     height: 16px; 
   6:     background-image: url(sprite.png); 
   7:     background-repeat:no-repeat;
   8: }
   9: .sprite16x16-1-1 { background-position: 0px 0px; }
  10: .sprite16x16-1-2 { background-position: -16px 0px; }
  11: .sprite16x16-1-3 { background-position: -32px 0px; }
  12: .sprite16x16-2-1 { background-position: 0px -16px; }
  13: .sprite16x16-2-2 { background-position: -16px -16px; }
  14: .sprite16x16-2-3 { background-position: -32px -16px; }
  15: </style>
  16: ...
  17: <div class="icon16x16 sprite16x16-2-2"></div>

 

Przypadek 2: Sprite w elemencie “inline”

Często potrzebujemy, aby sprite zachowywał się jak zwykły obrazek w tagu <img>, który można umieszczać np. w tekście. Innymi słowy, żeby zachowywał się jak element typu “inline”. Problem polega na tym, że takim elementom nie można ustawiać wysokości ani szerokości, więc gdybyśmy wstawili sprite w element <span>, to nie wyświetliłby się poprawnie.

Jednym z rozwiązań może być ustawienie “display: inline-block” (CSS 2.1). Przykładowy kod wygląda następująco:

   1: <style type="text/css">
   2: .icon16x16
   3: {
   4:     display: inline-block;
   5:     width: 16px; 
   6:     height: 16px; 
   7:     background-image: url(sprite.png); 
   8:     background-repeat:no-repeat;
   9: }
  10: .sprite16x16-1-1 { background-position: 0px 0px; }
  11: .sprite16x16-1-2 { background-position: -16px 0px; }
  12: .sprite16x16-2-1 { background-position: 0px -16px; }
  13: .sprite16x16-2-2 { background-position: -16px -16px; }
  14: </style>
  15: ...
  16: Oto ikonka <span class="icon16x16 sprite16x16-2-2"></span> w tekście.

Powyższe rozwiązanie ma pewne wady związane z niepełną/niepoprawną interpretacją “inline-block” przez starsze przeglądarki. Nie zadziała to w FireFoxie 2.0 i starszych, natomiast w IE 6 i 7 element, któremu ustawiamy “display: inline-block” musi mieć oryginalnie “display: inline” (dlatego <span> dobrze nadaje się do tego celu).

Przypadek 3: Sprite w elemencie o zmiennej szerokości lub wysokości

Technika CSS Sprites może być również zastosowana do obrazków, które mają zmienną szerokość lub wysokość. Przypuśćmy, iż chcemy zrobić ładny pasek postępu w trzech kolorach: zielonym, żółtym i czerwonym. Oczywiście, każdy pasek będzie miał szerokość proporcjonalną do prezentowanego postępu. Wówczas tworzymy obrazek, w którym pionowo jeden pod drugim umieszczamy wypełnienia dla pasków:
ProgressBarFill
Teraz możemy użyć następującego kodu:

   1: <style type="text/css">
   2: .progressbar
   3: {
   4:     width: 100px;
   5:     height: 10px;
   6:     border: solid 1px;
   7:     margin: 2px;
   8: }
   9: .progressbar>div
  10: {
  11:     height: 10px;
  12:     background-image: url(ProgressBarFill.png);
  13:     background-repeat: repeat-x;
  14: }
  15: .progressbar-red { background-position: 0px 0px; }
  16: .progressbar-yellow { background-position: 0px -10px; }
  17: .progressbar-green { background-position: 0px -20px; }
  18: </style>
  19: ...
  20: <div class="progressbar"><div style="width: 20px" class="progressbar-red"></div></div>
  21: <div class="progressbar"><div style="width: 50px" class="progressbar-yellow"></div></div>
  22: <div class="progressbar"><div style="width: 90px" class="progressbar-green"></div></div>

Efekt będzie następujący:
progress

W przypadku elementów o zmiennej wysokości postępujemy analogicznie.

Przecież to tyle pracy…

Jeżeli uważasz, że przygotowanie obrazków, klas CSS oraz przebudowanie stron, aby używały CSS Sprites, to dużo pracy… masz rację. Ale zawsze są narzędzia, które nam tą pracę ułatwiają (na przykład tutaj możemy połączyć obrazki i wygenerować do nich klasy CSS). Poza tym, jest to wysiłek jednorazowy.

Podsumowanie

Mam nadzieję, że tym wpisem przekonam kogoś do stosowania CSS Sprites. Oczywiście, gdy interfejs naszej witryny składa się z trzech obrazków na krzyż, to gra nie jest warta świeczki. Natomiast, przy większej ich ilości wydaje mi się, iż efekt końcowy rekompensuje pracę, którą trzeba wykonać na początku.

Opublikowane 26 sierpnia 2009 22:53 przez jakubin

Komentarze:

# re: Przyspieszamy ASP.NET - CSS Sprites

Stosuje się, stosuje :)

26 sierpnia 2009 23:24 by dario-g

# Jakub Binkowski - dot or not : Przyspieszamy ASP.NET - CSS Sprites

Dziękujemy za publikację - Trackback z dotnetomaniak.pl

27 sierpnia 2009 00:11 by dotnetomaniak.pl

# re: Przyspieszamy ASP.NET - CSS Sprites

Cały cykl wygląda mega-wporzo, keep'em coming:)

27 sierpnia 2009 06:37 by Procent

# re: Przyspieszamy ASP.NET - CSS Sprites

Zauwazylem te technike kilka razy ale myslalem, ze jest stosowana raczej przez wygode niz rowniez dla poprawy wydajnosci.

Fajny art, dzieki :)

27 sierpnia 2009 18:53 by binary

# re: Przyspieszamy ASP.NET - CSS Sprites

Technika stara jak świat :)

Dla przypadku 2:

Dobrze by było zastosować odpowiednio ułożone spany:

<span>tekst</span><ikona><span>dalszy tekst</span>

i dać im float:left. Wtedy będzie działało na wszystkich przeglądarkach (semantyka nieco ucierpi, ale jeżeli chcemy wspierać przestarzałe przeglądarki...).

Jeżeli chcemy wstawiać taką ikonkę w tło, wtedy korzystamy z paddinga i odpowiednio zmniejszonych wymiarów danego elementu

A i dobrze zaznajomić się z łącząną techniką backgrounu:

.... {background:url(...) Xpx Ypx no-repeat; width:Xpx; height:Ypx}

25 stycznia 2010 10:58 by kartofelek

# re: Przyspieszamy ASP.NET - CSS Sprites

@kartofelek:

Dzięki za uwagi.

"Technika stara jak świat" - true, true, niemniej jednak wiele osób nie ma świadomości jej istnienia.

25 stycznia 2010 11:15 by jakubin

# Relacja z MTS 2010

Relacja z MTS 2010

10 października 2010 21:36 by Maciej Aniserowicz

# Relacja z MTS 2010 | Maciej Aniserowicz o programowaniu

Komentarze anonimowe wyłączone

About jakubin

MVP w kategorii C#, MCP. Aktualnie pracuje w Webstruments.pl jako programista C#.