cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

Quick-add: + add another resource

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

Quick-add: + add another resource

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

            
              <div class="expanding-grid">
	
	<ul class="links">
		<li><a href="#section1">1</a></li>
		<li><a href="#section2">2</a></li>
		<li><a href="#section3">3</a></li>
		<li><a href="#section4">4</a></li>
		<li><a href="#section5">5</a></li>
		<li><a href="#section6">6</a></li>
		<li><a href="#section7">7</a></li>
		<li><a href="#section8">8</a></li>
		<li><a href="#section9">9</a></li>
		<li><a href="#section10">10</a></li>
		<li><a href="#section11">11</a></li>
		<li><a href="#section12">12</a></li>
	</ul>

	<div id="section1" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">1</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nostrum consequatur, culpa voluptate distinctio iure! Error saepe cumque molestiae deserunt nemo autem non amet, aliquam vitae nulla sit praesentium unde iusto.</p>
		</article>
	</div>

	<div id="section2" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">2</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati veniam aliquam eos eius blanditiis, facilis minus quod nostrum. Dolores recusandae doloremque quam consequatur consequuntur accusantium quos possimus inventore ratione reiciendis!</p>
		</article>
	</div>

	<div id="section3" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">3</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nostrum consequatur, culpa voluptate distinctio iure! Error saepe cumque molestiae deserunt nemo autem non amet, aliquam vitae nulla sit praesentium unde iusto.</p>
		</article>
	</div>

	<div id="section4" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">4</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati veniam aliquam eos eius blanditiis, facilis minus quod nostrum. Dolores recusandae doloremque quam consequatur consequuntur accusantium quos possimus inventore ratione reiciendis!</p>
		</article>
	</div>

	<div id="section5" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">5</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nostrum consequatur, culpa voluptate distinctio iure! Error saepe cumque molestiae deserunt nemo autem non amet, aliquam vitae nulla sit praesentium unde iusto.</p>
		</article>
	</div>

	<div id="section6" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">6</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati veniam aliquam eos eius blanditiis, facilis minus quod nostrum. Dolores recusandae doloremque quam consequatur consequuntur accusantium quos possimus inventore ratione reiciendis!</p>
		</article>
	</div>

	<div id="section7" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">7</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nostrum consequatur, culpa voluptate distinctio iure! Error saepe cumque molestiae deserunt nemo autem non amet, aliquam vitae nulla sit praesentium unde iusto.</p>
		</article>
	</div>

	<div id="section8" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">8</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati veniam aliquam eos eius blanditiis, facilis minus quod nostrum. Dolores recusandae doloremque quam consequatur consequuntur accusantium quos possimus inventore ratione reiciendis!</p>
		</article>
	</div>
	
	<div id="section9" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">9</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nostrum consequatur, culpa voluptate distinctio iure! Error saepe cumque molestiae deserunt nemo autem non amet, aliquam vitae nulla sit praesentium unde iusto.</p>
		</article>
	</div>

	<div id="section10" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">10</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati veniam aliquam eos eius blanditiis, facilis minus quod nostrum. Dolores recusandae doloremque quam consequatur consequuntur accusantium quos possimus inventore ratione reiciendis!</p>
		</article>
	</div>

	<div id="section11" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">11</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nostrum consequatur, culpa voluptate distinctio iure! Error saepe cumque molestiae deserunt nemo autem non amet, aliquam vitae nulla sit praesentium unde iusto.</p>
		</article>
	</div>

	<div id="section12" class="expanding-container">
		<article class="hentry">
			<h1 class="entry-title">Title</h1>
			<div class="entry-image"><div class="img-placeholder">12</div></div>
			<p>Description. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati veniam aliquam eos eius blanditiis, facilis minus quod nostrum. Dolores recusandae doloremque quam consequatur consequuntur accusantium quos possimus inventore ratione reiciendis!</p>
		</article>
	</div>
</div>
            
          
!
            
              // Basic styles.

body {
	background-color: #fff;
	color: #333;
	font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
	font-size: 100%;
	font-weight: 400;
	line-height: 1.5;
	margin: 0 auto;
	max-width: 80em;
	overflow-y: scroll; // Permanent scroll bar.
	padding: 2em;
}

// Styles for our expanding grid.

$image-bg-color: orange;
$expanded-area-bg-color: #888;

