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

Slideshow e 'navigazione orizzontale' con jQuery

Un primo approccio alla creazione da zero di uno slideshow che possa essere sfruttato anche su dispositivi mobili.
Un primo approccio alla creazione da zero di uno slideshow che possa essere sfruttato anche su dispositivi mobili.
Link copiato negli appunti

In questo articolo mostreremo come creare una esperienza di navigazione orizzontale dei contenuti, miscelando la voglia di riprodurre una user experience simile a quella offerta dagli slideshow o dai tablet, alla necessità di caricare contenuti in modo tradizionale. In altre parole l'idea è di "sfogliare il sito" caricando una pagina nuova ad ogni transizione.

Affronteremo la questione in tre parti:

  • nella prima creeremo la struttura HTML e CSS del nostro slideshow, ovvero del contenitore
  • nella seconda affronteremo il codice jQuery di base
  • nella terza ed ultima parte estenderemo il nostro slideshow al mondo mobile aggiungendo un tipico effetto "swipe"

La struttura dello slideshow

La caratteristica principale dello slideshow quella di rappresentare un contenitore che si estende su tutta la pagina.

Per non lasciare l'utente disorientato, utilizziamo un menu di navigazione e associeremo ad ogni pagina del sito una voce del menu. La voce di menu corrispondente alla slide visualizzata sarà evidenziata con un differente colore sia per il testo che per lo sfondo.

Il nostro slideshow quindi si comporrà dei seguenti elementi:

  • Il contenitore principale delle slide
  • Le pagine (slide) con i contenuti
  • I pulsanti "Avanti" ed "Indietro" posti ai lati
  • Un menu di navigazione superiore

Il contenitore principale è centrato nella pagina e al suo interno le slide verranno disposte una accanto all'altra mediante l'interazione tra CSS e jQuery.

I pulsanti dello slideshow saranno posizionati in modo assoluto ai lati della pagina e centrati verticalmente. Vediamo ora la struttura HTML del nostro slideshow:

<div id="site">
  
<div id="nav">
  <ul id="navigation">
    <li><a href="#home" class="current" data-rel="0">Home</a></li>
    <li><a href="#articoli" data-rel="1">Articoli</a></li>
    <li><a href="#about" data-rel="2">About</a></li>
  </ul>
</div>

<div id="content">
  <div id="content-wrapper">
    <div class="page" id="home"><!-- prima slide --></div>
  	<div class="page" id="articoli"><!-- seconda slide --></div>
  	<div class="page" id="about"><!-- terza slide --></div>
  </div>
  
  <a href="#" id="previous">Prec.</a>
  <a href="#" id="next">Succ.</a>
  <img src="img/loading.gif" alt="" id="loader"/>
</div>
  
</div>

Abbiamo aggiunto anche un'immagine GIF che fungerà da immagine di preload

  1. Tramite l'ancora contenuta nell'attributo href
  2. Tramite l'attributo custom HTML5 data-rel

Questo legame ci semplificherà la vita quando definiremo il codice jQuery.

In un caso reale di navigazione orizzontale tra le categorie di un sito, cose come la definizione dei contenuti o la presenza di elementi come il menu di navigazione possono subire profondi cambiamenti: i contenuti potrebbero essere presi in modo dinamico dal CMS e il menu di navigazione integrato direttamente nel contenuto ad esempio. In questo momento però ci interessa mostrare un comportamento di base e semplificare tutto il resto.

Codice CSS

Nel nostro layout ci sono sia elementi posizionati in modo statico (nel flusso del documento) che elementi posizionati in modo assoluto (fuori dal flusso del documento). A metà di questi due contesti di formattazione si pongono i contenuti (le slide), che verranno flottati all'interno del contenitore.

Se ogni slide è larga 800 pixel, tre slide richiedono 2400 pixel di spazio. Ovviamente nessuno schermo ha questa risoluzione, quindi si impiega una tecnica fondamentale in ogni slideshow: il contenitore più esterno delle slide (#content) avrà la dichiarazione overflow:hidden. Tale dichiarazione ci permette di mostrare solo 800 pixel per volta, sopprimendo la visualizzazione del contenuto in eccesso.

Ma il cuore di ogni slideshow sta nel contenitore più interno (#content-wrapper), la cui larghezza totale verrà impostata sommando le larghezze di tutte le slide. Questo farà in modo che le slide si dispongano su un'unica riga, ma ha anche un altro effetto importante: impostando infatti position: relative su questo contenitore, non solo gli permetteremo di scorrere da destra a sinistra, ma faremo anche in modo che ciascuna slide abbia un offset sinistro definito che potremo usare con jQuery per far muovere il contenitore secondo la distanza necessaria a mostrare ciascuna slide.

Partiamo dalle dichiarazioni più generali:

Abbiamo resettato i margini e il padding di tutti gli elementi in modo da non dovere dichiararli ogni volta. Quindi abbiamo fatto in modo di avere la pagina a piena larghezza ed altezza usando le proprietà width height min-height

A questo punto possiamo passare a definire il contenitore più esterno:

#site {
	width: 100%;
}

Quindi tocca al menu di navigazione superiore. Si tratta di un semplice menu orizzontale con le singole allineate tramite display: inline

#nav {
	height: 3em;
	background: #000 url(img/menu.gif) repeat-x 0 0;
}

