Sfogliare le pagine di un sito: effetti di transizione AJAX e HTML5 history api

Quante volte ci sarà capitato di voler realizzare un sito web (o anche solo una parte di esso) che godesse di effetti visuali nel passaggio da una pagina all’altra piuttosto che del semplice caricamento della pagina da raggiungere?

Sicuramente molto spesso e, probabilmente, ogni volta che ci abbiamo pensato abbiamo optato per metodologie che introducevano contenuti nascosti all’interno della stessa pagina o cose simili.
Di seguito vedremo invece come ottenere il risultato desiderato utilizzando però pagine e link normali, senza alcun contenuto nascosto e potendo anche navigare nella history del browser.

Tutto questo sfruttando le potenzialità di una chiamata Ajax e delle HTML5 history API.

L’effetto specifico che propongo in questo articolo fa comparire la nuova pagina in scorrimento da destra, ma il sistema può essere applicato a qualsiasi altro effetto.

Il concetto alla base

Il concetto alla base del sistema è molto semplice. Nel nostro caso, in cui i contenuti della nuova pagina arriveranno scorrendo da destra, ci sono due contenitori:

  1. il primo è quello che racchiude il contenuto della pagina corrente
  2. il secondo risiede alla sua destra (oltre il limite rappresentato dal bordo dello schermo) invisibile e vuoto

Di seguito raffigurato con un esempio grafico:

concetto

Quando si clicca su un link viene fatta una richiesta Ajax che inserisce il contenuto della nuova pagina nel contenitore nascosto a destra, dopodiché lo fa scorrere verso sinistra, mentre quello di sinistra scivola via.

Infine il tutto si riposiziona per essere pronto a ricevere un nuovo click e aprire una nuova pagina.

Quello che stiamo per ottenere è visibile qui, e continuando a leggere scopriremo facilmente come fare.

Prepariamo la struttura

Per prima cosa creiamo una nuova cartella per il nostro progetto e inseriamo al suo interno i file: index.php e functions.php.

Riempiamo la pagina index.php in questo modo:

<?php
include('functions.php');
if(!isAjax()): ?>
	<!DOCTYPE html>
	<html lang="it">
	<head>
		<meta charset="utf-8">

		<link rel="stylesheet" href="css/style.css" type="text/css" media="screen"/>
		<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
		<script type="text/javascript" src="js/script.js"></script>
		
		<title>Ajax Page Slider</title>
	</head>
	<body>

	<header>
		<nav class="container">
			<ul>
				<li><a class="slide-item" href="index.php">Home Page</a></li>
				<li><a class="slide-item" href="pagina2.php">Pagina 2</a></li>
				<li><a class="slide-item" href="pagina3.php">Pagina 3</a></li>
			</ul>
		</nav>
	</header>
	<div id="page-slider-wrap">
		<div class="page-slider-inner-wrap">
			<div class="page-slide-1">
<?php endif; ?>
		<!----------------------------------->
		<!--QUI TUTTO IL CONTENUTO DELLA PAGINA-->
		<!----------------------------------->
		
<?php if(!isAjax()): ?>	  
			</div> <!-- Chiusua Page-slide-1-->
			<div class="page-slide-2"></div>
			<div class="fix-float"></div>
		</div> <!-- Chiusua Page Slider Inner-->
	</div> <!-- Chiusua Page Slider-->
</body>
</html>
<?php endif; ?>

Tralasciamo per un attimo la funzione isAjax() nei due if che si trovano sopra e sotto il contenuto (per ora assente) e vediamo che quello che abbiamo scritto altro non è che un semplicissimo layout con un menu in alto e il contenuto al centro.

Le cose necessarie per il risultato che vogliamo ottenere sono la classe slide-item assegnata ai link del menu (lo slide è avviato solo con link che possiedono questa classe) e questa parte del codice:

<?php
include('functions.php');
if(!isAjax()): ?>
	
	<!-- Tutta la parte superiore al contenuto -->
	
	<div id="page-slider-wrap">
		<div class="page-slider-inner-wrap">
			<div class="page-slide-1">
<?php endif; ?>
		<!----------------------------------->
		<!--QUI TUTTO IL CONTENUTO DELLA PAGINA-->
		<!----------------------------------->
		
