Creare slider personalizzati con jQuery

Un paio di mesi fa, per un mio caro amico web designer, ho sviluppato molto velocemente un paio di semplici funzioni javascript che permettono di gestire lo scorrimento di un div tramite lo slider di jQueryUI e la rotella del mouse.

Il funzionamento è abbastanza classico: si fa “scorrere” il div dei contenuti sotto un div “maschera” di dimensioni prefissate. Diciamo una versione rivisitata dei div con “overflow: auto;” e annessa scrollbar colorata del mai-glorioso internet explorer 6.0.

Le librerie che ho usato per realizzare lo slider sono jQuery, jQueryUI e il plugin mousewheel di Brandon Aaron, il tutto condito da un minimo di CSS, specie quello che riguarda la customizzazione dello slider. L’idea è quella di impostare l’offset superiore (la proprietà css “top”) massimo del div dei contenuti come valore massimo dello slider; così che muovendo lo slider in un range che va da 0 a X, cambi anche la proprietà top del div.

Vediamo ora l’implementazione dello slider e in seguito passeremo alla customizzazione.

<html>
	<head>
		<title>Slider verticale</title>
		<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css" type="text/css" media="all" />
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
		<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>
		<script src="jquery.mousewheel.min.js" type="text/javascript"></script>
		<style>
			* { margin: 0px; padding: 0px; }
			.clear { clear:both; }
			#content { width:510px; margin:100px auto; }
			.news { border:1px solid #000000; margin-bottom: 10px; }

			#right { float:right; height:150px; width:50px; }
			#slider-vertical { height:150px; }
			#maschera { width:450px; height:150px; overflow:hidden; position:relative; }
			#contenuti { position:absolute; top:0px; left:0px; width:450px; }
		</style>
	</head>
	<body>
		<div id="content">
			<div id="right">
				<div id="slider-vertical"></div>
			</div>
			<div id="center">
				<div id="maschera">
					<div id="contenuti">
						<div class="news">1 riga</div>
						<div class="news">2 righe<br />2 righe</div>
						<div class="news">3 righe<br />3 righe<br />3 righe</div>
						<div class="news">4 righe<br />4 righe<br />4 righe<br />4 righe</div>
						<div class="news">5 righe<br />5 righe<br />5 righe<br />5 righe<br />5 righe</div>
					</div>
				</div>
			</div>
			<div class="clear"></div>
		</div>
		<script type="text/javascript">
			function scroll(max_height,value) {
				var val = -1*(max_height-value);
				$('#contenuti').css('top',val+'px');
			}

			$(function() {
				max_height = parseInt($('#contenuti').css('height')) - parseInt($('#maschera').css('height'));

				$slider = $("#slider-vertical").slider({
					orientation: "vertical",
					range: "min",
					min: 0,
					max: max_height,
					value: max_height,
					slide: function( event, ui ) {
						scroll(max_height,ui.value);
					}
				});

				$('#contenuti').bind('mousewheel', function(event, delta) {
					scrollDelta = 20;
					var value = parseInt($slider.slider('value'));
					value += (delta > 0 ? scrollDelta : -scrollDelta)
					if (value > max_height) value = max_height;
					else if (value < 0) value = 0;
					$slider.slider('value', value);
					scroll(max_height,value);
					return false;
				});
			});
		</script>
	</body>
</html>

Per realizzare l’esempio, abbiamo usato un minimo di css per dare forma alla pagina (la parte in alto) e per creare la nostra maschera e posizionare lo slider. I valori che vorrete sicuramente cambiare sono la larghezza e l’altezza minima della maschera e dei contenuti (#maschera, #contenuti) così come l’altezza dello slider e della sua colonna che lo contiene (#slider-vertical, #right).

* { margin: 0px; padding: 0px; }
.clear { clear:both; }
#content { width:510px; margin:100px auto; }
.news { border:1px solid #000000; margin-bottom: 10px; }

#right { float:right; height:150px; width:50px; }
#slider-vertical { height:150px; }
#maschera { width:450px; height:150px; overflow:hidden; position:relative; }
#contenuti { position:absolute; top:0px; left:0px; width:450px; }

Il javascript che abbiamo utilizzato è abbastanza semplice ed è riportato di seguito

function scroll(max_height,value) {
	var val = -1*(max_height-value);
	$('#contenuti').css('top',val+'px');
}

$(function() {
	max_height = parseInt($('#contenuti').css('height')) - parseInt($('#maschera').css('height'));

	$slider = $("#slider-vertical").slider({
		orientation: "vertical",
		range: "min",
		min: 0,
		max: max_height,
		value: max_height,
		slide: function( event, ui ) {
			scroll(max_height,ui.value);
		}
	});

	$('#contenuti').bind('mousewheel', function(event, delta) {
		scrollDelta = 20;
		var value = parseInt($slider.slider('value'));
		value += (delta > 0 ? scrollDelta : -scrollDelta)
		if (value > max_height) value = max_height;
		else if (value < 0) value = 0;
		$slider.slider('value', value);
		scroll(max_height,value)
	});
});

Possiamo vedere come la funzione “scroll” (riga 40) sia quella che si occupa di cambiare l’offset superiore del div (proprietà “top” del css) che, grazie al posizionamento assoluto, risulterà scorrere sotto alla maschera (posizionata in modo relativo).

Dopo la funzione “scroll” c’è il codice che viene eseguito solo al document ready (riga 48) e consistono nell’instanzazione dello slider jQueryUI con valore massimo pari alla differenza tra l’altezza effettiva del div dei contenuti e quella del div maschera (riga 46). Per questioni di praticitià, la differenza chiamata “max_height” viene calcolata in una variabile esterna alle funzioni dentro il document ready, ma vi sprono a fare di meglio!
Nel metodo slide dello slider viene chiamata la funzione “scroll” passando l’altezza massima calcolata e l’attuale valore assunto dallo slider.

Subito dopo c’è la parte che riguarda la rotella del mouse (riga 59). All’interno della funzione anonima collegata all’evento mousewheel troviamo un parametro per regolare di quanti pixel vogliamo far scorrere il div (scrollDelta), un controllo per capire la direzione dello scroll più un check del valore massimo o minimo risultante in seguito all’azione. Il nuovo valore di offset così ottenuto viene quindi assegnato allo slider e in seguito passato alla funzione “scroll” (righe 65-66).

Ora che abbiamo visto il funzionamento, passiamo alla customizzazione grafica! Nell’esempio allegato ho messo un pomodoro come indicatore dello slider e poi ho cambiato lo sfondo e il bordo dello slider. Niente di complesso, giusto per rendere l’idea.
Vi riporto di seguito solo l’aggiunta di css che ho fatto allo script.

/* customizzazione */
#slider-vertical
{
	background: #FF0000;
	border:1px dotted #FFFFFF;
}

#slider-vertical > div
{
	background: #FFFFFF;
	border: 0;
	margin: 0 auto;
}

#slider-vertical > a
{
	background: url(pomodoro.png) no-repeat center center;
	border: 0;
	height:24px;
	width:24px;
}
/* fine customizzazione */

Update: per venire incontro alle esigenze di molti (Niko :P), allego una versione “migliorata” che consente di gestire più slider nella stessa pagina.

12 pensieri su “Creare slider personalizzati con jQuery

  1. Pingback: Wucca.it is born! | Valerio "Lotti" Riva's DevLog

  2. Nico

    Ciao!
    Grazie mille per il tuo tutorial! Mi è stato vitale!

    Ti chiedo aiuto per un piccolo particolare che non riesco a risolvere da giorni..
    Come posso creare più slider nella stessa pagina?
    Sul web parlano della funzione .each di jquery ma non ne vengo a capo!

    Ti ringrazio per il tuo tempo!

    Rispondi
  3. Lotti Autore articolo

    Ciao Nico!
    Prima di tutto ti faccio i complimenti per web circus! mi piace molto la home e si vede abbastanza bene anche da smartphone! 🙂 In bocca al lupo per il lavoro / futuro!

    Veniamo al fantomatico $.each! 🙂

    Ci sono due tipi di .each! quello applicabile direttamente a oggetti selezionati da jquery (classico) $(selettore).each( function (index, element) { … }); e quello versione stand-alone (utility) applicabile a qualsiasi array / oggetto $.each(obj, function (index, value) { … });. Entrambi funzionano allo stesso modo, ovvvero, eseguono un funzione, passando i parametri che ho elencato, su ogni elemento trovato dal selettore o presente nell’array / oggetto.

    Facciamo un esempio più inerente al topic così ti risolvo anche metà del lavoro 😛
    Supponendo la necessità di creare 3 slider si può agire in questo modo:

    var slider = [];
    $(“#slider-vertical”).each( function (index, element) {
    slider[index] = $(element).slider({
    orientation: “vertical”,
    range: “min”,
    min: 0,
    max: max_height,
    value: max_height,
    slide: function( event, ui ) {
    scroll(max_height,ui.value);
    }
    });
    });

    Ovviamente poi nella variabile slider troverai tutti i riferimenti per agganciare la seconda parte dello script 🙂

    PS: non l’ho testato, ma dovrebbe funzionare 😛

    Rispondi
    1. Nico

      Ciao!! Grazie mille della risposta.. non smetto mai di stupirmi della solidarietà che c’è tra noi amanti della programmazione..

      Ho capito quello che hai scritto (pur non essendo jQuery il mio pane quotidiano) ma purtroppo non ne vengo a capo perchè nella parte iniziale del tuo script, avendo più elementi con classe “scroll-content” mi si muovono tutti.

      function scroll(max_height,value) {
      var val = -1.5*(max_height – (max_height – value));
      jQuery(‘.scroll-content’).css(‘top’,val+’px’);
      }

      Ti posto la struttura che ho e lo script.
      Ho 3 elementi html con questa struttura (classi uguali e id diverso):

      &ltdiv class=”box” id=”showcase”&gt
      &ltdiv class=”box-white”&gt
      &lth2>Showcase</h2&gt

      &ltdiv class="slider"&gt&lt/div&gt
      &ltdiv class="slider_wrapper"&gt
      &ltdiv class="slider_container"&gt
      &ltdiv class="scroll-content"&gt
      &lt!– QUI LA MIA LISTA DI BOX –&gt
      &lt/div&gt&lt!– end content –&gt
      &lt/div&gt&lt!– end container –&gt
      &lt/div&gt&lt!– end scroll wrapper –&gt
      &lt/div&gt
      &lt/div&gt

      ..e poi il tuo magico script :

      function scroll(max_height,value) {
      var val = -1.5*(max_height – (max_height – value));
      jQuery(‘.scroll-content’).css(‘top’,val+’px’);
      }

      jQuery(function() {

      max_height = parseInt(jQuery(‘.scroll-content’).css(‘height’)) – parseInt(jQuery(‘.slider_container’).css(‘height’));

      $slider = jQuery(“.slider”).slider({
      orientation: “horizontal”,
      range: “min”,
      min: 0,
      max: max_height,
      value: 1,
      slide: function( event, ui ) {
      scroll(max_height,ui.value);
      }
      });

      jQuery(‘.scroll-content’).bind(‘mousewheel’, function(event, delta) {

      scrollDelta = -20;

      var value = parseInt($slider.slider(‘value’));
      value += (delta &gt 0 ? scrollDelta : -scrollDelta)
      if (value &gt max_height) value = max_height;
      else if (value &lt 0) value = 0;
      $slider.slider(‘value’, value);
      scroll(max_height,value);
      return false;
      });
      });

      Ovviamente così mi muove entrambe perchè hanno stesse classi.
      Chiedo il tuo aiuto prezioso e mi scuso per farti perdere tempo.. sono in debito!

      Grazie mille e continua con i tuoi tutorial!

      Rispondi
  4. Lotti Autore articolo

    Ho capito il problema 🙂 la soluzione è abbastanza semplice. al solito, io la posto, tu la provi 😛

    function scroll(index,max_height,value) {
    var val = -1*(max_height-value);
    $(‘.contenuti[rel=’+index+’]’).css(‘top’,val+’px’);
    }

    var max_height = [];
    var slider = [];
    $(“.slider-vertical”).each( function (index, element) {
    max_height[index] = parseInt($(‘.contenuti[rel=’+index+’]’).css(‘height’)) – parseInt($(‘.maschera[rel=’+index+’]’).css(‘height’));
    slider[index] = $(element).slider({
    orientation: “vertical”,
    range: “min”,
    min: 0,
    max: max_height,
    value: max_height,
    slide: function( event, ui ) {
    scroll(index,max_height[index],ui.value);
    }
    });
    });

    $(‘.contenuti’).each(function (i,element) {
    $(element).bind(‘mousewheel’, function(event, delta) {
    var index = parseInt($(element).attr(‘rel’));
    scrollDelta = 20;
    var value = parseInt($slider[index].slider(‘value’));
    value += (delta > 0 ? scrollDelta : -scrollDelta)
    if (value > max_height[index]) value = max_height[index];
    else if (value < 0) value = 0; $slider[index].slider('value', value); scroll(index,max_height[index],value); }); }); dovrebbe andare salvo problemi di sintassi 🙂 Il "trucco" sta nel definire un array dove vengono calcolate le altezze massime alla creazione degli slider e nel generalizzare la funzione scroll. Per distinguere i vari elementi basta aggiungere l'attributo "rel" nei tag con classe .contenuti e .maschera (l'attributo rel viene usato per comodità ed esce fuori dallo standard. in alternativa potresti dare degli id numerati con prefisso fisso. es: #contenuti_1, #contenuti_2)

    Rispondi
  5. Nico

    Ti ringrazio davvero ma purtroppo non funziona!! 🙁
    Comincio a pensare che sia impossibile avere due slider nella stessa pagina senza che l’una influenzi l’altra..

    Rispondi
  6. Nico

    You are awesome!!
    Ti ringrazio davvero.. solo un ultima cosa..
    Si riesce a fare in modo che vada oltre lo scroll anche lo slider manuale?

    Grazie ancora!!
    Be creative

    Rispondi
    1. Nico

      Wow!! hai salvato la salute del mio cervello!!
      Grazie davvero!!
      Continua con i tuoi tutorial mi raccomando!

      Rispondi

Rispondi a Nico Annulla risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *