Thumbnail Grid with Expanding Preview

A tutorial on how to create a thumbnail grid with an expanding image preview similar to the effect seen on Google Images.

Thumbnail Grid with Expanding Preview

If you have searched images on Google recently, you might have noticed the interesting expanding preview for a larger image when you click on a thumbnail. It’s a really nice effect and it is very practical, making a search much easier. Today we want to show you how to create a similar effect on a thumbnail grid. The idea is to open a preview when clicking on a thumbnail and to show a larger image and some other content like a title, a description and a link.

The interesting part is to calculate the correct preview height and to scroll the page to the right position. We’ll expand the preview in a way so that we can see the respective thumbnail row and cover the rest of the remaining page. Note that we don’t use very large images for the preview in the demo so you might see a lot of empty space on large monitors.

The demo features some amazing artwork by Jaime Martinez.

So let’s start!

The Markup

Initially, we need a thumbnail grid for which we will use an unordered list. Each list item will contain an anchor which will have several data attributes:

<ul id="og-grid" class="og-grid">
	<li>
		<a href="http://cargocollective.com/jaimemartinez/" data-largesrc="images/1.jpg" data-title="Azuki bean" data-description="Swiss chard pumpkin bunya nuts maize plantain aubergine napa cabbage soko coriander sweet pepper water spinach winter purslane shallot tigernut lentil beetroot.">
			<img src="images/thumbs/1.jpg" alt="img01"/>
		</a>
	</li>
	<li>
		<a href="http://cargocollective.com/jaimemartinez/" data-largesrc="images/2.jpg" data-title="Veggies sunt bona vobis" data-description="Komatsuna prairie turnip wattle seed artichoke mustard horseradish taro rutabaga ricebean carrot black-eyed pea turnip greens beetroot yarrow watercress kombu.">
			<img src="images/thumbs/2.jpg" alt="img02"/>
		</a>
	</li>
	<li><!-- ... --></li>
	<!-- ... -->
</ul>

The href value will be used to construct the link in the preview description (this also comes in handy when JavaScript is disabled). The data-largesrc attribute contains the path to the larger image. data-title and data-description contain the title and description, respectively.

When we click on a thumbnail, we want a preview element to appear under the list item. For that we will need to insert an element into the grid. In fact, we will use the list item itself and add the preview element after the anchor:

<li>

	<a href="http://cargocollective.com/jaimemartinez/" data-largesrc="images/2.jpg" data-title="Veggies sunt bona vobis" data-description="Komatsuna prairie turnip wattle seed artichoke mustard horseradish taro rutabaga ricebean carrot black-eyed pea turnip greens beetroot yarrow watercress kombu.">
		<img src="images/thumbs/2.jpg" alt="img02"/>
	</a>
	
	<div class="og-expander">
		<div class="og-expander-inner">
			<span class="og-close"></span>
			<div class="og-fullimg">
				<div class="og-loading"></div>
				<img src="images/2.jpg">
			</div>
			<div class="og-details">
				<h3>Veggies sunt bona vobis</h3>
				<p>Komatsuna prairie turnip wattle seed artichoke mustard horseradish taro rutabaga ricebean carrot black-eyed pea turnip greens beetroot yarrow watercress kombu.</p>
				<a href="http://cargocollective.com/jaimemartinez/">Visit website</a>
			</div>
		</div>
	</div>

</li>

Let’s style everything!

The CSS

Note that the CSS will not contain any vendor prefixes, but you will find them in the files.

So, let’s start with the thumbnail grid. It will be full width and we’ll center the text. In this case this will mean that it will center the thumbnails because we’ll set them to display: inline-block:

.og-grid {
	list-style: none;
	padding: 20px 0;
	margin: 0 auto;
	text-align: center;
	width: 100%;
}

.og-grid li {
	display: inline-block;
	margin: 10px 5px 0 5px;
	vertical-align: top;
	height: 250px;
}

The links and images will be displayed as block elements and we’ll remove some default styling:

.og-grid li > a,
.og-grid li > a img {
	border: none;
	outline: none;
	display: block;
	position: relative;
}

