Vistas previas de álbumes en vivo con CSS3 y jQuery

Hoy vamos a hacer un guión para obtener una vista previa del contenido de un álbum con una animación similar a una presentación de diapositivas. Esto se puede usar en galerías de fotos, tiendas en línea, páginas de perfil y más. El ejemplo está inspirado en Facebook, donde pasas el cursor sobre un álbum y obtienes una presentación de diapositivas de algunas de las fotos que contiene.

Comencemos con el HTML.

El HTML

El primer paso es establecer la base HTML del ejemplo de hoy. Este es un documento HTML5 estándar:

index.php

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Album Previews with CSS3 and jQuery | Tutorialzine </title>

        <!-- Our stylesheet -->
        <link rel="stylesheet" href="assets/css/styles.css" />

    </head>
    <body>

        <div id="main">

                <a href="#" data-images="assets/img/thumbs/11.jpg|assets/img/thumbs/10.jpg"
                   class="album">
                   <img src="assets/img/thumbs/4.jpg" alt="People" />
                   <span class="preloader"></span>
                </a>

                <!-- More albums will go here -->

        </div>

        <!-- JavaScript Includes -->
        <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
        <script src="assets/js/script.js"></script>
        <script src="assets/js/albumPreviews.js"></script>

    </body>
</html>

El #principal div contiene el marcado de los álbumes:

<a href="#" data-images="assets/img/thumbs/11.jpg|assets/img/thumbs/10.jpg" class="album">
   <img src="assets/img/thumbs/4.jpg" alt="People" />
   <span class="preloader"></span>
</a>

