Google Grid Gallery

A responsive Masonry grid with a gallery view using 3D Transforms. Based on the gallery seen on the Chromebook Getting Started guide by Google.

This Blueprint is a responsive grid gallery based on the gallery by Google for the Chromebook Getting Started guide. In this Blueprint we use Masonry for the grid and 3D transforms for navigating the items. For smaller screens we have some example media queries that adjust the grid layout and also the gallery view.

In the gallery view, the arrow keys can be used to navigate and the view can be closed using the “Esc” key.

Please note that we are using CSS 3D Transforms which are only supported in modern browsers.

The images used in the demo were created using the grafitti shapes by Luke Roberts.

The HTML

<div id="grid-gallery" class="grid-gallery">
	<section class="grid-wrap">
		<ul class="grid">
			<li class="grid-sizer"></li><!-- for Masonry column width -->
			<li>
				<figure>
					<img src="img/thumb/1.png" alt="img01"/>
					<figcaption><h3>Letterpress asymmetrical</h3><p>Chillwave hoodie ea gentrify aute sriracha consequat.</p></figcaption>
				</figure>
			</li>
			<li>
				<figure>
					<img src="img/thumb/2.png" alt="img02"/>
					<figcaption><h3>Vice velit chia</h3><p>Laborum tattooed iPhone, Schlitz irure nulla Tonx retro 90's chia cardigan quis asymmetrical paleo. </p></figcaption>
				</figure>
			</li>
			<li>
				<figure>
					<img src="img/thumb/3.png" alt="img03"/>
					<figcaption><h3>Brunch semiotics</h3><p>Ex disrupt cray yr, butcher pour-over magna umami kitsch before they sold out commodo.</p></figcaption>
				</figure>
			</li>
			<li>
				<figure>
					<img src="img/thumb/4.png" alt="img04"/>
					<figcaption><h3>Chillwave nihil occupy</h3><p>In post-ironic gluten-free deserunt, PBR&B non pork belly cupidatat polaroid. </p></figcaption>
				</figure>
			</li>
			<li>
				<figure>
					<img src="img/thumb/5.png" alt="img05"/>
					<figcaption><h3>Kale chips lomo biodiesel</h3><p>Pariatur food truck street art consequat sustainable, et kogi beard qui paleo. </p></figcaption>
				</figure>
			</li>
			<li>
				<figure>
					<img src="img/thumb/6.png" alt="img06"/>
					<figcaption><h3>Exercitation occaecat</h3><p>Street chillwave hoodie ea gentrify.</p></figcaption>
				</figure>
			</li>
		</ul>
	</section><!-- // grid-wrap -->
	<section class="slideshow">
		<ul>
			<li>
				<figure>
					<figcaption>
						<h3>Letterpress asymmetrical</h3>
						<p>Kale chips lomo biodiesel stumptown Godard Tumblr, mustache sriracha tattooed cray aute slow-carb placeat delectus. Letterpress asymmetrical fanny pack art party est pour-over skateboard anim quis, ullamco craft beer.</p>
					</figcaption>
					<img src="img/large/1.png" alt="img01"/>
				</figure>
			</li>
			<li>
				<figure>
					<figcaption>
						<h3>Vice velit chia</h3>
						<p>Chillwave Echo Park Etsy organic Cosby sweater seitan authentic pour-over. Occupy wolf selvage bespoke tattooed, cred sustainable Odd Future hashtag butcher.</p>
					</figcaption>
					<img src="img/large/2.png" alt="img02"/>
				</figure>
			</li>
			<li>
				<figure>
					<figcaption>
						<h3>Brunch semiotics</h3>
						<p>IPhone PBR polaroid before they sold out meh you probably haven't heard of them leggings tattooed tote bag, butcher paleo next level single-origin coffee photo booth.</p>
					</figcaption>
					<img src="img/large/3.png" alt="img03"/>
				</figure>
			</li>
			<li>
				<figure>
					<figcaption>
						<h3>Chillwave nihil occupy</h3>
						<p>Vice cliche locavore mumblecore vegan wayfarers asymmetrical letterpress hoodie mustache. Shabby chic lomo polaroid, scenester 8-bit Portland Pitchfork VHS tote bag.</p>
					</figcaption>
					<img src="img/large/4.png" alt="img04"/>
				</figure>
			</li>
			<li>
				<figure>
					<figcaption>
						<h3>Kale chips lomo biodiesel</h3>
						<p>Chambray Schlitz pug YOLO, PBR Tumblr semiotics. Flexitarian YOLO ennui Blue Bottle, forage dreamcatcher chillwave put a bird on it craft beer Etsy.</p>
					</figcaption>
					<img src="img/large/5.png" alt="img05"/>
				</figure>
			</li>
			<li>
				<figure>
					<figcaption>
						<h3>Exercitation occaecat</h3>
						<p>Cosby sweater hella lomo Thundercats VHS occupy High Life. Synth pop-up readymade single-origin coffee, fanny pack tousled retro. Fingerstache mlkshk ugh hashtag, church-key ethnic street art pug yr.</p>
					</figcaption>
					<img src="img/large/6.png" alt="img06"/>
				</figure>
			</li>
		</ul>
		<nav>
			<span class="icon nav-prev"></span>
			<span class="icon nav-next"></span>
			<span class="icon nav-close"></span>
		</nav>
		<div class="info-keys icon">Navigate with arrow keys</div>
	</section><!-- // slideshow -->
