Come aumentare le performance del mio sito? – CSS Sprites

sprites_intro
Hai creato un sito, magari seguendo la nostra guida “Come creare un sito web dalla A alla Z”, ma noti che spesso i tempi di caricamento sono lunghissimi. I motivi alla base di questo comportamento possono essere molteplici, ma ci sono tanti piccoli accorgimenti da poter implementare per migliorare le performance. Oggi parleremo dei CSS Sprites.

Cosa sono gli sprites?

Durante lo sviluppo di un sito è normale utilizzare molte immagini di sfondo per realizzare vari effetti che non sono possibili utilizzando solo XHTML+CSS. Ad esempio possiamo usarle per realizzare dei titoli con un font particolare, oppure per dei bottoni per un menu. Per fare un esempio concreto, potremmo avere un menu a quattro voci, e realizzare le seguenti immagini:

single_image

E voler applicare queste immagini per lo stato hover, tramite CSS:

single_image_hover

Sono richieste in totale 8 immagini, che si traducono in 8 richieste al server, una per immagine.

Uno sprite è la combinazione di più immagini in una, divisa in sezioni e manipolata tramite CSS. Seguendo l’esempio le immagini verrano combinate nella seguente:

menu

Il concetto di sprite per il web è stato ripreso dai videogiochi anni ’80, in cui l’illusione di movimento era realizzata spostando un’immagine raffigurante i personaggi rispetto allo sfondo (nella foto il mitico Guybrush Threepwood di Monkey Island).

guybrush_sprite

Oggi quasi tutti i siti ad alto traffico utilizzano questo tipo di immagini: questa ad esempio è quella utilizzata dai siti di Google:

google_sprites

Come migliorare un menu con immagini attraverso gli sprites?

Vediamo come realizzare il menu dell’esempio usando i due metodi, valutando poi le differenze di performance del sito. Iniziamo da un semplice markup XHTML, una lista di link:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <link rel="stylesheet" type="text/css" href="no_sprites.css" />
  <title>Menu senza sprites</title>
</head>
</body>
<ul id="nav">
  <li class="home"><a href="#">Home</a></li>
  <li class="about"><a href="#">About</a></li>
  <li class="contacts"><a href="#">Contacts</a></li>
  <li class="portfolio"><a href="#">Portfolio</a></li>
</ul>
</body>
</html>

Come puoi notare, ogni link ha una classe associata, per poter collegare il codice CSS. Applichiamo prima qualche formattazione di base, come la riduzione dei margini e alcuni accorgimenti per il testo:

body,h1,ol,ul,li,p{margin:0;padding:0;}

body{
  background-color:#FFF;
  color:#000;
  font:75%/1.4 Helvetica,Verdana,Arial,sans-serif;
}

Ora rimuoviamo gli stili di default dalla lista non ordinata e allineiamo gli elementi applicando un float a sinistra:

...
#nav{
	list-style:none;
	margin:20px;
}

#nav li{
	float:left;
	margin:0 4px;
}
...

Guardando il risultato, ci accorgiamo di essere sulla buona strada: gli elementi sono allineati orizzontalmente e hanno un piccolo margine che li separa. Prima di procedere con l’applicazione delle immagini, dobbiamo avere una piccola accortenza di grande importanza, ovvero dare ai vari link la dimensione esatta dell’immagine che in questo caso è di 100px di larghezza per 27px di altezza:

#nav{
	list-style:none;
	margin:20px;
	text-indent:-9999px; //questa regola nasconde il testo
}

#nav li a:link, #nav li a:visited{
	display:block;
	width:100px;
	height:27px;
}
...

La direttiva display:block è molto importante, perché rende cliccabile tutta l’area del link e non solo il testo interessato. Ho inoltre nascosto il testo dei link, utilizzando la proprietà text-indent. Procediamo dunque con l’applicazione delle immagini:

...
.home a:link, .home a:visited {background-image: url(home.png);}
.about a:link, .about a:visited {background-image: url(about.png);}
.contacts a:link, .contacts a:visited {background-image: url(contacts.png);}
.portfolio a:link, .portfolio a:visited {background-image: url(portfolio.png);}

.home a:hover, .home a:focus {background-image: url(homeh.png);}
.about a:hover, .about a:focus {background-image: url(abouth.png);}
.contacts a:hover, .contacts a:focus {background-image: url(contactsh.png);}
.portfolio a:hover, .portfolio a:focus {background-image: url(portfolioh.png);}
...

Questo blocco di codice può spaventare, ma in realtà le regole sono molto semplici: ad ogni classe sono associate due immagini, una per gli stati “normale” e “visitato”, e una per gli stati “hover” e “focus” (quest’ultimo è attivato quando il link viene selezionato tramite il tasto TAB). Il risultato finale è perfettamente funzionante, ma possiamo migliorarlo attraverso gli sprites. Nota infatti come la prima volta che passi il cursore del mouse su un link c’è un piccolo ritardo nella transizione tra le due immagini: questo ritardo è dovuto al tempo di caricamento dell’immagine hover. Vediamo come eliminare questo fastidioso effetto indesiderato.

