In questo articolo affronteremo la creazione di una pagina web di presentazione, l'ideale per una home page personale o un piccolo portfolio, e implementeremo con poche righe di codice un semplice script per la gestione della navigazione con le ancore tra i link interni e le loro destinazioni, ottenendo un piacevole effetto scorrimento.
Naturalmente i contenuti della pagina saranno accessibili e perfettamente visualizzabili anche con Javascript disabilitato. Buona la resa cross-browser: sono supportati tutti i browser moderni, da Internet Explorer 6 in su.
I tre esempi allegati all'articolo presentano lo stesso markup HTML; differiscono solo per il framework Javascript impiegato, che ho selezionato tra quelli di maggiore utilizzo: Prototype, JQuery e MooTools. La scelta della libreria da utilizzare è poi delegata alle preferenze e convinzioni di ognuno.
Avremmo potuto ottenere il medesimo effetto anche senza includere un framework; esistono molti script “stand alone” che fanno la stessa cosa (da leggere a tal proposito un precedente articolo di Cesare Lamanna).
Prima di cominciare vediamo subito l'esempio.
Il markup HTML
La nostra pagina ha una struttura molto semplice: header e footer con larghezza al 100% della finestra, mentre i contenuti sono in un div della larghezza voluta centrato nella pagina. Le varie sezioni del sito sono racchiuse in altrettanti div, ognuno con un id, su cui punteranno i link interni (ancore #) del menu di navigazione, contenuto nell'header.
Per rendere l'interfaccia più usabile, attraverso i CSS ho assegnato una posizione fissa all'header, che così rimane ancorato in alto sulla finestra del browser durante lo scorrimento della pagina. Questo comporta che il navigatore potrà avere sempre sott'occhio il menu per spostarsi tra le varie sezioni.
Purtroppo Internet Explorer 6 non supporta la regola CSS utilizzata, position:fixed
. Semplicemente su questo browser durante lo scrolling l'header non rimarrà fermo ma si muoverà con il resto del documento. Per migliorare l'usabilità ho inserito alla fine di ogni sezione di contenuti un collegamento per tornare all'inizio della pagina.
Il codice di Prototype
Nell'esempio ho utilizzato un file Javascript compresso contenente le ultime release di Prototype e Scriptaculous, includendo solo 'effect' tra le varie tipologie di effetti disponibili. Il resto del codice, cioè lo script che utilizzeremo, è incluso direttamente nel tag script
della pagina, ma solo per velocizzarne la lettura e la modifica in fase di test. L'autore del codice è Tobie Langel, uno dei core members di Prototype, (qui l'articolo originale nel suo blog). Ecco il codice:
<script type="text/javascript"> // Copyright (c) 2007 Tobie Langel (http://tobielangel.com) // Use as you please - just don't make it the new black! // Full tutorial available here: http://tobielangel.com/2007/3/11/a-fistful-of-dollars // Based on an idea by Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) document.observe ('dom:loaded', function() { //Event.observe(window, 'load', function() { $$('a[href^=#]:not([href=#])').each(function(element) { element.observe('click', function(event) { new Effect.ScrollTo(this.hash.substr(1)); Event.stop(event); }.bindAsEventListener(element)) }) }) </script>
Per prima cosa lo script trova tutti link in cui l'attributo href
contiene come primo carattere il simbolo # che fanno riferimento ognuno alla relativa sezione di contenuti. Attraverso la funzione $$(css selector...)
otteniamo un array di tutti questi elementi corrispondenti al selettore applicato: a[href^=#]:not([href=#]
. Grazie a Prototype (ma la stessa cosa vale per MooTools e JQuery) abbiamo la piena compatibilità cross-browser di quasi tutti i selettori CSS3. Da notare in questo caso specifico che selezioniamo tutti i tag <a>
che cominciano per “#” ma che non (not
) sono uguali a “#”, questo per evitare un errore Javascript nel caso di click su eventuali link “vuoti”, spesso utilizzati in modo un po' invasivo in alcuni script.
Il secondo passo è quello di intercettare il click sui nostri link: Prototype facilita molto la gestione degli eventi, attraverso l'oggetto event
e il metodo observe
. Essendo l'array dei nostri elementi (estratti con $$
) un enumerable, possiamo iterare su ognuno di questi e al verificarsi dell'evento eseguire la funzione di callback che produrrà lo scrolling.
Da non sottovalutare il fatto che è necessario bloccare l'azione predefinita del click sul collegamento, che, altrimenti, seguendo il link impedirebbe il funzionamento dello script.
Ora possiamo esaminare la funzione di callback che produce l'effetto di scorrimento della pagina: entra in gioco Scriptaculous. Viene infatti creata una nuova istanza di Effect.scrollTo
, a cui viene passato l'id dell'elemento che vogliamo raggiungere: tale id viene estratto leggendo il valore dell'attributo href
dell'elemento cliccato, ed eliminando il # all'inizio della stringa.
Per attivare il codice esaminato, in luogo del vecchio window onload
, con Prototype possiamo utilizzare document.observe
, che intercetta l'evento dom:loaded
; in pratica lo script viene eseguito non appena sia disponibile l'albero DOM del documento, senza attendere il caricamento degli elementi esterni alla pagina(ad esempio le immagini).
Il codice di Jquery
Questo esempio include JQuery 1.3.1 in versione compressa, prelevata direttamente dal sito ufficiale. Devo dire che il codice dello script è molto simile al precedente e non necessita di tante spiegazioni:
<script type="text/javascript"> $(document).ready(function(){ $('a[href^=#]:not([href=#])').click(function(e){ $('html, body').animate({ scrollTop: $($(this).attr("href")) .offset().top }, 1000); e.preventDefault(); }); }); </script>
Anche JQuery dispone di un metodo simile a document.observe
per intercettare l'evento domready
della pagina: si chiama document.ready
. Inoltre, la funzione $()
attraverso i selettori CSS permette di operare subito sull'array degli elementi restituiti, senza effettuare cicli o iterazioni. Che dire? Molto veloce! Per bloccare il comportamento di default dei link in questo caso si utilizza event.preventDefault()
, ma avremmo potuto mettere anche un classico return false
. Il movimento di scrolling è delegato all'effetto animate()
, che si applica sull'elemento e accetta diversi parametri opzionali, compresa anche una eventuale funzione di callback.
Per chi fosse interessato, non posso non citare l'interessante plugin ScrollTo scritto da Ariel Flesler che in tema di scrolling ci consente di ottenere molteplici soluzioni con estrema semplicità.
Il codice di Mootools
Anche il codice scritto con MooTools è molto simile ai precedenti, anzi presenta particolare affinità soprattutto con quello del “cugino” Prototype: l'esempio richiede il core 1.2.1, naturalmente la versione più aggiornata, e l'inclusione dell'effetto fx.scroll
. Prelevando i file dal sito ufficiale, possiamo scegliere la versione compressa con l'utilità di YUI.
Per onore di completezza, c'è da dire che esiste anche una classe che estende fx.scroll
(e che ne è figlia), che è stata appositamente creata per gestire lo scrolling degli elementi, Smoothscroll. L'utilizzo è veramente semplice e si presta perfettamente alla nostra causa: eccone un esempio. Basta creare una nuova istanza di SmoothScroll ed il gioco è fatto. Ecco il codice:
<script type="text/javascript"> window.addEvent('domready',function() { new SmoothScroll({ duration: 1000 }); }); </script>
Tutti gli esempi sono disponibili per il download.