</div><!-- // grid-gallery -->

<script src="js/imagesloaded.pkgd.min.js"></script>
<script src="js/masonry.pkgd.min.js"></script>
<script src="js/classie.js"></script>
<script src="js/cbpGridGallery.js"></script>
<script>
	new CBPGridGallery( document.getElementById( 'grid-gallery' ) );
</script>

The CSS

@font-face {
	font-family: 'fontawesome';
	src:url('../fonts/fontawesome/fontawesome.eot?-e43dk9');
	src:url('../fonts/fontawesome/fontawesome.eot?#iefix-e43dk9') format('embedded-opentype'),
		url('../fonts/fontawesome/fontawesome.woff?-e43dk9') format('woff'),
		url('../fonts/fontawesome/fontawesome.ttf?-e43dk9') format('truetype'),
		url('../fonts/fontawesome/fontawesome.svg?-e43dk9#fontawesome') format('svg');
	font-weight: normal;
	font-style: normal;
} /* Made with http://icomoon.io/app */

/* General style */
.grid-gallery ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.grid-gallery figure {
	margin: 0;
}

.grid-gallery figure img {
	display: block;
	width: 100%;
}

.grid-gallery figcaption h3 {
	margin: 0;
	padding: 0 0 0.5em;
}

.grid-gallery figcaption p {
	margin: 0;
}

/* Grid style */
.grid-wrap {
	max-width: 69em;
	margin: 0 auto;
	padding: 0 1em 1.875em;
}

.grid {
	margin: 0 auto;
}

.grid li {
	width: 25%;
	float: left;
	cursor: pointer;
}

.grid figure {
	padding: 15px;
	-webkit-transition: opacity 0.2s;
	transition: opacity 0.2s;
}

.grid li:hover figure {
	opacity: 0.7;
}

.grid figcaption {
	background: #e4e4e4;
	padding: 25px;
}

/* Slideshow style */
.slideshow {
	position: fixed;
	background: rgba(0,0,0,0.6);
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
	z-index: 500;
	opacity: 0;
	visibility: hidden;
	overflow: hidden;
	-webkit-perspective: 1000px;
	perspective: 1000px;
	-webkit-transition: opacity 0.5s, visibility 0s 0.5s;
	transition: opacity 0.5s, visibility 0s 0.5s;
}

.slideshow-open .slideshow {
	opacity: 1;
	visibility: visible;
	-webkit-transition: opacity 0.5s;
	transition: opacity 0.5s;
}

.slideshow ul {
	width: 100%;
	height: 100%;
	-webkit-transform-style: preserve-3d;
	transform-style: preserve-3d;
	-webkit-transform: translate3d(0,0,150px);
	transform: translate3d(0,0,150px);
	-webkit-transition: -webkit-transform 0.5s;
	transition: transform 0.5s;
}