.expanding-grid {
	position: relative;
	width: 100%;
	.links {
		display: block;
		margin: 0 -1em;
		overflow: hidden; // Clearfix.
		padding: 1em 0;
		> li {
			box-sizing: border-box;
			float: left;
			padding: 1em;
			a {
				background: $image-bg-color;
				color: #fff;
				display: block;
				font-size: 2em;
				line-height: 1;
				padding: 25% 1em;
				position: relative;
				text-align: center;
				text-decoration: none;
				-webkit-font-smoothing: antialiased;
				-moz-osx-font-smoothing: grayscale;
				&:hover {
					background: lighten($image-bg-color, 10%);
				}
				&.active {
					background: darken($image-bg-color, 10%);
					&:after {
						background-color: transparent;
						border-bottom: 0.375em solid $expanded-area-bg-color;
						border-left: 0.375em solid transparent;
						border-right: 0.375em solid transparent;
						bottom: -0.5em;
						content: '';
						height: 0;
						left: 50%;
						margin-left: -0.375em;
						position: absolute;
						width: 0;
					}
				}
			}
			@media only screen and (max-width: 39.99em) {
				width: 50%;
				&:nth-of-type(2n+1) {
					clear: left;
				}
			}
			@media only screen and (min-width: 40em) and (max-width: 59.99em) {
				width: percentage(1/3);
				&:nth-of-type(3n+1) {
					clear: left;
				}
			}
			@media only screen and (min-width: 60em) {
				width: percentage(1/4);
				&:nth-of-type(4n+1) {
					clear: left;
				}
			}
		}
	}

	.spacer {
		background-color: $expanded-area-bg-color;
		clear: both;
		display: block;
		margin: 0 1em;
	}

	.expanding-container {
		clear: both;
		display: none;
		overflow: hidden;
		width: 100%;
		&.expanded,
		&:target {
			display: block;
		}
	}

	.hentry {
		background: $expanded-area-bg-color;
		box-sizing: border-box;
		clear: both;
		color: #fff;
		min-height: 4em;
		overflow: hidden; // Clearfix.
		padding: 2em;
		width: 100%;
		-webkit-font-smoothing: antialiased;
		-moz-osx-font-smoothing: grayscale;
		.entry-image {
			box-sizing: border-box;
			float: right;
			margin-left: 1em;
			padding: 0.25em 0 0.52em 1em;
			text-align: center;
			width: 50%;
		}
		.entry-title {
			font-size: 1.5em;
		}
	}

	.close-button {
		background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48cGF0aCBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBkPSJNLjcuN2wxOCAxOG0tMTggMGwxOC0xOCIvPjwvc3ZnPg==) no-repeat scroll 50% 50% transparent;
		color: #fff;
		display: inline-block;
		height: 20px;
		line-height: 1;
		overflow: hidden;
		padding: 1.5em 2em;
		text-decoration: none;
		text-indent: 5em;
		white-space: nowrap;
		width: 20px;
		will-change: opacity;
		z-index: 5;
		-webkit-font-smoothing: antialiased;
		-moz-osx-font-smoothing: grayscale;
		&.active {
			transition: opacity 0.2s;
		}
		&:hover {
			opacity: 0.5;
		}
	}
}

// Style our simulated images.

.img-placeholder {
	background: $image-bg-color;
	color: #fff;
	font-size: 4em;
	font-weight: 300;
	line-height: 1;
	padding: 25% 0.25em;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}
            
          
!
            
              /**
 * jQuery Expanding Grid plugin.
 *
 * By Dan Boulet - https://danboulet.com
 */
