Pen Settings

HTML

CSS

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.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

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.

+ add another resource

Behavior

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.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!-- For a full explanation of this code, please refer to the blogpost at http://www.bram.us/2014/01/05/css-animated-content-switching/ -->

<h1>CSS Animated Content Switching <em>(think tabs/panels)</em>, using CSS3 Transitions</h1>

<p>For a full explanation of this code, please refer to the blogpost at <a href="http://www.bram.us/2014/01/05/css-animated-content-switching/">http://www.bram.us/2014/01/05/css-animated-content-switching/</a></p>

<h2>1. Horizontal slide (enter and exit animations running sequential)</h2>
<ul class="panelNav" data-panelwrapper="panelWrapper1">
  <li><a href="#panelA1">A</a></li>
  <li><a href="#panelB1">B</a></li>
  <li><a href="#panelC1">C</a></li>
</ul>
<div class="panelWrapper" id="panelWrapper1" data-enter="slideright" data-exit="slideleft" data-sequential="yes">
  <div class="panel current" id="panelA1">A</div>
  <div class="panel" id="panelB1">B</div>
  <div class="panel" id="panelC1">C</div>
</div>


<h2>2. Horizontal slide (enter and exit animations running concurrently)</h2>
<ul class="panelNav" data-panelwrapper="panelWrapper5">
  <li><a href="#panelA5">A</a></li>
  <li><a href="#panelB5">B</a></li>
  <li><a href="#panelC5">C</a></li>
</ul>
<div class="panelWrapper" id="panelWrapper5" data-enter="slideright" data-exit="slideright">
  <div class="panel current" id="panelA5">A</div>
  <div class="panel" id="panelB5">B</div>
  <div class="panel" id="panelC5">C</div>
</div>

<h2>3. Vertical Slide (enter and exit animations running sequential), with fade</h2>
<ul class="panelNav" data-panelwrapper="panelWrapper2">
  <li><a href="#panelA2">A</a></li>
  <li><a href="#panelB2">B</a></li>
  <li><a href="#panelC2">C</a></li>
</ul>
<div class="panelWrapper" id="panelWrapper2" data-enter="slideup fade" data-exit="slidedown fade" data-sequential="yes">
  <div class="panel current" id="panelA2">A</div>
  <div class="panel" id="panelB2">B</div>
  <div class="panel" id="panelC2">C</div>
</div>


<h2>4. Scaledown and up (enter and exit animations running concurrently)</h2>
<ul class="panelNav" data-panelwrapper="panelWrapper3">
  <li><a href="#panelA3">A</a></li>
  <li><a href="#panelB3">B</a></li>
  <li><a href="#panelC3">C</a></li>
</ul>
<div class="panelWrapper" id="panelWrapper3" data-enter="scaleup" data-exit="scaledown">
  <div class="panel current" id="panelA3">A</div>
  <div class="panel" id="panelB3">B</div>
  <div class="panel" id="panelC3">C</div>
</div>

<h2>5. Scaledown and up (enter and exit animations running sequential)</h2>
<ul class="panelNav" data-panelwrapper="panelWrapper4">
  <li><a href="#panelA4">A</a></li>
  <li><a href="#panelB4">B</a></li>
  <li><a href="#panelC4">C</a></li>
</ul>
<div class="panelWrapper" id="panelWrapper4" data-enter="scaleup" data-exit="scaledown" data-sequential="yes">
  <div class="panel current" id="panelA4">A</div>
  <div class="panel" id="panelB4">B</div>
  <div class="panel" id="panelC4">C</div>
</div>



<h2>6. Scaledown and up (enter and exit animations running sequential), with fade</h2>
<ul class="panelNav" data-panelwrapper="panelWrapper6">
  <li><a href="#panelA6">A</a></li>
  <li><a href="#panelB6">B</a></li>
  <li><a href="#panelC6">C</a></li>
</ul>
<div class="panelWrapper" id="panelWrapper6" data-enter="scaleup fade" data-exit="scaledown fade" data-sequential="yes">
  <div class="panel current" id="panelA6">A</div>
  <div class="panel" id="panelB6">B</div>
  <div class="panel" id="panelC6">C</div>
</div>



<h2>7. Per panel different animations</h2>
<ul class="panelNav" data-panelwrapper="panelWrapper7">
  <li><a href="#panelA7">A</a></li>
  <li><a href="#panelB7">B</a></li>
  <li><a href="#panelC7">C</a></li>