When we click on an item, we will give a special class to the respective list item which will be called og-expanded. We’ll add a little arrow as pseudo-element to the anchor:

.og-grid li.og-expanded > a::after {
	top: auto;
	border: solid transparent;
	content: " ";
	height: 0;
	width: 0;
	position: absolute;
	pointer-events: none;
	border-bottom-color: #ddd;
	border-width: 15px;
	left: 50%;
	margin: -20px 0 0 -15px;
}

The preview itself will have the class og-expander and we’ll position that element absolutely. The initial height of the preview will be 0 and we’ll set the overflow to hidden:

.og-expander {
	position: absolute;
	background: #ddd;
	top: auto;
	left: 0;
	width: 100%;
	margin-top: 10px;
	text-align: left;
	height: 0;
	overflow: hidden;
}

.og-expander-inner {
	padding: 50px 30px;
	height: 100%;
}

The inner division will have some paddings and a height of 100%.

The cross for closing the preview will be created using pseudo-elements, i.e. two rotated lines:

.og-close {
	position: absolute;
	width: 40px;
	height: 40px;
	top: 20px;
	right: 20px;
	cursor: pointer;
}

.og-close::before,
.og-close::after {
	content: '';
	position: absolute;
	width: 100%;
	top: 50%;
	height: 1px;
	background: #888;
	transform: rotate(45deg);
}

.og-close::after {
	transform: rotate(-45deg);
}

.og-close:hover::before,
.og-close:hover::after {
	background: #333;
}

The wrappers for the image and for the details will be 50% wide and we’ll make them float next to each other:

.og-fullimg,
.og-details {
	width: 50%;
	float: left;
	height: 100%;
	overflow: hidden;
	position: relative;
}

The details wrapper will have some padding and we’ll center the image inside of the image wrapper by setting the text-align to center and the image itself to display: inline-block. The image will also have a max-height and max-width of 100% so that it adjusts its size to the surrounding container:

.og-details {
	padding: 0 40px 0 20px;
}

.og-fullimg {
	text-align: center;
}

.og-fullimg img {
	display: inline-block;
	max-height: 100%;
	max-width: 100%;
}

Let’s style the text elements and the link:

.og-details h3 {
	font-weight: 300;
	font-size: 52px;
	padding: 40px 0 10px;
	margin-bottom: 10px;
}

.og-details p {
	font-weight: 400;
	font-size: 16px;
	line-height: 22px;
	color: #999;
}

.og-details a {
	font-weight: 700;
	font-size: 16px;
	color: #333;
	text-transform: uppercase;
	letter-spacing: 2px;
	padding: 10px 20px;
	border: 3px solid #333;
	display: inline-block;
	margin: 30px 0 0;
	outline: none;
}

.og-details a::before {
	content: '2192';
	display: inline-block;
	margin-right: 10px;
}

.og-details a:hover {
	border-color: #999;
	color: #999;
}

The loading element will be in the same container as the image and we’ll not use any images but this CSS-only technique. We’ll create a little circle and set three box shadows: one for making the circle itself look a bit smoother and two for “copying” the element. Then we create an animation that will change the background color and the box shadow colors sequentially:

.og-loading {
	width: 20px;
	height: 20px;
	border-radius: 50%;
	background: #ddd;
	box-shadow: 0 0 1px #ccc, 15px 30px 1px #ccc, -15px 30px 1px #ccc;
	position: absolute;
	top: 50%;
	left: 50%;
	margin: -25px 0 0 -25px;
	animation: loader 0.5s infinite ease-in-out both;
}