.slideshow ul.animatable li {
	-webkit-transition: -webkit-transform 0.5s;
	transition: transform 0.5s;
}

.slideshow-open .slideshow ul {
	-webkit-transform: translate3d(0,0,0);
	transform: translate3d(0,0,0);
}

.slideshow li {
	width: 660px;
	height: 560px;
	position: absolute;
	top: 50%;
	left: 50%;
	margin: -280px 0 0 -330px;
	visibility: hidden;
}

.slideshow li.show {
	visibility: visible;
}

.slideshow li:after {
	content: '';
	position: absolute;
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
	background: rgba(255,255,255,0.8);
	-webkit-transition: opacity 0.3s;
	transition: opacity 0.3s;
}

.slideshow li.current:after {
	visibility: hidden;
	opacity: 0;
	-webkit-transition: opacity 0.3s, visibility 0s 0.3s;
	transition: opacity 0.3s, visibility 0s 0.3s;
}

.slideshow figure {
	width: 100%;
	height: 100%;
	background: #fff;
	border: 50px solid #fff;
	overflow: hidden;
}

.slideshow figcaption {
	padding-bottom: 20px;
}

.slideshow figcaption h3 {
	font-weight: 300;
	font-size: 200%;
}

/* Navigation */
.slideshow nav span {
	position: fixed;
	z-index: 1000;
	color: #59656c;
	text-align: center;
	padding: 3%;
	cursor: pointer;
	font-size: 2.2em;
}

.slideshow nav span.nav-prev,
.slideshow nav span.nav-next {
	top: 50%;
	-webkit-transform: translateY(-50%);
	transform: translateY(-50%);
}

.slideshow nav span.nav-next {
	right: 0;
}

.slideshow nav span.nav-close {
	top: 0;
	right: 0;
	padding: 0.5em 1em;
	color: #31373a;
}