</ul>
<div class="panelWrapper" id="panelWrapper7" data-enter="slideleft" data-exit="scaledown fade" data-sequential="yes">
  <div class="panel current" id="panelA7" data-enter="slideright">A</div>
  <div class="panel" id="panelB7" data-exit="scaleup">B</div>
  <div class="panel" id="panelC7" data-enter="slideup" data-exit="slidedown">C</div>
</div>

<h2>8. Any combo you like &hellip; :-)</h2>


<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>  
              
            
!

CSS

              
                /* For a full explanation of this code, please refer to the blogpost at http://www.bram.us/2014/01/05/css-animated-content-switching/ */

body {
  background: #fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAQMAAABJtOi3AAAABlBMVEX4+Pj09PQf/c7fAAAAGklEQVR4Xq3MIQEAAADDIPqX/kvMIMEWEm8O7b0/wewc/NcAAAAASUVORK5CYII=) repeat;
  font-family: Georgia;
}

/* Panel Navigation */
.panelNav {
  list-style: none;
  margin: 0; padding: 0;
}

.panelNav li {
  display: inline-block;
  padding: 0 10px;
}


/*
PanelWrapper and Basic Panel styling.
Make sure to set `overflow:hidden` onto the wrapper. */
.panelWrapper {
  width: 400px;
  height: 200px;
  position: relative;
  overflow: hidden;
  border: 1px solid #464646;
}

