Outbook

HTML+CSS+JS, Accesibilidad, PHP y más

Inicio que contiene a Desarrollo web que contiene a Javascript que contiene a Javascript-Jquery: Galería con desplazamiento (carrusel)

Datos de búsqueda

Javascript-Jquery: Galería con desplazamiento (carrusel)

Actualizado 2011-02-18: Se añade una variante con desplazamiento ilimitado.

El objetivo es crear una galería con desplazamiento mediante Javascript manteniendo la accesibilidad cuando no hay soporte Javascript.

HTML

HTML inicial

El HTML inicial podría ser como el que se muestra a continuación:

<div class="componenteGaleria">
  <ul class="clear mostrar-[x]">
    <li>[...]</li>
    <li>[...]</li>
    [...]
    <li>[...]</li>
  </ul>
</div>

Estructura del HTML inicial

Como se puede observar se trata de una capa (DIV) que contiene una lista (UL). La única particularidad es la clase del UL, con el prefijo mostrar- que precede al número de elementos que se quieren tener visibles dentro del carrusel.

Javascript

Para conseguir el efecto de desplazamiento es necesario:

  1. Añadir una clase al elemento contenedor.
  2. Que los elementos del listado estén en una sola línea: habrá que calcular el ancho del total de elementos de lista y aplicárselo a la lista.
  3. Generar una capa para contener la lista y darle a dicha capa el ancho correspondiente al total de elementos que se desee tener visibles.
  4. La capa contenedora de lista deberá llevar position:relative; y overflow:hidden;, y la lista deberá posicionarse absoluta respecto de la capa position:absolute;
  5. Tras la capa contenedora de lista se insertan los controles anterior y siguiente.

Al clicar los controles el listado variará su posicionamiento izquierdo (propiedad CSS left) en una distancia equivalente al ancho de un elemento más sus márgenes, siempre comprobando que el área visible esté llena de elementos, limitando el desplazamiento según sea necesario cuando se escoge la variante limitada (predeterminada). Si se escoge la variante infinita, el listado se desplaza permanentemente en cualquier dirección.

Así quedaría el HTML tras los cambios:

<div class="componenteGaleria">
  
  <div class="contenedor-lista">
    <ul class="clear mostrar-[x]">
      <li>[...]</li>
      <li>[...]</li>
      [...]
      <li>[...]</li>
    </ul>
  </div>
  <ul class="controles">
    <li class="anterior"><a href="#">[...]</a></li>
    <li class="siguiente"><a href="#">[...]</a></li>
  </ul>
</div>

Estructura del HTML modificado con Javascript

Ver ejemplo funcional.

Javascript completo

Primero la llamada a las funciones:

$(document).ready(function () {
  
  // Los llamamos de uno en uno (pendiente de solucionar...)
  $('#contenido .componenteGaleriaLimitada ul').each(function () {
    $(this).carrusel();
  });
  $('#contenido .componenteGaleriaSinLimite ul').each(function () {
    $(this).carrusel({limitada:false});
  });
  
});

La opción limitada (valores true o false) establece si el carrusel es infinito o se para al llegar al final o volver al inicio.

Y el plugin:

(function($){

$.fn.carrusel = function(options){
  var defaults = {
  htmlControles: '<ul class="controles"><li class="anterior"><a href="#"><img src="ficheros/CR_IMG_ico_anterior.png" alt="Anterior" /></a></li><li class="siguiente"><a href="#"><img src="ficheros/CR_IMG_ico_siguiente.png" alt="Siguiente" /></a></li></ul>' // HTML para los controles
  ,htmlContenedorLista: '<div class="contenedor-lista" />' // HTML contenedor de listado
  ,claseContenedorLista: 'contenedor-lista'
  ,claseControlAnterior: 'anterior'
  ,claseControlSiguiente: 'siguiente'
  ,claseJs: 'componenteGaleria-js'
  ,claseOculto: 'indentado'
  ,selectorContenedorLista: '.contenedor-lista'
  ,selectorContenedorComponente: '.componenteGaleria'
  ,selectorContenedorEnlaceControl: '.controles li'
  ,selectorControlAnterior: '.anterior'
  ,selectorControlSiguiente: '.siguiente'
  ,selectorElementoLista: 'li'
  ,selectorOculto: '.indentado'
  
  ,animacion: true // Activar animación 'true', desactivar animación 'false'
  ,limitada:true
};
var datos = {};

var op = $.extend(defaults, options);

return this.each(function(){
  datos.listado = $(this);
  datos.componente = datos.listado.closest(op.selectorContenedorComponente).addClass(op.claseJs);
  prepararLista();
  
  prepararControles();
});

function prepararLista() {
  datos.listado.wrap(op.htmlContenedorLista);
  datos.contenedorLista = datos.listado.parent();
  calculaAncho();
}

function calculaAncho() {
  datos.elementosLista = datos.listado.find(op.selectorElementoLista);
  var numElementosLista = datos.elementosLista.length;
  var i = 0;
  var ancho = 0;
  var margen = 0;

  while (i<numElementosLista) {
    var elementoLista =  datos.elementosLista.eq(i);
    ancho += elementoLista.outerWidth(true);
    margenInocuo = elementoLista.outerWidth(true)-elementoLista.outerWidth();
    if(i+1==numElementosLista && op.limitada){
      margen = elementoLista.outerWidth(true)-elementoLista.outerWidth();
      elementoLista.css('margin','0');
    }
    i++;
  }

  var elementosVisibles = parseInt(datos.listado.attr('class').split('-')[1]);
  datos.anchoElemento = ancho/numElementosLista;
  datos.anchoVisibleGaleria = (datos.anchoElemento*elementosVisibles)-margenInocuo;
  datos.anchoListado = ancho-margen;
  datos.listado.css('width',datos.anchoListado+'px');
  datos.contenedorLista.css('width',datos.anchoVisibleGaleria+'px');
  
  var anchoComponente = datos.contenedorLista.outerWidth(true);
  datos.componente.css('width',anchoComponente+'px');
}

function prepararControles () {
  datos.componente.append(op.htmlControles);
  datos.enlaceControlAnterior = datos.componente.find(op.selectorContenedorEnlaceControl+op.selectorControlAnterior+' a').eq(0);
  datos.enlaceControlSiguiente = datos.componente.find(op.selectorContenedorEnlaceControl+op.selectorControlSiguiente+' a').eq(0);
  datos.enlacesControl = datos.componente.find(op.selectorContenedorEnlaceControl+' a')
  
  if (op.limitada) {prepararControlesLimitada();} else {prepararControlesIlimitada();}
}
function prepararControlesIlimitada () {
  //datos.enlacesControl.unbind('click');
  datos.enlacesControl.click(function (event) {
    event.preventDefault();
    datos.enlacesControl.unbind('click').click(function (event) {event.preventDefault();});
    var direccion = 1;
    if ($(this).closest(op.selectorContenedorEnlaceControl).hasClass(op.claseControlSiguiente)) {
      direccion = -1;
    }
    moverIlimitada(direccion);
  });
}

function moverIlimitada (direccion) {
  var elementos = datos.listado.find(op.selectorElementoLista);
  var primero = elementos.eq(0);
  var ultimo = elementos.last();
  var contenedor = primero.parent();
  
  // Flecha Izquierda
  if (direccion<0) {
    if (op.animacion) {
      datos.listado.animate({left:datos.anchoElemento*(-1)},function () {
        primero.appendTo(contenedor);
        datos.listado.css('left','0');
        prepararControlesIlimitada();
      });
    } else {primero.appendTo(contenedor);prepararControlesIlimitada();}
  }
  
  // Flecha Derecha
  else {
    if (op.animacion) {
      datos.listado.css('left',(datos.anchoElemento*(-1))+'px');
      ultimo.prependTo(contenedor);
      datos.listado.animate({left:0},function () {
        prepararControlesIlimitada();
      });
    } else {ultimo.prependTo(contenedor);prepararControlesIlimitada();}
  }
}

function prepararControlesLimitada () {
  
  
  if (recuperarPosicionActual()==0) {ocultarControl(datos.enlaceControlAnterior);}
  
  
  datos.enlacesControl.click(function (event) {
    event.preventDefault();
    datos.enlacesControl.unbind('click').click(function (event) {event.preventDefault();});
    var direccion = 1;
    if ($(this).closest(op.selectorContenedorEnlaceControl).hasClass(op.claseControlSiguiente)) {
      direccion = -1;
      if (datos.enlaceControlAnterior.hasClass(op.claseOculto)) {mostrarControl(datos.enlaceControlAnterior)}
    } else {
      if (datos.enlaceControlSiguiente.hasClass(op.claseOculto)) {mostrarControl(datos.enlaceControlSiguiente);}
    }
    moverLimitada(direccion);
  })
}

function moverLimitada (direccion) {
  var posicionActual = recuperarPosicionActual();
  
  var posicionNueva = (direccion*datos.anchoElemento)+posicionActual;
  var posicionMaxima = (datos.anchoListado-datos.anchoVisibleGaleria)*(-1);
  
  
  if (posicionNueva>=0) {
    posicionNueva=0;
    ocultarControl(datos.enlaceControlAnterior);
  }
  if (posicionNueva<=posicionMaxima) {
    ocultarControl(datos.enlaceControlSiguiente);
    posicionNueva=posicionMaxima;
  }
  if (op.animacion) {
    datos.listado.animate({left: posicionNueva},function () {prepararControlesLimitada();});
  } else {
    datos.listado.css('left',posicionNueva+'px');
    prepararControlesLimitada();
  }
  
}

function recuperarPosicionActual () {
  return parseInt(datos.listado.css('left').split('px')[0]);
}

function ocultarControl (enlace) {
  enlace.addClass(op.claseOculto);
}

function mostrarControl (enlace) {
  enlace.removeClass(op.claseOculto);
}

}})(jQuery);

Comentarios del artículo

Los comentarios están cerrados.

Si el comentario no guarda relación con el tema del artículo o los comentarios previos, si la redacción del mismo es ilegible (estilo HOYGAN), o si contiene insultos u otros términos ofensivos, será borrado de inmediato. No se garantiza ningún soporte a los ejemplos de desarrollo web presentados en este sitio.

Hay 4 comentarios a “Javascript-Jquery: Galería con desplazamiento (carrusel)”

maria marta dice:

Fecha de comentario: 2011/11/21 21:58

hola! necesitaría saber como hacer para que esta galeria se ajuste a la resolucion de pantalla, puedo poner todos los tamaños en porcentaje? estoy buscando algo asi.. gracias!

jervert dice:

Fecha de comentario: 2011/11/21 22:47

En principio no debería haber problema para poner dimensiones en porcentaje, salvo que habría que recalcular (modificando el JS) algunas dimensiones en caso de que se quiera volver a adaptar al redimiensionar la ventana

saco termico dice:

Fecha de comentario: 2011/12/18 01:14

¿Habría alguna manera de hacer que este carrusel se moviera de forma automática?

jervert dice:

Fecha de comentario: 2011/12/18 01:20

Habría que automatizar la llamada a la función que mueve el listado para que se repita en el intervalo de tiempo deseado (mediante ‘setInterval’), y si se quiere cumplir con WCAG, añadir unos controles que permitan parar el movimiento. Quizá sirva: http://blog.outbook.es/desarrollo-web/javascript-slideshow-con-jquery

Información del sitio