#nav ul {
	width: 100%;
	list-style: none;
	height: 100%;
	text-align: center;
	line-height: 3;
}

#nav li {
	display: inline;
	margin-right: 1em;
}

#nav a {
	color: #f96;
	padding: 0.4em 0.6em;
	text-decoration: none;
	text-transform: uppercase;
	letter-spacing: 0.1em;
}

#nav a:hover {
	color: #fff;
}

#nav a.current {
	background: #f96;
	color: #fff;
}

La classe .current

Passiamo ora al contenitore più esterno delle slide:

#content {
	margin: 2em auto;
	width: 100%;
	max-width: 800px;
	overflow: hidden;
}

Usando una larghezza in percentuale e una larghezza massima in pixel facciamo in modo che il contenitore si adatti alla finestra del browser. Se c'è spazio disponibile, allora la larghezza sarà di 800 pixel, altrimenti inferiore.

Quindi tocca al contenitore più interno:

#content-wrapper {
	position: relative;
}

La larghezza e l'altezza massima di questo elemento verranno fissate dinamicamente da jQuery in base al numero di slide e all'altezza massima del contenuto presente in esse. Quindi definiamo gli stili per ciascuna slide:

div.page {
	margin: 0;
	float: left;
	width: 800px;
	position: relative;
}

La larghezza di ciascuna slide deve essere uguale alla larghezza massima del contenitore più esterno. Ora non resta che posizionare in modo assoluto i due pulsanti e la GIF animata del preload:

#previous,
#next {
	width: 40px;
	height: 40px;
	position: absolute;
	text-indent: -9999px;
}

#previous {
	left: 0;
	background: url(img/arr-left.png) no-repeat;
}

#next {
	right: 0;
	background: url(img/arr-right.png) no-repeat;
}

#loader {
	position: absolute;
	top: 50%;
	left: 50%;
	margin: -16px 0 0 -16px;
	display: none;
}

Abbiamo detto che i due pulsanti devono essere centrati verticalmente, ma sui dispositivi mobili c'è un problema: la centratura viene persa quando si ruota il dispositivo. Deleghiamo quindi questo compito a jQuery che centrerà i due elementi intercettando il cambio di orientamento del dispositivo.

La nostra GIF è invece centrata sia orizzontalmente che verticalmente tramite una nota tecnica CSS: proprietà top left

L'immagine viene nascosta perchè a noi interessa che appaia per un certo periodo di tempo solo quando si seleziona una slide.

Centrare verticalmente i bottoni sui dispositivi mobile

Come abbiamo detto, la centratura verticale dei bottoni si perde sui dispositivi mobile quando l'utente ruota il dispositivo. Per questa ragione usiamo l'evento orientationchange dell'oggetto window associandogli il nostro metodo di utility positionButtons():

Potete intanto visionare il nostro esempio in questa pagina

Lo swipe

Esaminiamo ora come aggiungere un effetto swipe al nostro slideshow per i dispositivi mobile. Lo swipe non esiste come evento DOM sui dispositivi mobile, ma è la combinazione degli eventi touchstart, touchmove e touchend. Il movimento è quello che si effettua con un dito verso destra o sinistra per sfogliare o far scorrere le pagine.

Implementare questo effetto da zero è molto difficile, ma fortunatamente esistono plugin jQuery come touchSwipe che riescono nell'intento. Useremo questo plugin per il nostro slideshow.

Aggiungere lo swipe

Useremo le due action di Touchswipe chiamate swipeLeft e swipeRight per intercettare lo swipe sull'intero blocco contenitore (ossia #site). Alla prima action assoceremo l'azione registrata sul bottone "Indietro" e alla seconda quella sul bottone "Avanti".

Per farlo aggiungeremo un altro metodo di utility all'oggetto Utils:

Quindi invochiamo questo metodo se siamo su mobile in fase di inizializzazione:

$(function() {
	Slides.init();
	if (window.orientation) // Siamo su mobile? {
		$(window).bind('orientationchange', function() {
			Slides.Utils.positionButtons();
		});
		Slides.Utils.swiping();
	}
});

Potete vedere il nostro esempio completo in questa pagina

L'esempio completo è allegato all'articolo.

Nelle parti precedenti abbiamo analizzato il codice jQuery necessario per implementare un effetto swipe sui dispositivi mobile. In questa parte vedremo come aggiungere AJAX al nostro slideshow e realizzare finalmente la navigazione orizzontale delle pagine.

La nuova struttura HTML

Anzitutto dobbiamo modificare la struttura del markup HTML eliminando i contenuti di tutte le slide eccetto la prima (che potrebbe essere la nostra home page):

<div class="page" id="home">

  		<h1>Home</h1>
  		<!-- continua -->
</div>
<div class="page" id="articoli"></div>
<div class="page" id="about"></div>

I contenuti saranno infatti recuperati via AJAX con una richiesta GET. Si possono immaginare diversi modi per sfogliare l'elenco delle pagine, noi sfrutteremo una semplice query string del tipo page=numero.

Lo script lato server

In un ambiente di produzione il nostro script PHP userebbe il numero di pagina passato tramite AJAX per reperire i contenuti dal database. Nel nostro esempio ci limiteremo ad usare un array associativo per simulare questa interazione:

<?php
header('Content-Type: text/html');
$page = $_GET['page'];
if(ctype_digit($page) && strlen($page) == 1) {
	$pageNum = $page;
} else {
	exit();
}

$htmlContents = array(
	'...',  // primo contenuto
	'...',  // secondo contenuto
	'...'   // terzo contenuto
);
echo $htmlContents[$pageNum];

Lo script imposta subito il tipo di contenuto su text/html. Meglio impostare il content type in modo esplicito per evitare che il server lo imposti in modo arbitrario.

C'è una elementare validazione dei dati: se il parametro GET page è un numero e la sua lunghezza è di 1 carattere, allora viene impostata la variabile $pageNum. Altrimenti lo script si interrompe. A questo punto occorrerebbe restituire un errore.

Alla fine ritorniamo il contenuto relativo al numero di pagina scelto e associato alla posizione nell'array.

Il codice jQuery

Dobbiamo modificare il metodo doSlide() inserendo una chiamata al metodo $.get prima che la pagina scorra:

Utils: {
		doSlide: function(params) {
			params = $.extend({
				container: Slides.Elements.wrapper,
				a: Slides.Elements.links,
				spinner: Slides.Elements.loader,
				pages: Slides.Elements.pages,
				button: 'next'
			}, params);
			params.pages.eq(Slides.fn.index).
			animate({
				opacity: 0.5
			}, 600, function() {
				params.spinner.show();
				setTimeout(function() {
					params.spinner.hide();
					if (params.button == 'next') {
						Slides.fn.index++;
					} else {
						Slides.fn.index--;
					}
					$.get('ajax.php', {page: Slides.fn.index}, function(html) {
						params.pages.eq(Slides.fn.index).html(html);

					});
					params.container.animate({
						left: -params.pages.eq(Slides.fn.index).position().left
					}, 1000, 'linear', function() {
						params.a.eq(Slides.fn.index).addClass('current').
						parents('ul').find('a').not(params.a.eq(Slides.fn.index)).
						removeClass('current');
					});
				}, 1000);
			});
		},
        //...
}

Ecco la nostra modifica:

La query string GET viene passata come oggetto letterale che jQuery convertirà nel canonico page=numero

Ora non ci resta che modificare il codice per il menu di navigazione superiore:

navigationMenu: function() {
			var links = Slides.Elements.links;
			var wrapper = Slides.Elements.wrapper;
			var slides = Slides.Elements.pages;
			links.each(function() {
				var $a = $(this);
				var slide = $($a.attr('href'));
				var $index = $a.attr('data-rel');
				$a.click(function(evt) {
					slides.css('opacity', 1);
					evt.preventDefault();
					Slides.fn.index = $index;
					$.get('ajax.php', {page: $index}, function(html) {
						slide.html(html);
					
					});
					wrapper.animate({
						left: -slide.position().left
					}, 1000, 'linear', function() {
						$a.addClass('current').parents('ul').
						find('a').not($a).removeClass('current');
					});
				});
			});
}

Il codice è pressoché identico a quello visto in precedenza. La differenza sta nel fatto che la slide di riferimento qui viene presa dall'attributo href

Potete vedere l'esempio completo in questa pagina

Ti consigliamo anche