In “CSS Sprites2 – It’s JavaScript Time“, pubblicato su Alistapart, Dave Shea ci presenta una tecnica semplice e degradabile per applicare effetti di movimento sulle nostre interfacce di navigazione. Ho trovato quest’articolo estremamente ben fatto. Ho riproposto, qui di seguito i passaggi più rilevanti cercando di chiarirli a chi magari non conosce jQuery e vuole avvicinarsi a questa libreria con un esempio operativo.
Prima di tutto si crea una semplice lista:
[html]
[/html]
<ul> ha due classi, la prima “nav” ci permette di identificare l’interfaccia di navigazione dalle altre liste mentre la seconda, in questo caso “current-about” serve ad tener traccia della pagina in cui ci troviamo. Ogni list element ha la propria classe univoca.
Lo scopo è quello di ottenere al contempo un codice semplice e tutte le classi necessarie per inserire gli sprites.
A questo punto posizioniamo in modo assoluto il contenitore <ul>
[css]
.nav {
width: 401px;
height: 48px;
background: url(../i/blue-nav.gif) no-repeat;
position: absolute;
top: 100px;
left: 100px;
}
[/css]
Posizionare il contenitore (in modo assoluto o relativo) ci permetterà di sfruttare <ul> come riferimento per i list element (posizionati anch’essi in modo assoluto).
Ora si implementano gli elementi chiave relativi ai link contenuti nei list element posizionandoli in modo assoluto rispetto al contenitore <ul>:
[css]
.nav li a:link, .nav li a:visited {
position: absolute;
top: 0;
height: 48px;
text-indent: -9000px;
overflow: hidden;
}
.nav .home a:link, .nav .home a:visited {
left: 23px;
width: 76px;
}
.nav .home a:hover, .nav .home a:focus {
background: url(../i/blue-nav.gif) no-repeat -23px -49px;
}
.nav .home a:active {
background: url(../i/blue-nav.gif) no-repeat -23px -98px;
}
[/css]
Quello che si ottiene è riportato chiaramente nell’articolo originale; un semplice menu con effetto hover (condizione rispetto alla quale viene caricata un immagine di background contenente già tutti gli elementi grafici necessari e riposizionata rispetto alle dimensioni stabilite per il pulsante). Le 4 classi qui sopra andranno replicate per tutti i pulsanti (home, about, services e contact).
Inizializzare jQuery
A questo punto è necessario (se non lo avete già fatto) inizializzare jQuery. Collegate il framework e inizializzate lo script in questo modo:
[js]
$(document).ready(function(){
// qui metto lo script che viene eseguito quando il DOM è stato completamente caricato
});
[/js]
Ora via jQuery disattivo l’effetto hover, active ecc… impostato via CSS. In questo modo inizializzo il menu per l’effetto javascript che voglio ottenere ed al contempo faccio in modo che a js disattivati riemerga il comportamento precedentemente impostato via CSS (così abbiamo una degradazione a tre livelli: menu animato, menu CSS, lista semplice).
[js]
$(“.nav”).children(“li”).each(function() {
$(this).children(“a”).css({backgroundImage:”none”});
});
[/js]
Con la prima riga filtro e ciclo tutti gli elementi <li> figli della classe .nav. Con la seconda riga seleziono i link contenuti negli elementi ciclati dalla funzione e setto la proprietà background_image a “none”. Così ottengo una cosa del genere.
[js]
$(“.nav”).children(“li”).each(function() {
var current = “nav current-” + ($(this).attr(“class”));
var parentClass = $(“.nav”).attr(“class”);
if (parentClass != current) {
$(this).children(“a”).css({backgroundImage:”none”});
}
});
[/js]
A questo punto ciclo tutti i figli (li) della classe nav e setto due variabili (current e parentClass). “current” è una stringa fatta dalla concatenazione della sottostringa “nav current-” e la classe dell’elemento lista attualmente ciclato (vi ricordo che ul ha una classe di questo tipo “current-…”). “parentClass” va a leggere l’attributo class di un elemento avente come classe .nav (ul ha sia “nav” che “current-…” quindi parentClass sarà uguale a “nav current-…”).
A questo punto è necessario creare una funzione che ci permetta di controllare ogni forma di interazione con gli elementi lista:
[javascript]
function attachNavEvents(parent, myClass) {
$(parent + ” .” + myClass).mouseover(function() {
// do things here
}).mouseout(function() {
// do things here
}).mousedown(function() {
// do things here
}).mouseup(function() {
// do things here
});
}
[/javascript]
La funzione ha due argomenti (in realtà ciò la rende più flessibile ed applicabile a liste differenti, nel nostro caso potremmo passare alla funzione solamente la classe dell’elemento lista visto che .nav rimane un elemento fisso). La funzione sfrutta una caratteristica tipica di jQuery, ovvero la possibilità di concatenare diversi comportamenti in un unica riga di comando usando la notazione punto (per approfondimenti vedi la documentazione alla voce Chainability). In questo modo è possibile controllare tutti gli aspetti degli elementi lista in modo sintetico e leggibile.
Ora quindi aggiungeremo allo script principale la chiamata alla funzione per ogni elemento lista presente nel nostro menu (ovviamente non avendo impostato ancora nessun effetto per i comportamenti non vedremo ancora nulla)
[javascript]
attachNavEvents(“.nav”, “home”);
attachNavEvents(“.nav”, “about”);
attachNavEvents(“.nav”, “services”);
attachNavEvents(“.nav”, “contact”);
[/javascript]
A questo punto Shea introduce un piccolo trucco che a quanto pare rende più efficiente l’implementazione degli effetti di jQuery sul menu: invece di applicare direttamente tali effetti sugli elementi del menu li va ad applicare a dei div creati “al volo” via javascript. Questi div avranno una classe già devinita nei CSS (ce dovrà essere una per ogni elemento del menu):
[css]
.nav-home {
position: absolute;
top: 0;
left: 23px;
width: 76px;
height: 48px;
background: url(blue-nav.gif) no-repeat -23px -49px;
}
[/css]
Ogni div sarà posizionato in modo assoluto e si ritaglierà dall’immagine completa che contiene tutti i pulsanti e gli stati dei pulsanti solo la parte necessaria (questo approccio riduce notevolmente i tempi di caricamento del menu risolvendo in un unica richiesta al server tutte le immagini di cui il menù ha bisogno per funzionare).
Ora è tempo di implementare gli effetti (qui di seguito l’esempio per due stati: mouseover e mouseout):
[javascript]
function attachNavEvents(parent, myClass) {
$(parent + ” .” + myClass).mouseover(function() {
$(this).before(‘
‘);
$(“div.nav-” + myClass).css({display:”none”}).fadeIn(200);
}).mouseout(function() {
// fade out & destroy pseudo-link
$(“div.nav-” + myClass).fadeOut(200, function() {
$(this).remove();
});
});
}
[/javascript]
Con $(this).before andiamo a creare il div subito dopo l’elemento lista. Poi il div viene prima di tutto nascosto e con fadeIn(200) fatto apparire a una velocità di 200ms.
Quello che si ottiene dovrebbe essere simile a questo.
Naturalmente lo script si può completare aggiungendo con il medesimo principio altri div con classi differenti anche per gli altri due stati (mousedown e mouseup). In questo caso Shea sfrutta jQuery esclusivamente per creare i div e le classi e lascia fare il resto ai CSS creando classi ad hoc e visualizzando la parte di immagine contente lo stato corretto.
Naturalmente si possono utilizzare altri effetti come slideUp (vedi esempio).
In conclusione quello che si ottiene è un ottimo menu degradabile per i browser più vecchi, che funziona a js disattivati e in assenza dei CSS. Per com’è strutturato (è indubbiamente elegante ed ingegnoso) però lo vedo di difficile implementazione nei casi in cui abbiamo a che fare con un menu dinamico (come quello di un CMS).
Shea ci fornisce anche tutti gli script raggruppati in un file comodo comodo.






2 Risposte
[...] i tempi di attesa. Per ovviare a questo problema si puù utilizzare la tecnica dei CSS Sprite (ne avevamo già parlato qui). In quona sostanza invece che utilizzare icone da pochi kappa è meglio utilizzare grandi tavole [...]
[...] La traduzione italiana di Semanticstone [...]