.panel {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  
  text-align: center;
  line-height: 200px;
  font-size: 100px;
  color: #FFF;
  
  /*
  Prevent flickering of the screen when starting an animation
  @url http://blog.teamtreehouse.com/increase-your-sites-performance-with-hardware-accelerated-css
  */
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

/* Panel colors */
#panelA1, #panelA2, #panelA3, #panelA4, #panelA5, #panelA6, #panelA7 { background: #F00; }
#panelB1, #panelB2, #panelB3, #panelB4, #panelB5, #panelB6, #panelB7   { background: #0F0; }
#panelC1, #panelC2, #panelC3, #panelC4, #panelC5, #panelC6, #panelC7   { background: #00F; }


/*
A panel can be in one of the following states:
- [default],
- current (= the current active panel),
- exit (= the panel to slide/fade out),
- enter (= the panel to slide/fade in)

All [default] panels are hidden.
Above that we make sure the current panel is on top of the other panels
*/
.panel { z-index: -1; display: none; }
.panel.current, .panel.exit { z-index: 2; display: block; }
.panel.enter { display: block; }


/*
The key aspect in this example is the `.animating` class on the wrapper: only if the wrapper has the .animating class, CSS properties are transitioned.

This allows us to set starting positions without any transition, and then - once `.animating` is in place transition to the end position.
*/
.animating .exit,
.animating .enter {
  -webkit-transition: all .3s ease-in-out;
  -ms-transition: all .3s ease-in-out;
  transition: all .3s ease-in-out;
}

/*
What follows now are all transition start and end states. Names are re-used for both entering and exiting effects.

Note that some effects are aliases. Entering stage left (= from the left hand side of "the stage" (wrapper)) is the same as sliding in to the right.
*/


/* SLIDE OUT TRANSITIONS */
.exit.stageback,
.exit.stagetop,
.exit.slideup {
  -webkit-transform: translateY(0);
  -ms-transform: translateY(0);
  transform: translateY(0);
}
.animating .exit.stageback,
.animating .exit.stagetop,
.animating .exit.slideup {
  	-webkit-transform: translateY(-100%);
  -ms-transform: translateY(-100%);
  transform: translateY(-100%);
}

.exit.stagefront,
.exit.stagebottom,
.exit.slidedown {
  -webkit-transform: translateY(0);
  -ms-transform: translateY(0);
  transform: translateY(0);
}
.animating .exit.stagefront,
.animating .exit.stagebottom,
.animating .exit.slidedown {
  	-webkit-transform: translateY(100%);
  -ms-transform: translateY(100%);
  transform: translateY(100%);
}

.exit.stageleft,
.exit.slideleft {
  -webkit-transform: translateX(0);
  -ms-transform: translateX(0);
  transform: translateX(0);
}
.animating .exit.stageleft,
.animating .exit.slideleft {
  -webkit-transform: translateX(-100%);
  -ms-transform: translateX(-100%);
  transform: translateX(-100%);
}

.exit.stageright,
.exit.slideright {
  -webkit-transform: translateX(0);
  -ms-transform: translateX(0);
  transform: translateX(0);
}
.animating .exit.stageright,
.animating .exit.slideright {
  -webkit-transform: translateX(100%);
  -ms-transform: translateX(100%);
  transform: translateX(100%);
}


/* SLIDE IN TRANSITIONS */
.enter.stageback,
.enter.stagetop,
.enter.slidedown {
  -webkit-transform: translateY(-100%);
  -ms-transform: translateY(-100%);
  transform: translateY(-100%);
}
.animating .enter.stageback,
.animating .enter.stagetop,
.animating .enter.slidedown {
  -webkit-transform: translateY(0);
  -ms-transform: translateY(0);
  transform: translateY(0);
}

.enter.stagefront,
.enter.stagebottom,
.enter.slideup {
  -webkit-transform: translateY(100%);
  -ms-transform: translateY(100%);
  transform: translateY(100%);
}
.animating .enter.stagefront,
.animating .enter.stagebottom,
.animating .enter.slideup {
  -webkit-transform: translateY(0);
  -ms-transform: translateY(0);
  transform: translateY(0);
}

.enter.stageleft,
.enter.slideright {
  -webkit-transform: translateX(-100%);
  -ms-transform: translateX(-100%);
  transform: translateX(-100%);
}
.animating .enter.stageleft,
.animating .enter.slideright {
  -webkit-transform: translateX(0%);
  -ms-transform: translateX(0%);
  transform: translateX(0%);
}

.enter.stageright,
.enter.slideleft {
  -webkit-transform: translateX(100%);
  -ms-transform: translateX(100%);
  transform: translateX(100%);
}
.animating .enter.stageright,
.animating .enter.slideleft {
  -webkit-transform: translateX(0%);
  -ms-transform: translateX(0%);
  transform: translateX(0%);
}



/* SCALE TRANSITIONS, BEST TO COBMINE WITH FADE/OPACITY */
.enter.scaleup {
  -webkit-transform: scale(0.1);
  -ms-transform: scale(0.1);
  transform: scale(0.1);
}
.animating .enter.scaleup {
  	-webkit-transform: scale(1);
  -ms-transform: scale(1);
  transform: scale(1);
}

.exit.scaleup {
  -webkit-transform: scale(1);
  -ms-transform: scale(1);
  transform: scale(1);
}
.animating .exit.scaleup {
  	-webkit-transform: scale(1.9);
  -ms-transform: scale(1.9);
  transform: scale(1.9);
  opacity: 0;
}

.enter.scaledown {
  -webkit-transform: scale(1.9);
  -ms-transform: scale(1.9);
  transform: scale(1.9);
}
.animating .enter.scaledown {
  	-webkit-transform: scale(1);
  -ms-transform: scale(1);
  transform: scale(1);
}

.exit.scaledown {
  -webkit-transform: scale(1);
  -ms-transform: scale(1);
  transform: scale(1);
}
.animating .exit.scaledown {
	  -webkit-transform: scale(0.1);
  -ms-transform: scale(0.1);
  transform: scale(0.1);
}


/* OPACITY/FADE TRANSITIONS */
.enter.fade {
  opacity: 0;
}
.animating .enter.fade {
  opacity: 1;
}
.exit.fade {
  opacity: 1;
}
.animating .exit.fade {
  opacity: 0;
}


/* Sequential animations: delay the animation of the entering panel */
.animating[data-concurrent="no"] .panel.enter,
.animating[data-sequential="yes"] .panel.enter{
  -webkit-transition-delay: .3s !important;
  -ms-transition-delay: .3s !important;
  transition-delay: .3s !important;
}
              
            
!

JS

              
                // For a full explanation of this code, please refer to the blogpost at http://www.bram.us/2014/01/05/css-animated-content-switching/
jQuery(function($) {

	var startAnimation = function($panelContainer) {

		// Set .animating class (which triggers the CSS to start the animation)
		$panelContainer.addClass('animating');

	};

	var updatePanelNav = function($panelNav, $panelContainer, $panelToSlideIn, numPanels) {

		// Find index of $panelToSlideIn in the $panelContainer
		var idx = $panelToSlideIn.index('#' + $panelContainer.attr('id') + ' > .panel');

		if (idx === 0) {
			$panelNav.find('a[href="#prev"]').addClass('inactive');
		} else {
			$panelNav.find('a[href="#prev"]').removeClass('inactive');
		}

		if (idx == numPanels-1) {
			$panelNav.find('a[href="#next"]').addClass('inactive');
		} else {
			$panelNav.find('a[href="#next"]').removeClass('inactive');
		}

	};

	var stopAnimation = function($panelContainer, $panels, $panelToSlideIn) {

		// Fix for browsers who fire this handler for both prefixed and unprefixed events (looking at you, Chrome): remove any listeners
		// $panelToSlideIn.off('transitionend webkitTransitionEnd	MSTransitionEnd');

		// An optional extra class (or set of classes) that might be set on the panels
		var extraClass = $panelContainer.data('extraclass') || '';

		// set slid in panel as the current one
		$panelToSlideIn.removeClass().addClass('panel current ' + extraClass);

		// reset all other panels
		$panels.filter(':not(#' + $panelToSlideIn.attr('id')	+ ')').removeClass().addClass('panel ' + extraClass);

		// Allow a new animation
		$panelContainer.removeClass('animating');

	};

	var setExitPanel = function($panelToSlideOut, exitAnimation) {

		$panelToSlideOut
			.addClass('exit ' + exitAnimation)
			.removeClass('current');

	};

	var setEnterPanel = function($panelContainer, $panels, $panelToSlideIn, enterAnimation) {

		$panelToSlideIn

			// Slide it into view
			.addClass('enter ' + enterAnimation)

			// When sliding in is done,
			// .one('transitionend webkitTransitionEnd MSTransitionEnd', function(e) {

				// moved to a setTimeout in the click handling logic itself because Firefox doesn't always fire this!!!
				// stopAnimation($panelContainer, $panels, $panelToSlideIn)

			// })
			;

	};

	$('.panelNav').each(function(i) {

		var $panelNav = $(this),
			$panelNavItems = $panelNav.find('a'),
			$panelContainer = $('#' + $panelNav.data('panelwrapper')),
			$panels = $panelContainer.find('> .panel'),
			numPanels = $panels.length,
			animationDuration = ($panelContainer.data('sequential') == 'yes') ? 600 : 300;


		if (numPanels > 1) {
			$panelNav.find('a[href="#next"]').removeClass('inactive');
		}

		// When clicking on any of the panel navigation items
		$panelNavItems.on('click', function(e) {

			// Don't follow the link
			e.preventDefault();

			// Local vars
			var $panelToSlideIn, $panelToSlideOut, enterAnimation, exitAnimation;

			// Don't do anything if we are currently animating
			if ($panelContainer.is('.animating')) return false;

			// Define the panel to slideOut
			$panelToSlideOut = $panels.filter('.current');

			// Define the the panel to slide in
			if ($(this).attr('href') == '#next') {
				$panelToSlideIn = $panels.filter('.current').next('.panel');
			} else if ($(this).attr('href') == '#prev') {
				$panelToSlideIn = $panels.filter('.current').prev('.panel');
			} else {
				$panelToSlideIn = /* $panels.filter('#' + */ $($(this).attr('href')) /* .attr('id')) */;
			}

			// Don't do anything if there is no new panel
			if (!$panelToSlideIn.size()) return;

			// Don't do anything if the new panel equals the current panel
			if ($panelToSlideOut.attr('id') == $panelToSlideIn.attr('id')) return;

			// Define animations to use
			enterAnimation = $panelToSlideIn.data('enter') || $panelContainer.data('enter');
			exitAnimation = $panelToSlideOut.data('exit') || $panelContainer.data('exit');

			// Set the exit panel
			setExitPanel($panelToSlideOut, exitAnimation);

			// Set the enter panel
			setEnterPanel($panelContainer, $panels, $panelToSlideIn, enterAnimation);

			// Start the animation (immediately)
			// @note: using a setTimeout because "it solves everything", dixit @rem
			setTimeout(function() {
				startAnimation($panelContainer);
			}, 0);

			// Update next/prev buttons
			updatePanelNav($panelNav, $panelContainer, $panelToSlideIn, numPanels);

			// Stop the animation after a while
			setTimeout(function() {
				stopAnimation($panelContainer, $panels, $panelToSlideIn);
			}, animationDuration);

		});


	});


});
              
            
!
999px

Console