THUMBNAIL PROXIMITY EFFECT WITH JQUERY AND CSS3

By | October 18, 2014
0
0



Today we want to show you how to create a neat thumbnail proximity effect with jQuery.  This is our attempt to recreate the basics of that effect.

THE MARKUP

We’ll use an unordered list for the thumbnails and add a division for the description of each image (for this tutorial, we will be going through demo 2):

<ul id="pe-thumbs" class="pe-thumbs">
    <li>
        <a href="#">
            <img src="images/thumbs/1.jpg" />
            <div class="pe-description">
                <h3>Time</h3>
                <p>Since time, and his predestinated end</p>
            </div></a>
    </li>
    <li><!-- ... --></li>
</ul>

Let’s style it!

THE CSS

The unordered list will be centered on the page and we’ll add a background image to “shine through” the thumbnails that will have a low opacity:

.pe-thumbs{
    width: 900px;
    height: 400px;
    margin: 20px auto;
    position: relative;
    background: transparent url(../images/3.jpg) top center;
    border: 5px solid #fff;
    box-shadow: 0 1px 2px rgba(0,0,0,0.2);
}

We’ll also add a bit of tint to the background image by adding a pseudo element with a rgba background color:

.pe-thumbs:before {
    content: "";
    display: block;
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 100%;
    background: rgba(255,102,0,0.2);
}

The list items will float left and we’ll set the position of the anchors and images to relative:

.pe-thumbs li{
    float: left;
    position: relative;
}
.pe-thumbs li a,
.pe-thumbs li a img{
    display: block;
    position: relative;
}

Each thumbnail will have an initial width of 100 pixels and an opacity of 0.2:

.pe-thumbs li a img{
    width: 100px;
    opacity: 0.2;
}

The discription will be hidden by default and then we will make it appear using JavaScript:

.pe-thumbs li a div.pe-description{
    width: 200px;
    height: 100px;
    background: rgba(0,0,0,0.8);
    position: absolute;
    top: 0px;
    left: -200px;
    color: white;
    display: none;
    z-index: 1001;
    text-align: left;
}

And finally, let’s style the content of the description division:

.pe-description h3{
    padding: 10px 10px 0px 10px;
    line-height: 20px;
    font-family: 'BebasNeueRegular', 'Arial Narrow', Arial, sans-serif;
    font-size: 22px;
    margin: 0px;
}
.pe-description p{
    padding: 10px 0px;
    margin: 10px;
    font-size: 11px;
    font-style: italic;
    border-top: 1px solid rgba(255,255,255,0.3);
}

And that’s all the style! Let’s move on to the JavaScript!

THE JAVASCRIPT

The main idea is to first of all calculate the description container size and position when we hover over a thumbnail. This depends of course on the maximum scale of the thumbnail and where the thumbnail is located in the main wrapper. For example, when the thumbnail is close to the right edge, we’ll want to make the description box appear on the left side of the thumbnail.

Then we’ll need to bind the proximity event to the images. The idea is to scale the images up or down according to the position of the mouse. Once the image scales to the maximum value, we set its z-index very high, so that it stays on top, and we show the respective description:

    // list of thumbs
var $list       = $('#pe-thumbs'),
    // list's width and offset left.
    // this will be used to know the position of the description container
    listW       = $list.width(),
    listL       = $list.offset().left,
    // the images
    $elems      = $list.find('img'),
    // the description containers
    $descrp     = $list.find('div.pe-description'),
    // maxScale : maximum scale value the image will have
    // minOpacity / maxOpacity : minimum (set in the CSS) and maximum values for the image's opacity
    settings    = {
        maxScale    : 1.3,
        maxOpacity  : 0.9,
        minOpacity  : Number( $elems.css('opacity') )
    },
    init        = function() {
        
        // minScale will be set in the CSS
        settings.minScale = _getScaleVal() || 1;
        // preload the images (thumbs)
        _loadImages( function() {
            
            _calcDescrp();
            _initEvents();
        
        });
    
    },
    // Get Value of CSS Scale through JavaScript:
    // http://css-tricks.com/get-value-of-css-rotation-through-javascript/
    _getScaleVal= function() {
    
        var st = window.getComputedStyle($elems.get(0), null),
            tr = st.getPropertyValue("-webkit-transform") ||
                 st.getPropertyValue("-moz-transform") ||
                 st.getPropertyValue("-ms-transform") ||
                 st.getPropertyValue("-o-transform") ||
                 st.getPropertyValue("transform") ||
                 "fail...";
        if( tr !== 'none' ) {   
            var values = tr.split('(')[1].split(')')[0].split(','),
                a = values[0],
                b = values[1],
                c = values[2],
                d = values[3];
            return Math.sqrt( a * a + b * b );
        
        }
        
    },
    // calculates the style values for the description containers,
    // based on the settings variable
    _calcDescrp = function() {
        
        $descrp.each( function(i) {
        
            var $el     = $(this),
                $img    = $el.prev(),
                img_w   = $img.width(),
                img_h   = $img.height(),
                img_n_w = settings.maxScale * img_w,
                img_n_h = settings.maxScale * img_h,
                space_t = ( img_n_h - img_h ) / 2,
                space_l = ( img_n_w - img_w ) / 2;
            
            $el.data( 'space_l', space_l ).css({
                height  : settings.maxScale * $el.height(),
                top     : -space_t,
                left    : img_n_w - space_l
            });
        
        });
    
    },
    _initEvents = function() {
    
        $elems.on('proximity.Photo', { max: 80, throttle: 10, fireOutOfBounds : true }, function(event, proximity, distance) {
            
            var $el         = $(this),
                $li         = $el.closest('li'),
                $desc       = $el.next(),
                scaleVal    = proximity * ( settings.maxScale - settings.minScale ) + settings.minScale,
                scaleExp    = 'scale(' + scaleVal + ')';
            // change the z-index of the element once
            // it reaches the maximum scale value
            // also, show the description container
            if( scaleVal === settings.maxScale ) {
                
                $li.css( 'z-index', 1000 );
                
                if( $desc.offset().left + $desc.width() > listL + listW ) {
                    
                    $desc.css( 'left', -$desc.width() - $desc.data( 'space_l' ) );
                
                }
                
                $desc.fadeIn( 800 );
                
            }  
            else {
                
                $li.css( 'z-index', 1 );
            
                $desc.stop(true,true).hide();
            
            }  
            
            $el.css({
                '-webkit-transform' : scaleExp,
                '-moz-transform'    : scaleExp,
                '-o-transform'      : scaleExp,
                '-ms-transform'     : scaleExp,
                'transform'         : scaleExp,
                'opacity'           : ( proximity * ( settings.maxOpacity - settings.minOpacity ) + settings.minOpacity )
            });
        });
    
    },
    _loadImages = function( callback ) {
        
        var loaded  = 0,
            total   = $elems.length;
        
        $elems.each( function(i) {
            
            var $el = $(this);
            
            $('<img>').load( function() {
                
                ++loaded;
                if( loaded === total )
                    callback.call();
                
            }).attr( 'src', $el.attr('src') );
        
        });
    
    };
return {
    init    : init
};

Leave a Reply

Your email address will not be published. Required fields are marked *