Come utilizzare gli sprites?

Per capire il funzionamento basta immaginare di guardare un poster su un muro attraverso un rettangolo ritagliato in un cartoncino: le parti circostanti il ritaglio ci impediscono di vedere il poster nella sua interezza, avendo quindi percezione di una parte limitata dell’immagine.

sprite_spiegate

Come mostrato nell’immagine, attraverso CSS spostiamo l’immagine di sfondo, e l’aver impostato l’esatta dimensione per i link precedentemente ci garantisce che verrà visualizzata esattamente la porzione di immagine che ci interessa.

Un altro vantaggio degli sprites è che le modifiche al codice sono minime, interessando esclusivamente il CSS. La prima modifica è l’aggiunta della stessa immagine di sfondo per tutti i link del menu:

...
#nav li a:link, #nav li a:visited{
	background-image: url(menu.png); //unica immagine per tutti i link
	display:block;
	height:27px;
	width:100px;
}
...

Una volta fatto questo, dobbiamo posizionare lo sfondo inserendo le giuste coordinate per ogni elemento. Per conoscere queste coordinate possiamo aiutarci con un programma di fotoritocco qualsiasi, come GIMP o Photoshop. In questo caso è relativamente semplice, dato che gli elementi sono tutti della stessa dimensione. Vediamo come è strutturata una dichiarazione:

...
.about a:link, .about a:visited {background-position: -100px 0;}
...

Abbiamo utilizzato la regola background-position che prende come parametri lo spostamento orizzontale e quello verticale, in quest’ordine. Come abbiamo visto nell’immagine esplicativa, il pulsante “About” occupava la posizione a 100px dal bordo sinistro e a 0px da quello superiore. Dato che dobbiamo spostare l’immagine verso sinistra, il valore da inserire dovrà essere negativo. Facendo un po’ di conti si ricavano facilmente le posizioni di ogni elemento:

.home a:link, .home a:visited {background-position: 0 0;}
.about a:link, .about a:visited {background-position: -100px 0;}
.contacts a:link, .contacts a:visited {background-position: -200px 0;}
.portfolio a:link, .portfolio a:visited {background-position: -300px 0;}

.home a:hover, .home a:focus {background-position: 0 -28px;}
.about a:hover, .about a:focus {background-position: -100px -28px;}
.contacts a:hover, .contacts a:focus {background-position: -200px -28px;}
.portfolio a:hover, .portfolio a:focus {background-position: -300px -28px;}

E questo è il risultato finale.

Considerazioni finali

L’uso delle immagini sprite nello sviluppo di un sito web è un aspetto molto sottovalutato: a fronte di qualche ora impiegata per la creazione dell’immagine, si hanno vantaggi sia sotto l’aspetto di diminuzioni di richieste al server, sia come dimensioni dei file scaricati (infatti l’immagine totale è di dimensioni inferiori rispetto alla somma delle singole immagini). Effettuando dei test sull’esempio mostrato nell’articolo, si nota che nella versione con immagini multiple, il caricamento della pagina è distribuito nell’arco di circa 3.82 secondi, a causa del successivo caricamento delle immagini degli stati “hover”, mentre la versione con sprite impiega solo 0.521 secondi, scaricando tutti gli elementi della pagina.

single_images_small
image_sprites_small

Il guadagno totale è quindi circa del 50% (considerando il tempo di caricamento della pagina).

Bisogna però fare alcune considerazioni sul caso: credo che questa tecnica sia utile una volta stabilita una versione definitiva del sito, perché la creazione della sprite contenente tutti gli elementi di un sito è un’operazione abbastanza laboriosa.

Quindi la mia opinione è: immagini singole in fase di sviluppo e di testing, e sprites per la versione definitiva del layout. Tu cosa ne pensi?

Tag: ,

L'autore

Appassionato di web design, si diletta a creare dei layout (X)HTML+CSS. È un maniaco del codice pulito e ordinato, il tipo di persona che vi ritrovate in casa a raddrizzarvi i quadri appesi alla parete. Ha deciso che diventerà un web designer con la “doppia vvu” maiuscola, e trascorre intere nottate sveglio per realizzare il suo sogno.

Sito web dell'autore | Altri articoli scritti da

Articoli correlati

Potresti essere interessato anche ai seguenti articoli:

30 commenti

Trackback e pingback

  1. uberVU - social comments
    Social comments and analytics for this post... This post was mentioned on Twitter by nando_p: RT @YIW Come aumentare le…
  2. Twitter Bootstrap: come sviluppare rapidamente applicazioni web? | Your Inspiration Web
    [...] cartella IMG ha al suo interno, invece, due sprites utilizzate per le icone dei pulsanti, dei menu, ecc. Le…
  3. Come rendere trasparenti gli elementi con CSS3? | Your Inspiration Web
    [...] di un’immagine. Questo effetto prima doveva essere creato utilizzando più immagini (magari utilizzando una sprite) ed era un incubo…