Cada álbum es un enlace, que normalmente apuntaría a la página completa del álbum, donde el usuario vería todas las fotos del álbum (aquí apunta a #). El álbum también incluye un atributo de datos que contiene las URL de las imágenes que contiene (es una buena idea señalar las miniaturas y no las imágenes completas). En la parte de jQuery del tutorial, obtendremos estas URL y las agregaremos como imágenes reales al enlace del álbum y las animaremos.

Dentro del enlace, está la imagen inicial del álbum (que se mostraría incluso si JavaScript está deshabilitado). Esta imagen debería ser diferente de los incluidos en el atributo de datos. El último es el preloader span, que muestra un PNG transparente que se rota usando CSS3. Decidí seguir este camino en lugar de usar un GIF, ya que el formato PNG admite una transparencia adecuada y se ve mejor.

Sin embargo, sería demasiado trabajo escribir el HTML de todos los álbumes manualmente. Esta es la oportunidad perfecta para lanzar algo de PHP para generarlo automáticamente.

index.php

$albums = array(
    'People' => array(
                'assets/img/thumbs/4.jpg',
                'assets/img/thumbs/11.jpg',
                'assets/img/thumbs/10.jpg'),

   // More albums go here
);

foreach ($albums as $name => $a) {

    ?>

    <a href="#" data-images="<?php echo implode('|', array_slice($a,1))?>" class="album">
       <img src="<?php echo $a[0]?>" alt="<?php echo $name?>" />
       <span class="preloader"></span>
    </a>

    <?php

}

Puede ver que estoy usando la función array_slice cuando construyo el atributo de datos, para que la imagen predeterminada no se repita (de lo contrario, vería la misma imagen dos veces en la presentación de diapositivas).

Con esto fuera del camino, ¡vamos a escribir algo de JavaScript!

JavaScript

Al igual que con los otros tutoriales en el sitio, estoy usando la biblioteca jQuery para facilitar la escritura de JavaScript.

La funcionalidad principal de este ejemplo toma la forma de un complemento jQuery portátil. En el evento mouseenter, el complemento busca el atributo de imágenes de datos, lo analiza y agrega las imágenes al álbum. Luego inicia una presentación de diapositivas que se detiene automáticamente en el evento mouseleave:

activos/js/albumPreviews.js

(function($) {

    $.fn.albumPreviews = function() {

        return this.each(function(){

            var album = $(this),
                loop = null, images = $();

            if(!album.data('images')){
                // The data-images attribute is missing. Skip this album.
                return true;
            }

            var sources = album.data("images").split('|');

            album.on('mouseenter', function(){

                if(!images.length){
                    // The images have not been loaded yet

                    $.each(sources,function(){
                        images = images.add('<img src="' + this + '" />');
                    });

                    // Start the animation after the first photo is loaded
                    images.first().load(function() {
                        album.trigger('startAnimation');
                    });

                    album
                        .append(images)
                        .addClass('loading');
                }
                else{
                    // Start the animation directly
                    album.trigger('startAnimation');
                }

            }).on('mouseleave', function(){
                album.trigger('stopAnimation');
            });

            // Custom events:

            album.on('startAnimation',function(){

                var iteration = 0;

                // Start looping through the photos
                (function animator(){

                    album.removeClass('loading');

                    // Hide the currently visible photo,
                    // and show the next one:

                    album.find('img').filter(function(){
                        return ($(this).css('opacity') == 1);
                    }).animate({
                        'opacity' : 0
                    }).nextFirst('img').animate({
                        'opacity' : 1
                    });

                    loop = setTimeout(animator, 1000);  // Once per second

                })();

            });

            album.on('stopAnimation',function(){

                album.removeClass('loading');
                // stop the animation
                clearTimeout(loop);
            });

        });

    };

    // This jQuery method will return the next
    // element of the specified type, or the
    // first one if it doesn't exist

    $.fn.nextFirst = function(e) {
        var next = this.nextAll(e).first();
        return (next.length) ? next : this.prevAll(e).last();
    };

})(jQuery);

Estoy usando dos eventos personalizados para organizar mejor mi código startAnimation y stopAnimation. Se activan con mouseenter/mouseleave. La animación es manejada por el animador función, que se llama una vez cada segundo con un tiempo de espera. Puedes modificar esto a tu gusto.

Y así es como se usa:

activos/js/script.js

$(function() {

    // Initialize the plugin
    $('#main .album').albumPreviews();

});

Esto activará el complemento y configurará los controladores de eventos mouseenter/mouseleave en los elementos. Todo lo que tenemos que hacer ahora es agregar un poco de CSS ordenado para que se vea bien.

El CSS

Aquí solo presentaré la parte más interesante de la hoja de estilo. Puedes ver el resto de las reglas CSS en assets/css/styles.css .

Los álbumes tienen el .album clase. Esto hace que sea más fácil darles estilo:

.album{
    width:140px;
    height:140px;
    margin: 15px 5px;
    position:relative;

    display:inline-block;
    border: 4px solid #F0F0F0;
    background-color: #F0F0F0;

    border-radius:12px;
    box-shadow:0 -2px 0 #616161;

    /* Reflections below the image */
    -webkit-box-reflect: below 0 -webkit-linear-gradient(rgba(255,255,255,0) 0%, rgba(255,255,255,0) 80%, rgba(255,255,255,0.1) 100%);
}

/* Showing a subtle shadow on the borders of the image */
.album:before{
    content: '';
    top: -1px;
    left: -1px;
    right: -1px;
    bottom: -1px;
    z-index:1000;
    position: absolute;
    box-shadow: 0 0 2px rgba(0, 0, 0, 0.4) inset;
    border:1px solid #fff;
}

/* The album photos (hidden by default) */
.album img{
    top:0;
    left:0;
    opacity:0;
    width:140px;
    height:140px;
    position:absolute;
}

/* The first (the default) thumbnail is visible */
.album img:first-child{
    opacity:1;
}

.album img,
.album:before{
    border-radius: 10px;
}

/* The preloader PNG. It is rotated with a CSS keyframe animation */

.album .preloader{
    display:none;
}

.album.loading .preloader{
    content:'';
    position:absolute;
    width:18px;
    height:18px;
    background:url('../img/preloader.png') center center;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin:auto;
    display:block;

    /* Configure a keyframe animation for Firefox */
    -moz-animation: rotate 1s linear infinite;

    /* Configure it for Chrome and Safari */
    -webkit-animation: rotate 1s linear infinite;
}

/* Webkit keyframe animation */
@-webkit-keyframes rotate{
    0%{     -webkit-transform:rotate(0deg);}
    100%{   -webkit-transform:rotate(360deg);}
}

/* Firefox Keyframe Animation */
@-moz-keyframes rotate{
    0%{     -moz-transform:rotate(0deg);}
    100%{   -moz-transform:rotate(360deg);}
}

El .precargador png se muestra la primera vez que pasa el mouse sobre el álbum. Luego, el script comienza a cargar las imágenes. Si tiene una conexión rápida, es posible que no lo vea, pero es bueno tenerlo, para dar a los usuarios de redes lentas la sensación de que algo está sucediendo en segundo plano. El precargador está animado con una animación de fotograma clave CSS que se repite una cantidad infinita de veces.

¡Con esta vista previa de nuestro álbum en vivo está completa!

¡Listo!

Puede usar este ejemplo para mejorar la experiencia de los visitantes al usar su sitio. El efecto de vista previa puede ser útil cuando se presenta una gran lista de productos (como el tutorial de búsqueda de productos de Google, donde sería bueno tener fotos de productos adicionales presentadas de esta manera), álbumes, videos, perfiles de usuario y más.

Todo lo que tiene que hacer para usar el ejemplo en su sitio es generar el marcado HTML de los álbumes e incluir el complemento.