From our sponsor: Meco is a distraction-free space for reading and discovering newsletters, separate from the inbox.
Today we want to show you how to create a neat thumbnail proximity effect with jQuery. The idea is to scale thumbnails when hovering over them and also scale their neighbouring thumbnails proportionally to their distance. We’ll also make a description appear.
This is based on a request we once got from a reader who asked if the effect on http://porscheeveryday.com/ could be achieved with jQuery. This is our attempt to recreate the basics of that effect.
We will be using the jQuery Proximity plugin by James Padolsey.
The illustations in the demos are by Florian Nicolle and they are licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.
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); $('').load( function() { ++loaded; if( loaded === total ) callback.call(); }).attr( 'src', $el.attr('src') ); }); }; return { init : init };
Demos
Check out all three examples:
Inspiring! Demo 2 is excellent, especially if it were combined with a smooth lightbox. Fantastic concept.
I LOVE YOU !
i will use this, thank you MARY LOU
it’s very nice effect, i have mentioned it on my blog :).. http://blog.tangyandbrightdesigns.com/2012/01/04/thumbnail-proximity-effect-with-jquery-and-css3by-codrops/
You Rock Mary!!! ThankU so much once again!
Demo 3 is really really good. Thanks !
Awesome like always thanks!
I love Lou
very nice
Mary, which programs you use to make your code and design?
Answer me please.
Luv ur jobs!
Really Good effect
Can i use it for my website?
This is great! Stupid question but has IE9 adopted CSS3?
Great! I especially like the demo 3.
Could also the background change when hovering over the thumbnails (excuse my English, I’m French)?
@Joe, yes. IE9 is okay.
awesome effect, and it’s work great on IE9.
Wow… this is awesome! This is hands down the best design/dev blog I’ve ever read.
Wonderful. lovely pictures layout
yeah !.
fun !
Fantastic! But it seems to not work in IE7 or IE8? Being these are large amounts of the online world (currently 22% for both), are there workarounds for these browsers?
Amazing! I love this effect… I’m creating a set of templates for my website and this one is a must! Keep being amazing.
Demo 3 is gooder 😀
Wooow, It’s very cool !
I noticed there is a nice fallback for IE7/8. However, in Mobile Safari the full version shows – but of course can’t be used since no rollovers on an iPad.
It would be better to display the IE7 version on mobile devices for this reason. How would I accomplish that?
Steve –
what ‘nice fallback’ are you referring to for IE7/8? It’s merely a broken-looking grid that has no roll over effect, with functionality stripped. Or are you referring to something else you implemented?
Love the demo 3, nice effect, indeed!
This effect is really smart and just shows off what can do with JQuery and some imagination 🙂
Mary…You are a master to me…great idea and concept with fantastic coding… Thanks a lot Mary Lou!
Mary Lou..I love your works..tanks a lot ..best regards to you sister.
my good
exactly like water dropping on a warm spring pond…regards
Great! A 4th example with an overlay on click of a picture would be nice or something like that don’t you think so?
Really nice effect, improved a bit by adding ‘overflow:hidden;’ to ‘.pe-thumbs li a, .pe-thumbs li a img’ as follows:
.pe-thumbs li a, .pe-thumbs li a img {
overflow:hidden;
}
Hi,
By adding JQuery sortable to this I was able to do what would, otherwise be a really complicated UI, in a really simple and wicked way… So, again Mary (and I’m fully aware that I must be repeating myself). THANK YOU.
Really nice! Is it possible to use any box script in conjunction? I tried a few different ones but to no avail…
i its a really nice effect.. but it does not work on IE7/8.. the thumbs just froze all together. please i need a solution..
Yes, it’s broken in IE7/8 – nothing is clickable, is there a patch coming out soon for this? We love the script but it needs a bit of love!
This is great! I got it to work with highslide js – you can click on an image and go to a YouTube video for ex. http://ww.fatherhood101.zxq.net (test site). Bummed that the effect doesn’t work on an iPad, would be perfect if it could trace your finger. Love all the awesome tutorials here though!
Hi Mary Lou,
I’ve just tried to implement this tutorial you’ve created and the functionality doesn’t appear to work in IE7/8.
Are there any workarounds to get this fantastic script to work in IE7/8? I’ve read through the comments and there doesn’t seem to be any response or solution to this issue.
Your help or response would be greatly appreciated, especially in this community too.
Adeline
Does anybody have a solution to get this fantastic script run in IE 7/8/9?
Thanks for an answer!
This is awesome….But I don’t know why it is not working on my website.