<?php if(!isAjax()): ?>	  
			</div> <!-- Chiusua Page-slide-1-->
			<div class="page-slide-2"></div>
			<div class="fix-float"></div>
		</div> <!-- Chiusua Page Slider Inner-->
	</div> <!-- Chiusua Page Slider-->

	<!-- Tutta la parte sottostante al contenuto -->
	
<?php endif; ?>

La funzione isAjax() controlla se la pagina è stata aperta mediante la chiamata Ajax, perchè se è così, deve essere prelevato soltanto il suo contenuto specifico e non di nuovo l’header e il footer, altrimenti si avrebbe un effetto matriosca.

Dichiariamo quindi in questo modo la funzione nel file functions.php:

function isAjax() {
	return (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
}

Sarebbe una buona idea decidere di lavorare con un codice più pulito e mantenibile, così lo riordiniamo e scriviamo qualche riga all’interno della pagina in questo modo:

<?php
include('functions.php');

if(!isAjax())
	include ('templates/page-top.inc.php');
?>
		<section class="container content">
			<h1>Ajax Page Slide</h1>
			<h5>Le particolarit&agrave; sta nell'avere un effetto visuale senza rinunciare al normale funzionamento delle url e cronologia del browser</h5>
		</section>		
<?php
if(!isAjax())
	include ('templates/page-bottom.inc.php');
?>

Una volta che abbiamo impostato la nostra pagina in php e html, applichiamogli il seguente foglio di stile:

codice

Siamo vicini alla fine dell’opera e i coraggiosi che hanno decido di seguirmi dovrebbero avere avanti a loro un risultato come questo:

/**********************************************************************************************************************************/
/******************************************************* CSS NECESSARIO***********************************************************/
#page-slider-wrap {position:relative; width:100%; overflow:hidden;}

.page-slider-inner-wrap {
	position:relative;
	width: 200%;
	margin-left: 0px;
}

.page-slide-1, .page-slide-2 {
	position: relative;
	float: left;
	width: 50%;
	
}

/*************************************************************************************************************************************/
/***************************************************** CSS UNICAMENTE ESTETICO ********************************************************/
html, body {margin:0; height:100%;}
body { 
	font-family: Verdana, sans-serif;
	background: #d4e4ef; /* Old browsers */
	background: -moz-linear-gradient(top, #d4e4ef 0%, #86aecc 100%); /* FF3.6+ */
	background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#d4e4ef), color-stop(100%,#86aecc)); /* Chrome,Safari4+ */
	background: -webkit-linear-gradient(top, #d4e4ef 0%,#86aecc 100%); /* Chrome10+,Safari5.1+ */
	background: -o-linear-gradient(top, #d4e4ef 0%,#86aecc 100%); /* Opera 11.10+ */
	background: -ms-linear-gradient(top, #d4e4ef 0%,#86aecc 100%); /* IE10+ */
	background: linear-gradient(to bottom, #d4e4ef 0%,#86aecc 100%); /* W3C */
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d4e4ef', endColorstr='#86aecc',GradientType=0 ); /* IE6-9 */
	color:#444;
}

.fix-float {clear:both;}

header {overflow:hidden;}

.container {
	margin:20px;
	padding:20px;
	border:1px solid #6187A0;
	box-shadow: 6px 6px 12px 0px #444;
	background: #FCFFFF;

}
.content {min-height:300px;}

h1, h5 {text-align:center;}

nav ul {list-style:none; margin:0; height:20px;}
nav ul li{margin:5px 0; float:left; margin:0 10px;}
nav ul li a{padding:5px 10px; color:#666; text-decoration:none;}
nav ul li a:hover {color:#000;}

risultato

Copiamo il contenuto di index in pagina2.php e pagina3.php per non avere link che portano a pagine vuote e avremo adesso delle pagine perfettamente funzionanti, ma che cambiano ancora in maniera “classica”.

Implementiamo quindi la parte javascript per ottenere il risultato a cui puntiamo.

Il file javascript

Come ho fatto anche precedentemente, prima vi mostro il codice e poi ve lo spiego; il codice da inserire nel file javascript è il seguente:

//Funzione di risposta alla chiamata ajax che carica la nuova pagina e esegue l'animazione di slider
function pageSlider (data, text, xhr) {

	$('.page-slide-2').html(xhr.responseText);
	$('.page-slider-inner-wrap').animate({
		marginLeft: - $('.page-slider-inner-wrap').width() / 2
	}, 2000, function() {
		$('.page-slide-1').html(xhr.responseText);
		$('.page-slider-inner-wrap').css('margin-left', 0);
		$('.page-slide-2').html('');
	});
}


jQuery(document).ready(function() {

	//Soltanto i link con la classe .slide-item faranno partire lo slider
	$('a.slide-item').click(function(event) {
		var currentPage = document.location.pathname.substring(document.location.pathname.lastIndexOf('/') + 1);
		if ($(this).attr('href') != currentPage){ //se il link clickato non porta alla pagina corrente..
		
			if (history && history.pushState) {	
				history.pushState(null, document.title, $(this).attr('href'));
					
					//Richiama la nuova pagina attraverso una chiamata ajax
					$.get($(this).attr('href'), {ajax:'1'}, function(data, text, xhr) {
						pageSlider(data, text, xhr);
					});
				
				event.preventDefault();	
			}
		}
	});
	
});

//Permette di ottenere l'effetto dello slide anche quando si clicca sui tasti indietro o avanti del browser
window.addEventListener('load', function() {
	$ = jQuery;
	
	setTimeout(function() {
		window.addEventListener('popstate', function() {
			$.get(location.href, {ajax:'1'}, function(data, text, xhr) {
				pageSlider(data, text, xhr);
			});
		});
	}, 0);
	
});

La prima parte viene richiamata quando la chiamata Ajax viene portata a termine (il risultato si trova in xhr.responseText) e serve a gestire unicamente l’effetto grafico, quindi nel caso si voglia cambiare l’effetto di transizione laterale in qualche altra cosa o lo si voglia, ad esempio, velocizzare o modificare in qualsiasi modo è la funzione pageSlider che deve essere modificata.

La parte centrale resta in attesa del clic su un link a cui è assegnata la classe slide-item, quando questo accade, se l’indirizzo è diverso da quello corrente, il nuovo link viene aggiunto alla history del browser e parte la chiamata ajax che avvia l’effetto impostato nella funzione pageSlider().

L’ultima parte invece serve ad avviare l’effetto di pageSlider() anche quando si clicca sui tasti avanti o indietro del browser.

Come credo sia chiaro quindi, le ultime due parti non andrebbero modificate se non si è sicuri di quello che si sta facendo, dato che il corretto funzionamento dello script potrebbe essere messo a rischio.

In conclusione

Come vi ho già anticipato adesso dovreste aver ottenuto un risultato come questo.

Ricapitolando: lo script funziona con qualsiasi link a cui venga assegnata la classe slide-item e ogni volta che la pagina corrente e quella da raggiungere hanno la giusta struttura, permette di cambiare pagina con un effetto di scorrimento laterale utilizzare le reali url delle pagine e nessun contenuto nascosto.

Potete scaricare il codice completo e con il file javascript commentato quasi rigo per rigo a questo link.

Mi piacerebbe sapere come voi avreste risolto questo problema e se vi è piaciuto il metodo che ho usato io, potreste dirmelo lasciando un commento, dove resterò disponibile per rispondere a vostre domande!

Tag: , , ,

L'autore

Diviso tra informatica e illusionismo, Antonio è un appassionato WebDeveloper freelance che ama mettersi alla prova con sfide sempre più stimolanti. Dalla mentalità imprenditoriale e dal pensiero "outside the box", è stato sedotto da Wordpress, Bootstrap e Laravel, divenute ormai le sue tenere amanti, aiutandolo a realizzare ogni progetto in maniera intelligente e ben curata.

Sito web dell'autore | Altri articoli scritti da

Articoli correlati

25 commenti

Trackback e pingback

  1. Sfogliare le pagine di un sito: effetti di tran...
    […] Quante volte ci sarà capitato di voler realizzare un sito web (o anche solo una parte di esso) che…