Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Slider di immagini con Javascript e CSS3

Sfruttiamo Javascript e le capacità di animazione offerte dai CSS3 per realizzare uno slider di immagini che funziona su tutti i browser.
Sfruttiamo Javascript e le capacità di animazione offerte dai CSS3 per realizzare uno slider di immagini che funziona su tutti i browser.
Link copiato negli appunti

Grazie al supporto sempre più capillare dei moduli CSS3 sui vari browser, è possibile realizzare interfacce complesse senza ricorrere a JavaScript.

Partendo da quest'idea, realizzaremo uno slider di immagini riducendo al minimo l'uso di JavaScript pur mantenendo un supporto di base anche ai browser meno avanzati. In alcuni casi dovremo limitarne la flessibilità, ma solo per semplificare gli script in questo contesto.

Requisiti funzionali

A livello di funzionalità dovremo sviluppare uno slider con le seguenti caratteristiche:

  • scrolling orizzontale di una serie di immagini con uguali dimensioni (conoscendone numero e larghezza);
  • navigazione fra le immagini tramite controlli di avanzamento o link alle immagini.

Requisiti tecnici

A livello tecnico adotteremo la tecnica del progressive enhancement per offrire la miglior esperienza utente in base alle funzionalità supportate dal browser. I nostri obiettivi sono:

  • garantire la fruibilità dei contenuti con e senza JavaScript;
  • ridurre al minimo l'uso di librerie in favore di soluzioni native;
  • evitare l'uso di animazioni JavaScript in favore dei moduli CSS3;
  • raggiungere il massimo delle performance nel caricamento e la miglior fluidità nelle animazioni.

A partire da questi requisiti svilupperemo il nostro slider secondo questo schema (tra parentesi alcune versione dei browser usati come riferimento):

  • solo CSS2 e HTML: supporto di base con barra di scorrimento orizzontale nativa del browser e pulsanti per navigare fra le immagini;
  • supporto a JavaScript (IE7+, FF3.6 e precedenti): navigazione senza barra di scorrimento, controlli di avanzamento, nessuna animazione;
  • supporto alle transizioni CSS3 (FF4, Chrome8+, Safari 3.2+, Opera10.50+): scorrimento animato;
  • supporto alle trasformazioni 3D (Chrome10+, Safari5+, Mobile Safari): immagini traslate con trasformazioni 3D per sfruttare l'accelerazione 3D della GPU ed ottimizzare la fluidità del movimento, soprattutto per i browser mobile.

HTML e CSS di base

Per iniziare, il markup del nostro slider non è dissimile da quello di tante altre gallerie JavaScript:

<div id="container">
<div id="wrapper">
<ul class="slider">
<li><img src="img/1.jpg" id="img1" alt="" /></li>
<li><img src="img/2.jpg" id="img2" alt="" /></li>
...
</ul>
</div>
<div class="navigation">
<a href="#" class="nav_prev js-shown">Indietro</a>
<a href="#img1" class="nav_btn">1</a>
<a href="#img2" class="nav_btn">2</a>
...
<a href="#" class="nav_next js-shown">Avanti</a>
</div>
</div>

Da notare che alcuni elementi hanno una classe js-shown che ci servirà per mostrarli o meno in base al supporto JavaScript del browser.

Per il CSS di base utilizzeremo l'ultima versione del Reset CSS di Eric Meyer per poi assegnare uno stile ai nostri elementi:

#container {
margin: 30px;
}
#wrapper {
border: 1px solid #ccc;
height: 320px;
margin-bottom: 10px;
overflow-x: auto;
overflow-y: hidden;
position: relative;
width: 480px;
}
.slider {
position: absolute;
top: 0;
left: 0;
height: 320px;
width: 1920px; /* larghezza totale */
}
.slider li {
float: left;
height: 320px;
width: 480px;
}
.slider img {
display: block;
}
/* link di navigazione */
.navigation {
overflow: hidden;
width: 100%;
}
.navigation a {
background: #ccc;
color: #333;
font: bold 14px arial, helvetica, sans-serif;
display: block;
float: left;
padding: 4px 10px;
margin-right: 5px;
text-decoration: none;
}
.navigation a:active {
background-color: #999;
}
.js-shown {
display: none !important;
}

In questa demo potete visualizzare la versione già funzionante del nostro slider.

Supporto JavaScript

Sui browser che supportano JavaScript possiamo migliorare l'esperienza utente eliminando la barra di scorrimento nativa del browser ed aggiungendo i controlli di avanzamento. Poiché questi ultimi sono già presenti nell'HTML ma nascosti, dobbiamo provvedere a mostrarli via JavaScript e CSS:

//CSS
.hasjs .js-shown {
display: block;
}
.hasjs #wrapper {
overflow: hidden;
}
//JavaScript
//aggiunge la classe hasjs al tag html
document.documentElement.className += ' hasjs';

Con questa tecnica non dovremo aspettare l'evento DOMready per modificare gli stili ed eviteremo così spiacevoli flash in fase di caricamento.

A questo punto iniziamo a sviluppare il costruttore Slider utilizzando una self-executing function in modo da mantenere il namespace globale pulito. Al suo interno definiremo alcune funzioni e variabili per verificare il supporto ad alcune funzionalità, ed eventualmente ricorrere a soluzioni di fallback.