.icon:before,
.icon:after {
	font-family: 'fontawesome';
	speak: none;
	font-style: normal;
	font-weight: normal;
	font-variant: normal;
	text-transform: none;
	line-height: 1;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

span.nav-prev:before {
	content: "e601";
}

span.nav-next:before  {
	content: "e600";
}

span.nav-close:before {
	content: "e602";
}

/* Info on arrow key navigation */
.info-keys {
	position: fixed;
	top: 10px;
	left: 10px;
	width: 60px;
	font-size: 8px;
	padding-top: 20px;
	text-transform: uppercase;
	color: #fff;
	letter-spacing: 1px;
	text-align: center;
}

.info-keys:before,
.info-keys:after {
	position: absolute;
	top: 0;
	width: 16px;
	height: 16px;
	border: 1px solid #fff;
	text-align: center;
	line-height: 14px;
	font-size: 12px;
}

.info-keys:before {
	left: 10px;
	content: "e603";
}

.info-keys:after {
	right: 10px;
	content: "e604";
}

/* Example media queries (reduce number of columns and change slideshow layout) */

@media screen and (max-width: 60em) {
	/* responsive columns; see "Element sizing" on http://masonry.desandro.com/options.html */
	.grid li {
		width: 33.3%;
	}

	.slideshow li {
		width: 100%;
		height: 100%;
		top: 0;
		left: 0;
		margin: 0;
	}

	.slideshow li figure img {
		width: auto;
		margin: 0 auto;
		max-width: 100%;
	}

	.slideshow nav span,
	.slideshow nav span.nav-close {
		font-size: 1.8em;
		padding: 0.3em;
	}

	.info-keys {
		display: none;
	}

}

@media screen and (max-width: 35em) {
	.grid li {
		width: 50%;
	}
}

@media screen and (max-width: 24em) {
	.grid li {
		width: 100%;
	}
}

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 JavaScript

/**
 * cbpGridGallery.js v1.0.0
 * http://www.codrops.com
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * 
 * Copyright 2014, Codrops
 * http://www.codrops.com
 */
;( function( window ) {
	
	'use strict';

	var docElem = window.document.documentElement,
		transEndEventNames = {
			'WebkitTransition': 'webkitTransitionEnd',
			'MozTransition': 'transitionend',
			'OTransition': 'oTransitionEnd',
			'msTransition': 'MSTransitionEnd',
			'transition': 'transitionend'
		},
		transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
		support = {
			transitions : Modernizr.csstransitions,
			support3d : Modernizr.csstransforms3d
		};

	function setTransform( el, transformStr ) {
		el.style.WebkitTransform = transformStr;
		el.style.msTransform = transformStr;
		el.style.transform = transformStr;
	}

	// from http://responsejs.com/labs/dimensions/
	function getViewportW() {
		var client = docElem['clientWidth'],
			inner = window['innerWidth'];
		
		if( client < inner )
			return inner;
		else
			return client;
	}

	function extend( a, b ) {
		for( var key in b ) { 
			if( b.hasOwnProperty( key ) ) {
				a[key] = b[key];
			}
		}
		return a;
	}

	function CBPGridGallery( el, options ) {
		this.el = el;
		this.options = extend( {}, this.options );
  		extend( this.options, options );
  		this._init();
	}

	CBPGridGallery.prototype.options = {
	};

	CBPGridGallery.prototype._init = function() {
		// main grid
		this.grid = this.el.querySelector( 'section.grid-wrap > ul.grid' );
		// main grid items
		this.gridItems = [].slice.call( this.grid.querySelectorAll( 'li:not(.grid-sizer)' ) );
		// items total
		this.itemsCount = this.gridItems.length;
		// slideshow grid
		this.slideshow = this.el.querySelector( 'section.slideshow > ul' );
		// slideshow grid items
		this.slideshowItems = [].slice.call( this.slideshow.children );
		// index of current slideshow item
		this.current = -1;
		// slideshow control buttons
		this.ctrlPrev = this.el.querySelector( 'section.slideshow > nav > span.nav-prev' );
		this.ctrlNext = this.el.querySelector( 'section.slideshow > nav > span.nav-next' );
		this.ctrlClose = this.el.querySelector( 'section.slideshow > nav > span.nav-close' );
		// init masonry grid
		this._initMasonry();
		// init events
		this._initEvents();
	};

	CBPGridGallery.prototype._initMasonry = function() {
		var grid = this.grid;
		imagesLoaded( grid, function() {
			new Masonry( grid, {
				itemSelector: 'li',
				columnWidth: grid.querySelector( '.grid-sizer' )
			});
		});
	};

	CBPGridGallery.prototype._initEvents = function() {
		var self = this;

		// open the slideshow when clicking on the main grid items
		this.gridItems.forEach( function( item, idx ) {
			item.addEventListener( 'click', function() {
				self._openSlideshow( idx );
			} );
		} );

		// slideshow controls
		this.ctrlPrev.addEventListener( 'click', function() { self._navigate( 'prev' ); } );
		this.ctrlNext.addEventListener( 'click', function() { self._navigate( 'next' ); } );
		this.ctrlClose.addEventListener( 'click', function() { self._closeSlideshow(); } );

		// window resize
		window.addEventListener( 'resize', function() { self._resizeHandler(); } );

		// keyboard navigation events
		document.addEventListener( 'keydown', function( ev ) {
			if ( self.isSlideshowVisible ) {
				var keyCode = ev.keyCode || ev.which;

				switch (keyCode) {
					case 37:
						self._navigate( 'prev' );
						break;
					case 39:
						self._navigate( 'next' );
						break;
					case 27:
						self._closeSlideshow();
						break;
				}
			}
		} );

		// trick to prevent scrolling when slideshow is visible
		window.addEventListener( 'scroll', function() {
			if ( self.isSlideshowVisible ) {
				window.scrollTo( self.scrollPosition ? self.scrollPosition.x : 0, self.scrollPosition ? self.scrollPosition.y : 0 );
			}
			else {
				self.scrollPosition = { x : window.pageXOffset || docElem.scrollLeft, y : window.pageYOffset || docElem.scrollTop };
			}
		});
	};

	CBPGridGallery.prototype._openSlideshow = function( pos ) {
		this.isSlideshowVisible = true;
		this.current = pos;

		classie.addClass( this.el, 'slideshow-open' );

		/* position slideshow items */

		// set viewport items (current, next and previous)
		this._setViewportItems();
		
		// add class "current" and "show" to currentItem
		classie.addClass( this.currentItem, 'current' );
		classie.addClass( this.currentItem, 'show' );

		// add class show to next and previous items
		// position previous item on the left side and the next item on the right side
		if( this.prevItem ) {
			classie.addClass( this.prevItem, 'show' );
			var translateVal = Number( -1 * ( getViewportW() / 2 + this.prevItem.offsetWidth / 2 ) );
			setTransform( this.prevItem, support.support3d ? 'translate3d(' + translateVal + 'px, 0, -150px)' : 'translate(' + translateVal + 'px)' );
		}
		if( this.nextItem ) {
			classie.addClass( this.nextItem, 'show' );
			var translateVal = Number( getViewportW() / 2 + this.nextItem.offsetWidth / 2 );
			setTransform( this.nextItem, support.support3d ? 'translate3d(' + translateVal + 'px, 0, -150px)' : 'translate(' + translateVal + 'px)' );
		}
	};

	CBPGridGallery.prototype._navigate = function( dir ) {
		if( this.isAnimating ) return;
		if( dir === 'next' && this.current === this.itemsCount - 1 ||  dir === 'prev' && this.current === 0  ) {
			this._closeSlideshow();
			return;
		}

		this.isAnimating = true;
		
		// reset viewport items
		this._setViewportItems();

		var self = this,
			itemWidth = this.currentItem.offsetWidth,
			// positions for the centered/current item, both the side items and the incoming ones
			transformLeftStr = support.support3d ? 'translate3d(-' + Number( getViewportW() / 2 + itemWidth / 2 ) + 'px, 0, -150px)' : 'translate(-' + Number( getViewportW() / 2 + itemWidth / 2 ) + 'px)',
			transformRightStr = support.support3d ? 'translate3d(' + Number( getViewportW() / 2 + itemWidth / 2 ) + 'px, 0, -150px)' : 'translate(' + Number( getViewportW() / 2 + itemWidth / 2 ) + 'px)',
			transformCenterStr = '', transformOutStr, transformIncomingStr,
			// incoming item
			incomingItem;

		if( dir === 'next' ) {
			transformOutStr = support.support3d ? 'translate3d( -' + Number( (getViewportW() * 2) / 2 + itemWidth / 2 ) + 'px, 0, -150px )' : 'translate(-' + Number( (getViewportW() * 2) / 2 + itemWidth / 2 ) + 'px)';
			transformIncomingStr = support.support3d ? 'translate3d( ' + Number( (getViewportW() * 2) / 2 + itemWidth / 2 ) + 'px, 0, -150px )' : 'translate(' + Number( (getViewportW() * 2) / 2 + itemWidth / 2 ) + 'px)';
		}
		else {
			transformOutStr = support.support3d ? 'translate3d( ' + Number( (getViewportW() * 2) / 2 + itemWidth / 2 ) + 'px, 0, -150px )' : 'translate(' + Number( (getViewportW() * 2) / 2 + itemWidth / 2 ) + 'px)';
			transformIncomingStr = support.support3d ? 'translate3d( -' + Number( (getViewportW() * 2) / 2 + itemWidth / 2 ) + 'px, 0, -150px )' : 'translate(-' + Number( (getViewportW() * 2) / 2 + itemWidth / 2 ) + 'px)';
		}

		// remove class animatable from the slideshow grid (if it has already)
		classie.removeClass( self.slideshow, 'animatable' );

		if( dir === 'next' && this.current < this.itemsCount - 2 || dir === 'prev' && this.current > 1 ) {
			// we have an incoming item!
			incomingItem = this.slideshowItems[ dir === 'next' ? this.current + 2 : this.current - 2 ];
			setTransform( incomingItem, transformIncomingStr );
			classie.addClass( incomingItem, 'show' );
		}

		var slide = function() {
			// add class animatable to the slideshow grid
			classie.addClass( self.slideshow, 'animatable' );

			// overlays:
			classie.removeClass( self.currentItem, 'current' );
			var nextCurrent = dir === 'next' ? self.nextItem : self.prevItem;
			classie.addClass( nextCurrent, 'current' );

			setTransform( self.currentItem, dir === 'next' ? transformLeftStr : transformRightStr );

			if( self.nextItem ) {
				setTransform( self.nextItem, dir === 'next' ? transformCenterStr : transformOutStr );
			}

			if( self.prevItem ) {
				setTransform( self.prevItem, dir === 'next' ? transformOutStr : transformCenterStr );
			}

			if( incomingItem ) {
				setTransform( incomingItem, dir === 'next' ? transformRightStr : transformLeftStr );
			}

			var onEndTransitionFn = function( ev ) {
				if( support.transitions ) {
					if( ev.propertyName.indexOf( 'transform' ) === -1 ) return false;
					this.removeEventListener( transEndEventName, onEndTransitionFn );
				}

				if( self.prevItem && dir === 'next' ) {
					classie.removeClass( self.prevItem, 'show' );
				}
				else if( self.nextItem && dir === 'prev' ) {
					classie.removeClass( self.nextItem, 'show' );
				}

				if( dir === 'next' ) {
					self.prevItem = self.currentItem;
					self.currentItem = self.nextItem;
					if( incomingItem ) {
						self.nextItem = incomingItem;
					}
				}
				else {
					self.nextItem = self.currentItem;
					self.currentItem = self.prevItem;
					if( incomingItem ) {
						self.prevItem = incomingItem;
					}
				}

				self.current = dir === 'next' ? self.current + 1 : self.current - 1;
				self.isAnimating = false;
			};

			if( support.transitions ) {
				self.currentItem.addEventListener( transEndEventName, onEndTransitionFn );
			}
			else {
				onEndTransitionFn();
			}
		};

		setTimeout( slide, 25 );
	}

	CBPGridGallery.prototype._closeSlideshow = function( pos ) {
		// remove class slideshow-open from the grid gallery elem
		classie.removeClass( this.el, 'slideshow-open' );
		// remove class animatable from the slideshow grid
		classie.removeClass( this.slideshow, 'animatable' );

		var self = this,
			onEndTransitionFn = function( ev ) {
				if( support.transitions ) {
					if( ev.target.tagName.toLowerCase() !== 'ul' ) return;
					this.removeEventListener( transEndEventName, onEndTransitionFn );
				}
				// remove classes show and current from the slideshow items
				classie.removeClass( self.currentItem, 'current' );
				classie.removeClass( self.currentItem, 'show' );
				
				if( self.prevItem ) {
					classie.removeClass( self.prevItem, 'show' );
				}
				if( self.nextItem ) {
					classie.removeClass( self.nextItem, 'show' );
				}

				// also reset any transforms for all the items
				self.slideshowItems.forEach( function( item ) { setTransform( item, '' ); } );

				self.isSlideshowVisible = false;
			};

		if( support.transitions ) {
			this.el.addEventListener( transEndEventName, onEndTransitionFn );
		}
		else {
			onEndTransitionFn();
		}
	};

	CBPGridGallery.prototype._setViewportItems = function() {
		this.currentItem = null;
		this.prevItem = null;
		this.nextItem = null;

		if( this.current > 0 ) {
			this.prevItem = this.slideshowItems[ this.current - 1 ];
		}
		if( this.current < this.itemsCount - 1 ) {
			this.nextItem = this.slideshowItems[ this.current + 1 ];
		}
		this.currentItem = this.slideshowItems[ this.current ];
	}

	// taken from https://github.com/desandro/vanilla-masonry/blob/master/masonry.js by David DeSandro
	// original debounce by John Hann
	// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
	CBPGridGallery.prototype._resizeHandler = function() {
		var self = this;
		function delayed() {
			self._resize();
			self._resizeTimeout = null;
		}
		if ( this._resizeTimeout ) {
			clearTimeout( this._resizeTimeout );
		}
		this._resizeTimeout = setTimeout( delayed, 50 );
	}

	CBPGridGallery.prototype._resize = function() {
		if ( this.isSlideshowVisible ) {
			// update width value
			if( this.prevItem ) {
				var translateVal = Number( -1 * ( getViewportW() / 2 + this.prevItem.offsetWidth / 2 ) );
				setTransform( this.prevItem, support.support3d ? 'translate3d(' + translateVal + 'px, 0, -150px)' : 'translate(' + translateVal + 'px)' );
			}
			if( this.nextItem ) {
				var translateVal = Number( getViewportW() / 2 + this.nextItem.offsetWidth / 2 );
				setTransform( this.nextItem, support.support3d ? 'translate3d(' + translateVal + 'px, 0, -150px)' : 'translate(' + translateVal + 'px)' );
			}
		}
	}

	// add to global namespace
	window.CBPGridGallery = CBPGridGallery;

})( window );

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 in the loop: Get your dose of frontend twice a week

Fresh news, inspo, code demos, and UI animations—zero fluff, all quality. Make your Mondays and Thursdays creative!

Feedback 135

Comments are closed.
  1. Great plugin! The only issue is when you use it on the archive page it only works on the first article, is there a way to make the google gallery to work on all?

  2. I’m interesting in the same Acitjazz question….
    I’d like to disable slideshow popup when the window is smaller than 480px.
    Please help,
    Marco

  3. Example is fantastic, but I have a small problem. When using your script, the following error –
    TypeError: this.el is null
    Source: http: //sait1.loc/js/cbpGridGallery.js
    Line: 67
    In this line of code:
    this.grid = this.el.querySelector ('section.grid-wrap> ul.grid');
    Tell me how to fix this?
    Thanks in advance …

    • dealt with the previous problem. There was a following. When you click on the picture screen does not appear zoom image. How to solve the prompt please. Really like your gallery, you want to use this version.

  4. Great job on this one! Am using this to create a gallery for a fellow artist but weirdly enough the Large grid after clicking is not working ( on mobile (iOS…no idea about others for now. On iOs mobile it just breaks off my big image and shows no icons at all.). Also on desktop it just does not show the closing cross icon, neither the arrows while in other browsers it does. My icon paths are correct so far I checked. I used flaticon. I analysed as much as I could to find my error but am out of ideas….I tried so far:

    1.With png’s/jpg’s….same error
    2. Removing my static header/footer…error persists (please note the website is static…the person I am making it for wanted just the gallery items responsive, the rest standard…hence the ‘funny’ combi)
    3.Removing body html 100%….adding back…nothing changes

    The only thing I did was renaming demo.css in gallery.css and component.css in portfolio.css…this due to the set up of the website. But all is linked properly…all code is same as in the demo etc. Am not a java hero or jquery so maybe the problem lays there but I can’t find it. If anyone is willing to help out…I would be extremely thankful. Link to the website is nw.musestouch.com/alpenchic.html. Website is still under construction but I spended already lots of time on this issue, and wasting so much time on a gallery I can’t make it work is frustrating to say the least.

    Is there a solution to my problem and if so which one?

  5. Hi. great script. Is it possible to have this contained within a container with a set height?
    Thanks!

  6. It’s really Great Plugin…

    how can do auto slide show with play and pause buttons.

  7. Hi Awesome script! But we are facing problem in mobile and tablets when we open slideshow because all slides have large contents. Works fine on standard browsers for PC and MAC but doesn’t work on iPad and iPhone (scrolls the body instead of the slideshow). Anyone knows why?

    • I’m working on the same problem right now too. Did you figure out how to adjust the image size when it comes to the preview?

  8. Hi,
    I have tried to install the script on my Drupal site, but obviously, there is some issue, as the links don’t work while clicking on any item: http://sinyayadynya.com/en/work.
    If someone has any idea how to fix this issue, I would be very grateful. Thanks.

  9. This gallery is brilliant! But I have no idea how to get it on my package website. There’s an area to copy & paste code to embed. Any help would be very much appreciated. Thanks.

  10. Hi ,i have tried this script more than 5 times but it cause some strange problems in my code
    for example my slider arrow stop working when i use this grid

    this grid will be awesome if you fix it i loved it but feel sad for this issue
    thank you

  11. Hello,
    I have a problem with this grid. I don’t know why it’s too long to load images. Theres a possibility to pre-load images?
    Thank you

  12. Hi, I love the gallery, it’s fantastic! Just a small issue, if you can help please. Its all good until I view the zoomed images on my phone (Galaxy s2) The large images are off the edge on the right hand side of the screen, and as each new image loads, a section of the previous one jumps back and covers part of the left hand side of the new image. On desk top all good. Any assistance would be greatly apprecited. Thanks

  13. hi, i love the gallery, i have one issue with this gallery. i use gallery and isotope filter so make more useful and it works good for filter but when i click and popup box it start from first box can you help to resolve this. Thanks

    • @lia you get any solution for this problem. there is support for author here we need to make it our own way. thanks you

  14. i am not able to using this gallery more than one time in a single page of html.. please solve my problem as soon as possible…
    thankyou

    • Hello vikas, my problem is that I need to dynamically load the slide, the plugin can not be updated, please help. thanks

  15. Hello, anyone know how to solve when you have vertical images in the middle of horizontal images ?
    For size I saw you need to change .slideshow li but after that ?

    Thanks in advance !

    Cotp

  16. I made this layout for a Sharepoint App. I got issues with the effect when you click on one “field”. It doesn’t open the field. It does nothing. Can anyone help me?

  17. Hi guys. In order to use it more then 1 time on a same page use jQuery + this code
    <script> $(document).ready(function(){ var $mask = "grid-gallery"; var $targets = $('.'+ $mask); $targets.each(function (i){ $(this).attr('id', $mask+'_'+[i+1]); $targetid = $(this).attr("id"); new CBPGridGallery( document.getElementById($targetid) ); }); }); </script>
    instead of
    <script> new CBPGridGallery( document.getElementById( 'grid-gallery' ) ); </script>

  18. How to close the slideshow on click of Link ? What is the event which i need to call to close slideshow ?

  19. I’m having a similar problem. My photos are different dimensions – from landscape to portrait and square, however at the relevant point in components.css we have…

    .slideshow li { width: 660px; height: 560px; ... }

    I’ve tried replacing the values with percentages but to no avail. Is there any way of making this dynamically change to the dimensions of the photos? Even if I had to add something for every photo I wouldn’t mind. Otherwise this is just what I am looking for. Well written Mary Lou!

  20. hi, excellent gallery but it do not work on default browser on samsung galaxy. I have tried to find solution but there is nothing… Anyone help? 🙂

  21. I cannot initiate this script on a magento platform… Any ideas?

    Uncaught TypeError: $(…).CBPGridGallery is not a function

    • Change component CSS:

      .grid li { width: 33%; /* width of each item 33% = 3 per row, 25% = 4 etc etc */ float: left; cursor: pointer; }

  22. For some reason my gallery content is not centered. It is bugging me and have been combing through it and trying different things with the code to no avail. Anyone else having this problem?

  23. When I insert this into my website, I get two issues. I believe the two are linked. The first, is that all the text on my website inherits the font styles from this module. How can I make it so that this doesn’t happen? Load it as an iframe?

  24. Is there any way to address portrait images nicely? Im currently using it with imagefill.js when does center it but it still crops of 2/3rds of the image. Cheers

  25. I have more text in Slideshow, but here I couldn’t scroll that area that I changed css listed below; pls help
    .slideshow li p{
    overflow:scroll;
    display:block;
    overflow-x:hidden;
    }

  26. I coudn’t create scroll-y in the area in the slideshow. I have more text in ; now it crops the paragraph, pls help

  27. Great slideshow!
    I’ve implemented it on my site but ideally would like the slideshow to loop rather than close when you get to the next on last image or previous on first image.
    Does anyone know a way of doing this?

  28. I’ve implemented it on my site but ideally would like the slideshow to loop rather than close when you get to the next on last image or previous on first image

  29. is there an actual way to make elements in an equal heights? i do not have coding background enough.

  30. I have a problem…Console log me: Uncaught TypeError: Cannot read property ‘children’ of null at this line: this.slideshowItems = [].slice.call( this.slideshow.children );

  31. Is there any way to add a “filter” such as Filterable Product Grid?
    I’ve trying to combine both blueprints but I’m not able to do it u.u