(function ($, window, document) {

// Enable strict mode
"use strict";

/**
 * Return the last element in the current row of a grid layout.
 */
var getLastSiblingInRow = function (element) {
	var candidate = element,
			elementTop = element.offsetTop;

	// Loop through the element’s next siblings and look for the first one which
	// is positioned further down the page.
	while (candidate.nextElementSibling !== null) {
		if (candidate.nextElementSibling.offsetTop > elementTop) {
			return candidate;
		}
		candidate = candidate.nextElementSibling;
	}
	return candidate;
};

/**
 * Calculate the distance that we need to scroll the page to bring a
 * section, defined as the area between the top and bottom, into view.
 */
var calculatePageScrollDistance = function (top, bottom) {
	var windowScrollDistance = $(window).scrollTop(),
			windowHeight = $(window).height(),
			scrollDistanceToTop,
			scrollDistanceToBottom;

	// Scroll to the top of the section if the we are already scrolled past it.
	if (windowScrollDistance >= top) {
		return top - windowScrollDistance;
	}
	// Do nothing if there is enough space to show the section without having to scroll.
	else if ((windowScrollDistance + windowHeight) >= bottom) {
		return 0;
	}
	else {
		// Find the maximum distance we can scroll without passing the top of the section.
		scrollDistanceToTop = top - windowScrollDistance;
		// Find the distance we need to scroll to reveal the entire section.
		scrollDistanceToBottom = bottom - (windowScrollDistance + windowHeight);

		return Math.min(scrollDistanceToTop, scrollDistanceToBottom);
	}
};

/**
 * Create the expanding preview grid.
 */
var expandingGrid = function (context, options) {
	var defaults = {
		animationDuration: 250,
		linksSelector: '.links a',
		expandingAreaSelector: '.expanding-container',
		closeButtonMarkup: '<a href="#" class="close-button">Close</a>',
		spacerMarkup: '<span class="spacer" aria-hidden="true"/>',
		elementActiveClass: 'active',
		elementExpandedClass: 'expanded',
		onExpandBefore: false,
		onExpandAfter: false
	};

	var settings = $.extend({}, defaults, options);

	var isExpanded = false;
	var activeLink = false;
	var activeExpandedArea = false;
	var activeExpandedAreaTop = false;
	var activeExpandedAreaHeight = false;
	var lastItemInActiveRow = false;
	var activeRowChanged = false;
	var checkExpandedAreaResize = false;
	var $links = $(settings.linksSelector, context);
	var $expandingAreas = $(settings.expandingAreaSelector, context);
	var $closeButton = $(settings.closeButtonMarkup);
	var $spacer = $(settings.spacerMarkup);
	var $secondarySpacer = $spacer.clone();

	/**
	 * Scroll a section of the page into view, using animation.
	 */
	var scrollSectionIntoView = function (top, bottom, duration, callback) {
		var animate;
		var scroll = 0;
		var distance = calculatePageScrollDistance(top, bottom);
		var windowScrollDistance = $(window).scrollTop();
		var timeLeft;

		// Set default duration.
		duration = (typeof duration === 'undefined') ? settings.animationDuration : duration;
		timeLeft = duration;

		var start = new Date().getTime();
		var last = start;
		var tick = function() {
			timeLeft = Math.max(duration - (new Date() - start), 0);

			var x = (timeLeft === 0 || distance === 0) ? 0 : ((new Date() - last) / timeLeft * distance);
			var diff = (distance > 0 ? Math.min(x, distance) : Math.max(x, distance));
			distance = distance - diff;
			scroll += diff;
			window.scrollTo(0, windowScrollDistance + scroll);

			last = new Date().getTime();

			if (last - start <= duration) {
				animate = (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
			}
			else {
				if (typeof callback === 'function') {
					callback();
				}
			}
		};

		tick();
	};

	// Process the links.
	$links.each(function () {
		var $this = $(this);
		var targetId = $this.attr('href').match(/#([^\?]+)/)[1];
		var target = document.getElementById(targetId);

		if (target) {
			$this.click(function (event) {
				var clickedLink = this;
				var scrollTargetOffset;
				var closeButtonAnimationDelay;

				event.preventDefault();

				// Is this link already expanded?
				if (isExpanded && activeLink === clickedLink) {
					// Close it.
					$closeButton.click();
				}
				// Otherwise, expand it.
				else {
					$links.removeClass(settings.elementActiveClass).filter($this).addClass(settings.elementActiveClass).parent('li').each(function () {
						var lastSibling = getLastSiblingInRow(this);
						activeRowChanged = lastSibling !== lastItemInActiveRow;
						if (activeRowChanged) {
							lastItemInActiveRow = lastSibling;
						}
						// If we are changing rows, replace spacer with secondary spacer.
						if (isExpanded && activeRowChanged) {
							$secondarySpacer.height($spacer.height());
							$spacer.height(0).replaceWith($secondarySpacer);
						}
						$(lastItemInActiveRow).after($spacer);
					});
					if (isExpanded && activeRowChanged) {
						$secondarySpacer.animate({height: 0}, settings.animationDuration, function () {
							$(this).detach();
						});
						$closeButton.removeClass(settings.elementActiveClass).hide();
					}
					scrollTargetOffset = ($secondarySpacer.position().top < $spacer.position().top ? $secondarySpacer.height() : 0);
					activeExpandedAreaTop = ($spacer.position().top - scrollTargetOffset);
					$expandingAreas.removeClass(settings.elementExpandedClass).hide().filter(target).each(function () {
							var $this = $(this);
							var autoHeight = $this.height();
							var autoOuterHeight = $this.outerHeight();
							var initialHeight = (isExpanded && activeExpandedAreaHeight && (activeRowChanged === false)) ? activeExpandedAreaHeight : 0;

							stopExpandedAreaMonitor();

							$spacer.animate({height: autoHeight + 'px'}, settings.animationDuration);

							$this.css({
								height: initialHeight + 'px',
								position: 'absolute',
								left: 0,
								top: $spacer.position().top + 'px'
							}).show(0, function () {
								// Callback.
								if (typeof settings.onExpandBefore === 'function') {
									settings.onExpandBefore.call(this);
								}
							}).animate({
								height: autoHeight + 'px',
								top: activeExpandedAreaTop + 'px'
							}, settings.animationDuration, function () {
								$this.css({height: 'auto'}).addClass(settings.elementExpandedClass);

								// Set a timer to monitor changes to expanded area’s height.
								activeExpandedAreaHeight = $this.height();
								checkExpandedAreaResize = setInterval(function () {
									var activeExpandedAreaNewHeight = $this.height();
									if (activeExpandedAreaNewHeight !== activeExpandedAreaHeight) {
										activeExpandedAreaHeight = activeExpandedAreaNewHeight;
										syncExpandedAreaWithSpacer();
									}
								}, 1000);

								// Callback.
								if (typeof settings.onExpandAfter === 'function') {
									settings.onExpandAfter.call(this);
								}
							});

							// Scroll the page to bring the active link and preview into view.
							var scrollTargetTop = $(clickedLink).offset().top - scrollTargetOffset;
							var scrollTargetBottom = $this.offset().top + autoOuterHeight + 20 - scrollTargetOffset;
							scrollSectionIntoView(scrollTargetTop, scrollTargetBottom);
						});

					// Activate close button.
					closeButtonAnimationDelay = (isExpanded && activeRowChanged && ($this.parent().index() > $(activeLink).parent().index())) ? settings.animationDuration : (settings.animationDuration / 4);
					$closeButton.css({
							position: 'absolute',
							right: 0,
							top: activeExpandedAreaTop + 'px'
						}).delay(closeButtonAnimationDelay).fadeIn(settings.animationDuration, function () {
							$(this).addClass(settings.elementActiveClass);
						});

					// Set global variables.
					activeLink = this;
					activeExpandedArea = target;
					isExpanded = true;
				}
			});
		}
	});

	// Process the close button.
	$closeButton.appendTo(context).hide().click(function (event) {
		var $activeLink = $(activeLink);
		var activeLinkTopOffset = $activeLink.offset().top;
		var activeLinkBottomOffset = activeLinkTopOffset + $activeLink.outerHeight();

		event.preventDefault();

		// DOM manipulation and animations.
		$links.removeClass(settings.elementActiveClass);
		$expandingAreas.slideUp(settings.animationDuration).removeClass(settings.elementExpandedClass);
		$closeButton.removeClass('active').hide();
		$spacer.animate({height: 0}, settings.animationDuration, function () {
			$spacer.detach();
		});

		// Scroll the page to bring the active link into view.
		scrollSectionIntoView(activeLinkTopOffset, activeLinkBottomOffset);

		stopExpandedAreaMonitor();

		// Reset global variables.
		isExpanded = false;
		activeLink = false;
		activeExpandedArea = false;
	});

	/**
	 * Stop monitoring size of expanded area.
	 */
	var stopExpandedAreaMonitor = function () {
		if (checkExpandedAreaResize) {
			clearInterval(checkExpandedAreaResize);
		}
	};

	/**
	 * Match preview and spacer in height and position.
	 */
	var syncExpandedAreaWithSpacer = function () {
		if (activeExpandedArea && isExpanded) {
			$spacer.height($(activeExpandedArea).height());
			activeExpandedAreaTop = $spacer.position().top;
			$closeButton.add(activeExpandedArea).css({top: activeExpandedAreaTop + 'px'});
		}
	};

	/**
	 * Place spacer in proper position within grid.
	 */
	var positionSpacer = function () {
		var lastSibling;
		if (activeLink && lastItemInActiveRow && isExpanded) {
			// Remove spacer.
			$spacer.detach();
			lastSibling = getLastSiblingInRow($(activeLink).parent()[0]);
			// Reposition spacer, if necessary.
			if (lastItemInActiveRow !== lastSibling) {
				console.log(lastSibling);
				lastItemInActiveRow = lastSibling;
			}
			// Restore spacer.
			$(lastItemInActiveRow).after($spacer);
		}
	};

	// React to window resize.
	$(window).resize(function () {
		if (isExpanded) {
			positionSpacer();
			syncExpandedAreaWithSpacer();
		}
	});
};

// Create the jQuery plugin.
$.fn.expandingGrid = function (options) {
	return this.each(function () {
		expandingGrid(this, options);
	});
};

})(jQuery, window, document);

$(document).ready(function () {
	$('.expanding-grid').expandingGrid();
});
            
          
!
999px
Loading ..................

Console