var Slider = (function (window){
// rilevo il supporto nativo alla selezione degli elementi con query CSS
var _hasQuerySelector = 'querySelectorAll' in document;
//supporto universale all'aggiunta di eventi
//based on http://ejohn.org/projects/flexible-javascript-events/
function addEvent( obj, type, func ) {
var fn = function (e) {
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
func();
};
if ( obj.attachEvent ) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
obj.attachEvent( 'on'+type, obj[type+fn] );
} else {
obj.addEventListener( type, fn, false );
}
}
//selezione degli elementi via query CSS
function getEls (selector, context) {
var parent = context || document;
// uso Sizzle come fallback
return _hasQuerySelector ? parent.querySelectorAll(selector) : Sizzle(selector, parent);
}
//Estraggo il primo elemento di una query
function getEl (selector, context) {
return getEls(selector, context)[0];
}

Oltre alla funzione addEvent, che ci permette di utilizzare lo script con IE7 e 8, abbiamo anche impostato un fallback a Sizzle (il selector engine di jQuery) nel caso non fosse disponibile querySelectorAll (come avviene in IE7).

Il passo successivo è quello di definire il costruttore dello slider in una variabile privata:

var _Slider = function (wrapper) {
//il contenitore dello slider
var $wrapper = document.getElementById(wrapper),
//navigazione indietro
$navPrev = getEl('.nav_prev', $wrapper),
//navigazione avanti
$navNext = getEl('.nav_next', $wrapper),
//puntatori diretti alle immagini
$navBtns = getEls('.nav_btn', $wrapper),
//questo riferimento a this ci servirà più tardi
that = this;
//salvo un riferimento interno ad alcuni elementi
this.$slider = getEl('.slider', $wrapper);
// numero totale delle immagini
this.IMAGE_COUNT = getEls('.slider img', $wrapper).length || 0;
// l'immagine visualizzata corrente
this.current_img = 0;
//agganciamo gli eventi ai controlli...
//...immagine precedente
addEvent($navPrev, 'click', function () {
that.prev();
});
//...immagine successiva
addEvent($navNext, 'click', function () {
that.next();
});
//.., puntatori
for (var i=0, l = $navBtns.length; i < l; i++) {
addEvent($navBtns[i], 'click',
//uso una closure per "fissare" il valore di i
(function () {
var index = i;
return function () {
that.seek(index);
};
})()
);
}
};

Nel costruttore abbiamo fatto riferimento ai metodi .prev(), .next() e .seek() che andremo a definire nel prototipo comune ad ogni istanza dell'oggetto:

_Slider.prototype = {
//larghezza di default dell'immagine
IMAGE_WIDTH : 480,
seek : function (index) {
if (index < 0 || index >= this.IMAGE_COUNT) {
index = 0; //normalizza il puntatore
}
//imposto l'immagine corrente
this.current_img = index;
//visualizzo l'immagine richiesta
this._animateSlide('-' + (index*this.IMAGE_WIDTH) + 'px');
},
next : function () {
this.seek(this.current_img + 1);
},
prev : function () {
this.seek(this.current_img - 1);
},
_animateSlide : function (amount) {
//modifico la proprietà CSS left del contenitore delle immagini
this.$slider.style.left = amount;
}
};

L'ultimo passo per rendere usabile il costruttore è esporlo nel namespace globale e chiudere la funzione auto-eseguente:

//sopra c'è il prototipo
return _Slider;
})(window);

Infine inizializziamo un oggetto Slider:

// browser standard-compliant
if ( document.addEventListener ) {
document.addEventListener('DOMContentLoaded', function () {
new Slider('#wrapper');
}, false);
// fallback per IE
} else if ( window.attachEvent ) {
window.attachEvent('onload', function () {
new Slider('#wrapper');
});
}

Vediamo un esempio dello slider in azione.

Aggiungere del movimento

Per aggiungere un effetto di movimento al passaggio da un'immagine all'altra ci appoggeremo alle transizioni CSS3. Per farlo basterà aggiungere poche righe di codice al file CSS:

.hasjs .slider {
-webkit-transition: all 0.5s ease-out;
-moz-transition: left 0.5s ease-out;
-o-transition: left 0.5s ease-out;
transition: left 0.5s ease-out;
}

Ecco il risultato.

Da notare che, per quanto riguarda la regola CSS per Webkit, abbiamo impostato una transizione per tutte le proprietà CSS dell'elemento. Questo ci introduce all'ultima fase di realizzazione del nostro script, in cui useremo le trasformazioni CSS 3D per sfruttare l'accelerazione 3D ed avere una maggiore fluidità nell'animazione.

Animazioni con accelerazione 3D

La prima cosa da fare è verificare il supporto alle trasformazioni 3D. Inseriremo il codice necessario all'inizio della funzione auto-eseguente:

var _hasQuerySelector = ... ,
_has3DSupport = (( 'WebKitCSSMatrix' in window) && 'm11' in (new WebKitCSSMatrix) );

Infine dovremo modificare il metodo ._animateSlide():

_animateSlide : function (amount) {
if (_has3DSupport) {
this.$slider.style.WebkitTransform = 'translate3d(' + amount + ', 0, 0)';
} else {
this.$slider.style.left = amount;
}
}

Un'ultima ottimizzazione è quella di impostare il valore iniziale della trasformazione nel CSS, in modo da abilitare fin dall'inizio il rendering 3D sull'elemento che andremo ad animare:

.hasjs .slider {
-webkit-transform: translate3d(0,0,0);
}

Ecco il risultato finale (per godere dell'accelerazione 3D dovrete testare lo slider su iPhone, Safari 5.0+ o Chrome 10.0+).

Conclusioni

Grazie ai nuovi moduli CSS3 ed al supporto JavaScript nativo di features avanzate, siamo riusciti a contenere il peso del file JavaScript con un'ottima compatibilità e buone performance. Tutti i file di esempio sono disponibili per il download.

Se inoltre volessimo estendere l'animazione anche ai browser che non supportano le transizioni CSS3, potremmo rivolgerci a librerie di effetti molto leggere come Émile evitando di ricorrere a librerie troppo ingombranti.

Ti consigliamo anche