El objetivo es crear una galería con elementos superpuestos:
Al clicar sobre uno de los elementos plegados, éste se despliega, a la vez que el que estaba seleccionado con anterioridad se pliega. Totalmente accesible mediante navegación de teclado.
HTML
Para el ejemplo se ha utilizado la siguiente estructura de código HTML 5 (aunque puede cambiarse a HTML 4):
<div class="componenteGaleriaSuperpuesta">
<article class="bloque-superpuesta">
<div class="bloque-superpuesta-interior-1">
<div class="bloque-superpuesta-interior-2">
<header>
<p class="fecha-bloque"><time datetime="AAAA-MM-DDTHH:MM+HH:MM">DD <abbr title="Mes">XXX.</abbr> AAAA<span> HH:MM</span></time></p>
<h1 class="titulo-bloque"><a href="#">[Título]</a></h1>
</header>
<div class="texto-bloque">
<p>[Texto]</p>
</div>
<div class="elemento-multimedia imagen">
<p><a href="#"><img src="#" alt="Ver más sobre [Título]" /></a></p>
</div>
</div>
</div>
</article>
<article class="bloque-superpuesta">[...]</article>
<article class="bloque-superpuesta">[...]</article>
<article class="bloque-superpuesta">[...]</article>
<article class="bloque-superpuesta">[...]</article>
<article class="bloque-superpuesta">[...]</article>
<article class="bloque-superpuesta">[...]</article>
</div>
Javascript
Para lanzar el comportamiento:
jQuery(document).ready(function () {
jQuery('.componenteGaleriaSuperpuesta').galeriaSuperpuesta();
});
El plugin Jquery, que va comentado con algunas explicaciones puntuales:
(function($){
$.fn.galeriaSuperpuesta = function(options){
var defaults = {
selectorElementoLista:'.bloque-superpuesta'
,selectorInteriorElementoLista: '.bloque-superpuesta-interior-1'
,selectorActivarSuperpuesta: '.activar-superpuesta'
,selectorActivo: '.bloque-activo'
,selectorElementoMultimedia: '.elemento-multimedia'
,claseJs: 'componenteGaleriaSuperpuesta-js'
,claseActivo: 'bloque-activo'
//,htmlCapaInteriorComponente: '<div class="interior-1"><div class="interior-2"></div></div>'
,htmlCapaActivacion: '<a href="#" class="activar-superpuesta"><span class="indentado">Activar</span></a>'
,datosOpacidad: 20
,datosOpacidadHover: 20
,zindex: 1
};
var datos = {
componente: null
};
var op = $.extend(defaults, options);
return this.each(function(){
datos.componente = $(this);
iniciarComponente();
});
function iniciarComponente () {
datos.componente.addClass(op.claseJs); // Se añade clase que indica que Javascript está activo
insertarEnlaceActivacion();
}
function insertarEnlaceActivacion () { // Se inserta el enlace que produce la opacidad y permite activar los elementos
datos.elementoLista = datos.componente.find(op.selectorElementoLista);
//datos.elementoLista.wrapAll(op.htmlCapaInteriorComponente);
datos.elementoLista.each(function () {
var destino = $(this).find(op.selectorInteriorElementoLista).eq(0);
destino.prepend(op.htmlCapaActivacion);
opacidadEnlaceActivador(destino);
});
posicionarElementosLista();
}
function opacidadEnlaceActivador (destino) {
// Alternancia de opacidad en el hover del enlace. Necesario para Internet Explorer 8 e inferiores
var enlace = destino.find(op.selectorActivarSuperpuesta).eq(0);
opacidadReposada(enlace);
enlace.hover(
function () {
opacidadActiva(enlace);
}
,function () {
opacidadReposada(enlace);
}
);
}
function opacidadReposada (enlace) {
enlace.css({
'opacity':'.'+(op.datosOpacidad/10)
,'filter':'alpha(opacity='+op.datosOpacidad+')'
});
}
function opacidadActiva (enlace) {
enlace.css({
'opacity':'.'+(op.datosOpacidadHover/10)
,'filter':'alpha(opacity='+op.datosOpacidadHover+')'
});
}
function posicionarElementosLista () { // Se posicionan los elementos de lista
datos.anchoComponente = datos.componente.width(); // Ancho componente
datos.anchoElementoLista = datos.elementoLista.eq(0).outerWidth(); // Ancho de elemento de lista
datos.anchoElementoListaSimple = datos.elementoLista.eq(0).width(); // Ancho de elemento de lista sin bordes o padding
datos.numElementoLista = datos.elementoLista.length; // Número de elementos de lista
datos.anchoParaOcultos = Math.floor((datos.anchoComponente-datos.anchoElementoLista)/(datos.numElementoLista-1)); // Ancho visible de elementos ocultos
datos.variacionPosicionMostrar = datos.anchoElementoLista-datos.anchoParaOcultos; // Distancia de movimiento al activar un elemento
var elementoListaCentral = Math.ceil(datos.numElementoLista/2)-1; // Elemento central
var posicionElemento = 0;
var ejeZ = op.zindex; // Z-index: debe evolucionar de menor a mayor, para que las superposiciones funcionen adecuadamente
datos.elementoLista.each(function (index) { // Se aplican las posiciones a los elementos
$(this).css({
'left':posicionElemento+'px'
,'z-index':ejeZ
});
if (elementoListaCentral==index) {
posicionElemento +=datos.anchoElementoLista;
$(this).find(op.selectorActivarSuperpuesta).eq(0).css('width',datos.anchoElementoListaSimple+'px')
$(this).addClass(op.claseActivo).find(op.selectorElementoMultimedia).eq(0).css('left','0');
} else {
$(this).find('a:not('+op.selectorActivarSuperpuesta+')').attr('tabindex','-1');
$(this).find(op.selectorActivarSuperpuesta).eq(0).css('width',datos.anchoParaOcultos+'px')
posicionElemento +=datos.anchoParaOcultos;
}
ejeZ += 1;
});
eventoAlternarElementosLista();
}
function eventoAlternarElementosLista () { // Evento para seleccionar elementos
datos.componente.find(op.selectorActivarSuperpuesta).bind('click',alternarElementosLista);
}
function alternarElementosLista (event) {
event.preventDefault();
var elementoLista = $(this).closest(op.selectorElementoLista); // Elemento a mostrar
// Distinción de la dirección hacia la que tienen que moverse los elementos
if (elementoLista.nextAll(op.selectorActivo).length==1) {
var elementoListaActivo = elementoLista.nextAll(op.selectorActivo);
var grupo = elementoLista.nextUntil(op.selectorActivo).add(elementoListaActivo); // Formación del grupo de elementos a mover
var direccion = 1;
} else {
var elementoListaActivo = elementoLista.prevAll(op.selectorActivo);
var grupo = elementoLista.prevUntil(op.selectorActivo).add(elementoLista); // Formación del grupo de elementos a mover
var direccion = -1;
}
grupo.each(function (index) { // Se produce el movimiento de los elementos
var nuevaPosicion = parseInt($(this).css('left').split('px')[0])+(datos.variacionPosicionMostrar*direccion);
$(this).animate({left:nuevaPosicion},250)
});
// Se cambia el elemento activo y se mueven las imágenes para que queden posicionadas siempre al centro
elementoListaActivo.removeClass(op.claseActivo).find(op.selectorElementoMultimedia).eq(0).animate({left:(datos.variacionPosicionMostrar/2*(-1))},250,function () {
elementoListaActivo.find(op.selectorActivarSuperpuesta).css('width',datos.anchoParaOcultos+'px')
elementoListaActivo.find('a:not('+op.selectorActivarSuperpuesta+')').attr('tabindex','-1');
});
elementoLista.addClass(op.claseActivo).find(op.selectorElementoMultimedia).eq(0).animate({left:0},250,function () {
elementoLista.find(op.selectorActivarSuperpuesta).css('width',datos.anchoElementoListaSimple+'px');
elementoLista.find('a:not('+op.selectorActivarSuperpuesta+')').attr('tabindex','');
});
}
}})(jQuery);