@keyframes loader {
	0% { background: #ddd; }
	33% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ccc, -15px 30px 1px #ddd; }
	66% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ddd, -15px 30px 1px #ccc; }
}

Last, but not least, we’ll add two media queries for adjusting the text a bit and for hiding the full image once the screen gets so small that the preview image is not really useful anymore (we’ll also not load it in the JavaScript then).


@media screen and (max-width: 830px) {

	.og-expander h3 { font-size: 32px; }
	.og-expander p { font-size: 13px; }
	.og-expander a { font-size: 12px; }

}

@media screen and (max-width: 650px) {

	.og-fullimg { display: none; }
	.og-details { float: none; width: 100%; }
	
}

That’s all the style. Now, let’s take a look at the JavaScript.

The JavaScript

Let’s start by caching some elements and initializing some variables:

	// list of items
var $grid = $( '#og-grid' ),
	// the items
	$items = $grid.children( 'li' ),
	// current expanded item´s index
	current = -1,
	// position (top) of the expanded item
	// used to know if the preview will expand in a different row
	previewPos = -1,
	// extra amount of pixels to scroll the window
	scrollExtra = 0,
	// extra margin when expanded (between the preview element and the next item row)
	marginExpanded = 10,
	$window = $( window ), winsize,
	$body = $( 'html, body' ),
	// transitionend events
	transEndEventNames = {
		'WebkitTransition' : 'webkitTransitionEnd',
		'MozTransition' : 'transitionend',
		'OTransition' : 'oTransitionEnd',
		'msTransition' : 'MSTransitionEnd',
		'transition' : 'transitionend'
	},
	transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
	// support for csstransitions
	support = Modernizr.csstransitions,
	// default settings
	settings = {
		minHeight : 500,
		speed : 350,
		easing : 'ease'
	};

We will start by preloading all the images (thumbnails) in the grid. We then save the offset top and height for each item in the grid, get the current window’s size, and initialize some events:

	function init( config ) {
		
		// the settings..
		settings = $.extend( true, {}, settings, config );

		// preload all images
		$grid.imagesLoaded( function() {

			// save item´s size and offset
			saveItemInfo( true );
			// get window´s size
			getWinSize();
			// initialize some events
			initEvents();

		} );

	}

	// saves the item´s offset top and height (if saveheight is true)
	function saveItemInfo( saveheight ) {
		$items.each( function() {
			var $item = $( this );
			$item.data( 'offsetTop', $item.offset().top );
			if( saveheight ) {
				$item.data( 'height', $item.height() );
			}
		} );
	}

	function getWinSize() {
		winsize = { width : $window.width(), height : $window.height() };
	}

We will bind the click event for each item (anchor) and for the close button (when the item is opened). When we click on an item, the preview with the large image source and the details will be revealed or hidden if already shown. If we click the close button (cross) on the preview then this preview will be closed too.
We are also binding the resize event for the window, where some values are reset and the preview gets closed (if opened).

	function initEvents() {
		
		// when clicking an item, show the preview with the item´s info and large image;
		// close the item if already expanded.
		// also close if clicking on the item´s cross
		$items.on( 'click', 'span.og-close', function() {
			hidePreview();
			return false;
		} ).children( 'a' ).on( 'click', function(e) {

			var $item = $( this ).parent();
			// check if item already opened
			current === $item.index() ? hidePreview() : showPreview( $item );
			return false;

		} );

		// on window resize get the window´s size again
		// reset some values..
		$window.on( 'debouncedresize', function() {
			
			scrollExtra = 0;
			previewPos = -1;
			// save item´s offset
			saveItemInfo();
			getWinSize();
			var preview = $.data( this, 'preview' );
			if( typeof preview != 'undefined' ) {
				hidePreview();
			}

		} );

	}

With the showPreview function we will basically initialize the Preview object, which in turn will expand and reveal the details and the large version of the image. If a Preview instance is already initialized then we will only update the preview with the new details (if the clicked item is in the same row as the current expanded item) or hide it and initialize / open a new one (if not in the same row).
In order to check if the items are in the same row as the current preview, we use the offset top value of the items.

	function showPreview( $item ) {

		var preview = $.data( this, 'preview' ),
			// item´s offset top
			position = $item.data( 'offsetTop' );

		scrollExtra = 0;

		// if a preview exists and previewPos is different (different row) from item´s top, then close it
		if( typeof preview != 'undefined' ) {

			// not in the same row
			if( previewPos !== position ) {
				// if position > previewPos then we need to take the current preview´s height in consideration when scrolling the window
				if( position > previewPos ) {
					scrollExtra = preview.height;
				}
				hidePreview();
			}
			// same row
			else {
				preview.update( $item );
				return false;
			}
			
		}

		// update previewPos
		previewPos = position;
		// initialize new preview for the clicked item
		preview = $.data( this, 'preview', new Preview( $item ) );
		// expand preview overlay
		preview.open();

	}

The Preview object will have a reference to the currently displayed item (Preview.$item), and the index of the expanded item (Preview.expandedIdx). Note that the expanded item is not necessarily the displayed item. For instance if we click on a second item that is on the same row as the one clicked before then the Preview will be “reused” and the Preview.expandedIdx will not be the index of the Preview.$item. We need to keep the reference to the expanded item so that when the Preview is closed we know which item to “collapse”.

	// the preview obj / overlay
	function Preview( $item ) {
		this.$item = $item;
		this.expandedIdx = this.$item.index();
		this.create();
		this.update();
	}

As the Preview object is initialized we create the necessary structure where the item´s details will be rendered and we append it to the item:

	create : function() {
		// create Preview structure:
		this.$title = $( '<h3></h3>' );
		this.$description = $( '<p></p>' );
		this.$href = $( '<a href="#">Visit website</a>' );
		this.$details = $( '<div class="og-details"></div>' ).append( this.$title, this.$description, this.$href );
		this.$loading = $( '<div class="og-loading"></div>' );
		this.$fullimage = $( '<div class="og-fullimg"></div>' ).append( this.$loading );
		this.$closePreview = $( '<span class="og-close"></span>' );
		this.$previewInner = $( '<div class="og-expander-inner"></div>' ).append( this.$closePreview, this.$fullimage, this.$details );
		this.$previewEl = $( '<div class="og-expander"></div>' ).append( this.$previewInner );
		// append preview element to the item
		this.$item.append( this.getEl() );
		// set the transitions for the preview and the item
		if( support ) {
			this.setTransition();
		}
	}

Then we fill the previous structure with the item´s details (stored in data attributes and the href).
The update function will also be used to just update the content of an existing preview.

	update : function( $item ) {

		// update with new item´s details 
		if( $item ) {
			this.$item = $item;
		}
		
		// if already expanded, remove class "og-expanded" from current item and add it to new item
		if( current !== -1 ) {
			var $currentItem = $items.eq( current );
			$currentItem.removeClass( 'og-expanded' );
			this.$item.addClass( 'og-expanded' );
			// position the preview correctly
			this.positionPreview();
		}

		// update current value
		current = this.$item.index();

		// update preview´s content
		var $itemEl = this.$item.children( 'a' ),
			eldata = {
				href : $itemEl.attr( 'href' ),
				largesrc : $itemEl.data( 'largesrc' ),
				title : $itemEl.data( 'title' ),
				description : $itemEl.data( 'description' )
			};

		this.$title.html( eldata.title );
		this.$description.html( eldata.description );
		this.$href.attr( 'href', eldata.href );

		var self = this;
		
		// remove the current image in the preview
		if( typeof self.$largeImg != 'undefined' ) {
			self.$largeImg.remove();
		}

		// preload large image and add it to the preview
		// for smaller screens we don´t display the large image (the last media query will hide the wrapper of the image)
		if( self.$fullimage.is( ':visible' ) ) {
			this.$loading.show();
			$( '<img/>' ).load( function() {
				self.$loading.hide();
				self.$largeImg = $( this ).fadeIn( 350 );
				self.$fullimage.append( self.$largeImg );
			} ).attr( 'src', eldata.largesrc );	
		}

	}

To reveal the preview we need to set the height of the Preview element and also of the item (to push down the items below). The height of the preview will be the window´s height minus the height of the grid item. To avoid cases where that height could be too small we add the option “minHeight” where we can specify the minimum height needed for the preview element.
As the preview opens we will want to scroll the window so that the preview is completely visible (and if possible, also the item).

	open : function() {

		setTimeout( $.proxy( function() {	
			// set the height for the preview and the item
			this.setHeights();
			// scroll to position the preview in the right place
			this.positionPreview();
		}, this ), 25 );

	}

	setHeights : function() {

		var self = this,
			onEndFn = function() {
				if( support ) {
					self.$item.off( transEndEventName );
				}
				self.$item.addClass( 'og-expanded' );
			};

		this.calcHeight();
		this.$previewEl.css( 'height', this.height );
		this.$item.css( 'height', this.itemHeight ).on( transEndEventName, onEndFn );

		if( !support ) {
			onEndFn.call();
		}

	}

	calcHeight : function() {

		var heightPreview = winsize.height - this.$item.data( 'height' ) - marginExpanded,
			itemHeight = winsize.height;

		if( heightPreview < settings.minHeight ) {
			heightPreview = settings.minHeight;
			itemHeight = settings.minHeight + this.$item.data( 'height' ) + marginExpanded;
		}

		this.height = heightPreview;
		this.itemHeight = itemHeight;

	}

	positionPreview : function() {

		// scroll page
		// case 1 : preview height + item height fits in window´s height
		// case 2 : preview height + item height does not fit in window´s height and preview height is smaller than window´s height
		// case 3 : preview height + item height does not fit in window´s height and preview height is bigger than window´s height
		var position = this.$item.data( 'offsetTop' ),
			previewOffsetT = this.$previewEl.offset().top - scrollExtra,
			scrollVal = this.height + this.$item.data( 'height' ) + marginExpanded <= winsize.height ? position : this.height < winsize.height ? previewOffsetT - ( winsize.height - this.height ) : previewOffsetT;
		
		$body.animate( { scrollTop : scrollVal }, settings.speed );

	}

When closing the preview we reset the heights of the preview element and the expanded item. Once this is done, the preview element / structure gets removed from the DOM.

	close : function() {

		var self = this,
			onEndFn = function() {
				if( support ) {
					$( this ).off( transEndEventName );
				}
				self.$item.removeClass( 'og-expanded' );
				self.$previewEl.remove();
			};

		setTimeout( $.proxy( function() {

			if( typeof this.$largeImg !== 'undefined' ) {
				this.$largeImg.fadeOut( 'fast' );
			}
			this.$previewEl.css( 'height', 0 );
			// the current expanded item (might be different from this.$item)
			var $expandedItem = $items.eq( this.expandedIdx );
			$expandedItem.css( 'height', $expandedItem.data( 'height' ) ).on( transEndEventName, onEndFn );

			if( !support ) {
				onEndFn.call();
			}

		}, this ), 25 );
		
		return false;

	}

And that's it! We hope you enjoyed this tutorial and find it inspiring!

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 477

Comments are closed.
  1. Hi, is this on github? I used the plugin for a friends project and made some upgrades to it like the option for next and previous arrows and made the thumbnail go back to its original position and would like to fork it unfortunately I can’t seem to find it anywhere.

  2. AMAZING <333
    tho my only problem is the [visit website] button.
    is there a way to separate the button on each image preview ? so that each image preview would go to a different URL when they click [visit website]
    help would be much appreciated <33

  3. I keep getting these error’s and iv’e tried everything, not sure why $.event is throwing an error.

    Uncaught TypeError: Cannot read property ‘event’ of undefined grid.js:10
    Uncaught TypeError: Cannot call method ‘init’ of undefined scripts.js:120

    Any help would be much appreciated!

  4. so no has discovered a way to put any kind of html inside the expanded container ? a video, a paragraph, 2 words instead of a picture. ? ?

    • If you look in grid.js, you’ll find that the html is created through javascript and that it takes the contents of data-href and data-description to fill in the content areas (line 343). If you want to custom fill content, you’ll have to do a bit of modifying. First you need to remove the generated content and then you’ll need to update the CSS to properly fit whatever HTML content you have.

  5. It’s bit of of a shame that this is so limited, because the functionality is great. If there was a way to make the slide out section a div instead of using the data attributes, this would be an excellent solution for a lot of people.

  6. When you click on the thumb and the side expands, it’s a link on the bottom. “Visit webside” or anything like that. Is it possible to make this link open in a new tab?

    • on line 347 change:

      this.$href = $( '<a href="#">Visit website</a>' );

      to:

      this.$href = $( '<a href="#" target="_blank">Visit website</a>' );

  7. How could i prevent one block expands? i need just one block without the expand effect, please, help!

  8. omfg…… i just can’t seem to wrap my head around the data attributes and get a darn div to show up in the expanded preview.
    seems like it should be sooooo simple.

  9. Hello all,

    I am using this site framework as a base to build my GF a portfolio for her video work, however I am seeing you can use video? is there some hack-ish way to at least add vimeo videos to this? Any help would be amazing!!

  10. Hi, the question is: how to use two of this in one page.
    I got 3 section in my page about courses: courses 1, courses 2 and courses 3.
    I tried to make all works, but they are in different DIV and UL and using the same IDs or CLASS it simplye does’nt work. The first in order from top works, the second and third didn’t open.
    I searched for solution but nothing happens!

    • Somewhere in the 14 pages of this comment-section this question is answered … It’s thanks to those comments I succesfully managed to have several grids on one page.

  11. How to change the plugin to have the dynamic height?
    I’ve tried to make changes but could not…

  12. This is great, just what I was looking for 🙂

    I’ve gotten it working no problem, and am now trying to overlay text using the title attribute on hover. In the grid view, it works perfectly. But when one of the thumbs is expanded and you hover over one of the boxes, the overlay is misaligned. It only happens in the expanded view. Is anyone else having this issue?

    • I forgot to mention, that the misalignment, is only for the box that is currently expanded. Also note that the only “moving” the grid is doing is window scrolling when the box expands.

  13. How do I remove the link “Visit Website” without affecting the expansion? I have only managed to get rid of the css to the “Visit Website” link but I want to remove it completely.

    • One way is on line 347 of grid.js, do this:
      this.$href = $( '' );

      If you remove the whole line, there are quite a few other instances that need to be removed.

  14. Using this for a site I’m doing and I have added some text under the various thumbnails.

    I now need to be able to move the arrow that appears under the image but I can’t find how to do this. Anyone know?

  15. I’m having a problem with a hover effect I’ve added. It works great in the grid view, but once I expand the preview pane, the hover effect does not move with the images and still hover in the spots where the images were.

    Here is a simplified sample of my code:
    <div class="container"> <div class="main"> <ul id="og-grid"> <li> <a data-title="Title 1" data-description="This is a description"> <img src="images/1.jpg" alt="1"/> </a> <div class="caption a one"> <h3>Title 1</h3> <p>Short Description for the Hover <a href="#" class="red-btn">Read More</a> </p> </div> </li> </ul> </div> </div>
    Anyone have thoughts on this?

  16. I’ve read through the comments and searched other sites, and can’t come up with a viable solution for what I want to do. So, this is a two-part question.

    First : How can you calculate the height of div.og-expanded based on the content height of either div.og-details or div.og-fullimg )depending on which is taller) instead of the window height? I found a somewhat viable solution here, but the answer is pretty vague on how to apply this to the existing grid.js script.

    Second: My site has sticky top navigation, and I can’t figure out how to offset the preview images based on the navigation’s fixed height. So when I click open div.og-expanded the row of images above it is hidden under the navigation.

    I’ve been able to sort out all of the other changes I wanted to make, so any help with these two items is greatly appreciated. Thanks!

    • Hi Matt,

      To get the offset edit the following

      $body . animate ( { scrollTop : scrollVal – 70 } , settings.speed );

      70 is the height of the sticky element

    • Can anyone explain how to change the height of the div.og-expanded to fit the height of the content instead of the offset height of the browser window?

    • I don’t see why not. You just need to supply the URL in the a new data attribute. E.G – data-video=”VIDEOURL” in to the <a href rel=”nofollow”> that’s currently used in the HTML

      You’ll then need to set it up in the JS – Get it added like so:

      videosrc : $ itemEl . data( ‘video’ )

      and then

      this . $href . attar ( ‘href’, eldata . videosrc ) ;

      you’ll need to remove the spaces in the code – I’ve added it in as this comment section doesn’t like code 🙁

    • Where exactly would you put in the videosrc info? I cannot get it to work adding these two things to the grid.js file on lines 386 and 392 (new lines added)

  17. Hello everybody

    Firstly, thanks for this amazing tutorial.

    Can i add slideshow instead of “data-largesrc” image ?

    Thanks for help and sorry for my bad english

  18. Hi everybody!

    Firstly, thanks for this great tutorial! It’s so amazing! Love it!

    But can the link-button “Visit Website” add a “Lightbox”?

    Many thanks for help!

  19. Hi and thanks a lot,
    I founded how to remove “visit website” links on all detail boxes, but I was wondering if there is a way to remove it only for a few of them ?

    Thanks again and excuse my english !

    • Hi Leo!

      Did you be any chance find a solution for this. I’m in the same pickle you’re in.

      Thanks in advance!

    • I had this problem. Here’s what I did:

      The whole thing functions off the <a> tag so you have to work with it. Therefore no matter what you do you’ll end up with a “visit website” link but you can hide it when you want. If you have a link it will insert the link but if there is no link it will just have

      <a href="#">visit website.</a><!--formatted-->

      So in instances where we get the “#” we want to hide the element.

      If you look at line 390 you will see this:
      this.$href.attr( 'href', eldata.href );

      Change/add in this:
      if((eldata.href).indexOf('#') >= 0) { this.$href.attr( 'style', 'display:none;' ); } else { this.$href.attr( 'href', eldata.href ); } <!--formatted-->

      It indexes the value of “eldata.href” and if it finds the “#” it applies an inline style to display none. Otherwise it goes on like normal. Works for me.

  20. Hi there,
    Great little code and I would like to implement this into a site for the company I work for. The question has been raise about using interactive 3d models instead of the large image. I have a script for the interactive 3d model but I’m not sure how to put it in place of the image. Is there away to do this? Plus how do I insert an iframe into the og-expander?

    Cheers

    • Hey Dan

      Can you send me a sample of how the script you need to use? I can have a look at where it’ll need to go and how you can use that and only supply a snippet of code for the specific model 🙂

  21. Hello!
    Anyone knows how to combine this tutorial with for example a Masonry grid? When I apply masonry to it, the expanded view gets fucked.. I want to use different thumb-sizes, and need it to flow.

  22. Hi all,

    This is great btw.

    I see where I can take out the href in previous comments, but I’m looking to only take it out for about half of the items displayed. Is there an easy way in the code to only include the href under certain conditions – if the <a> has a specific class?

    Thanks all,
    (beginner Javascript-er)

  23. Thank you for amazing tutorial.

    I have a question – is there any way to simple add next/prev buttons? I am looking for a solution for few hours and I didn’t find anything. I am very weak in Java :/

    Thx for any help,

    Andres

  24. Hi,

    First I want to thank you for this tutorial.

    I found a little bug when we use the addItems function. If the preview is already open the offsetTop of the news items is wrong. Here is how I handle this little bug. Maybe it’s not perfect but it works for me.

    function addItems( $newitems ) { $items = $items.add( $newitems ); // get the current preview height var preview = $.data( window, 'preview' ); var previewHeight = 0; if(current >= 0) { previewHeight = preview.height; } $newitems.each( function() { var $item = $( this ); $item.data( { offsetTop : $item.offset().top - previewHeight, // remove preview height from offsetTop height : $item.height() } ); } ); initItemsEvents( $newitems ); }

    Olivier

    • Hi,
      thank you for everythig!!

      But….i’ve got some problem with the addItems() function.
      Can you please show me how to do it please?

      Thank you!

  25. I try to do it but doesnt work for me, when I click on the image.. this redirect to other page

  26. Hello everyone!
    ive been going through all the comments and havent managed to get an answer that will help me fix the height of the og-expander
    i changed it on the grid.js but it makes some of the items look too large to the amount of content in them.

    Does anyone have a solution??
    thanks!

  27. Hi, I am trying this code out on thumbnails with different height without success.
    Is there anyway example/way to do that?

  28. Hi, thank you for this cool piece of code, i wonder if there’s a way to implement it in 2 lines of thumbnails but Upper thumbnails to expand top-to-bottom and lower thumbnails to expand bottom-to-top?

  29. Very nice ! btw, is there a way to add this in my wordpress? i want to implement this to my wordpress site ..

  30. Nice tutorial, but I have a problem.I found the fix for multiple grid several pages back but it not seems to work with IE…

    it opens the expander and when I want to close it, the expander will disappear but the page will not “shrink” back to previous height…

    any hints on how to fix this?

  31. Hi,

    Great tutorial!

    I am solely a HTML5 and CSS3 developer though and my javascript is minimal, I am wondering what I would need to do to change the scrollVAL when I am just at a 400px breakpoint.

    I am aware that if i change this line

    $body.animate( { scrollTop : scrollVal }, settings.speed );

    I can set the scrollVal to drop at – ??

    but it then does this across all breakpoints and I only want it to drop by 100px on mobile.

    what would i need to write in order to do this.. any JS developers out there who could help? 🙂

  32. my html page having some images and videos for image it is working fine but how can we use it for video also…. please help..

  33. Hi, great plugin 🙂

    I have a site thats runs stellar.js for parallax and the plugins work just fine whit it. But i will like to add a function that collapse the expander when a user is clicking the main navigation. Is there a way to add this?

    • Add the ID or CLASS of the nav area you want it to close when clicked here:

      $items.on( ‘click’, ‘span.og-close’, function() {

  34. Hello everyone!

    can anyone help me with this particular problem:

    how can you set the height of .og-expander individually instead of the window height? I didn`t found a solution here, searching through the comments. And can somebody explain me how to apply this to the existing grid.js script?

    Thanks!

    • Hey, I’d like to just set them all to a fixed height, rather than filling the window. Do you have any luck figuring it out for your situation?

    • You both need to play about with both of these functions:

      calcHeight : function() {
      setHeights : function() {

  35. Can anyone help me add a swf like you would a large image, I’m having trouble handling the loading of the object?

  36. Great Article Mary!

    This would make a great way to present a photography porfolio or something similar in nature. 🙂

  37. Hi there
    I would like to open a certain item when loading the page. So basically i forward parameters in the url and then select the item i want to open based on this info by calling:
    Grid.showPreview($item);
    The item opens as it is supposed to. But when I then click on the close button i get the following error inside hidePreview() function:
    Uncaught TypeError: Cannot call method 'close' of undefined
    What do I have to do, that the Grid system knows, which item i have just opened so that it can close it.
    Because it gets stuck when calling var preview = $.data( this, 'preview' ); inside the hidePreview() function.
    I hope you understand what I mean by all this 🙂
    Best,
    Daniel

  38. HI, i need to know if there is any option to add a custom filter so user can group the thumbnails by filtering?

  39. when i use the plugin twice on the same page i am getting problems. can anyone help plz.

  40. Hi! Great script this! Although I have a question. Can I use it to show a slideshow (manual or automatic) inside the frame, in the area where the picture is? Basically to be able to show multiple images within the slider?

    • See my latest comment at the end of this comment thread for a demo of this 🙂

    • You need to create this a page template in a WordPress php file and then use a loop to go through posts, or something, that puts all the data from the post in to a template preview/thumb DIV ( a image that is clicked on to expand the preview )

  41. I really like this! I have a project that would split this plugin vertically. Any chance you had an idea in doing?

  42. I’m really loving these great tutorials. I’ve adapted the caption hover effects to use for my WordPress portfolio. But I would absolutely *love* to find a way to combine that one with this one – on clicking the button in the overlay (I’m using style 4 of those hover effects – the one with the block covering half the width of the image on hover) and then the content window slides down below. Any ideas how that could be done? I haven’t had any luck yet so I thought I’d ask.

  43. Hey, love this tutorial. You break it down and explain very well. I slightly modified it to run within a centered div at 80% of screen that runs down the page. I am running into one problem which i can’t figure out. The arrow that connects the expander to the thumbnail doesn’t disappear when the expander is closed. So i basically end up with multiple thumbnails with the small arrow on the bottom still even when the expander isn’t open. This is a a:after element, and i can’t figure out how to correct problem. Any help would be great! Thanks in advance.