Elastic Content Slider

A fluid content slider that will adjust in width and height depending on the size of its parent.
Elastic Content Slider

From our monthly sponsor: Automate manual QA and catch visual bugs with Percy’s all-in-one visual testing and review platform.

This Blueprint is a simple jQuery content slider. It has a sliding area for content and a tab-like navigation at the bottom. The slider is fluid, meaning that it will adjust to the parent’s container width and height. A couple of media queries show how to minimalise the look by just leaving icons for the navigation when the screen is very small. The content area will become scrollable if there isn’t enough space available. Every list item is a slide and and it has a corresponding link element in the navigation.

Note that we don’t show vendor prefixes here, but you’ll find them in the files. Also note that we use box-sizing: border-box by default for all elements.

The HTML

<div id="cbp-contentslider" class="cbp-contentslider">
	<ul>
		<li id="slide1">
			<h3 class="icon-wolf">Wolf</h3>
			<div>
				<div class="cbp-content">
					<p><!-- ... --></p>
				</div>
			</div>
		</li>
		<li id="slide2">
			<h3 class="icon-rabbit">Rabbit</h3>
			<div>
				<div class="cbp-content">
					<p>Chicory collard greens tatsoi cress bamboo shoot broccoli rabe lotus root earthnut pea arugula okra welsh onion leek shallot courgette. Chard garlic fava bean pea sprouts gram spinach plantain tomatillo. Chicory garlic black-eyed pea gourd chickpea cucumber lotus root.</p>
					<p>Daikon artichoke gumbo azuki bean bok choy avocado winter purslane gram earthnut pea broccoli salsify squash plantain wattle seed wakame broccoli rabe bamboo shoot. Zucchini lotus root azuki bean epazote dulse pumpkin rutabaga spinach. Endive mung bean gumbo maize plantain rock melon.</p>
				</div>
			</div>
		</li>
		<li id="slide3">
			<!-- ... -->
		</li>
		<li id="slide4">
			<!-- ... -->
		</li>
		<li id="slide5">
			<!-- ... -->
		</li>
	</ul>
	<nav>
		<a href="#slide1" class="icon-wolf"><span>Wolf</span></a>
		<a href="#slide2" class="icon-rabbit"><span>Rabbit</span></a>
		<a href="#slide3" class="icon-aligator"><span>Aligator</span></a>
		<a href="#slide4" class="icon-turtle"><span>Turtle</span></a>
		<a href="#slide5" class="icon-platypus"><span>Platypus</span></a>
	</nav>
</div>

The CSS

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

/* Needed for a fluid height: */
html, body, .container, .main { height: 100%;}

/* main wrapper */
.cbp-contentslider {
	width: 100%;
	height: 70%;
	margin: 1em auto;
	position: relative;
	border: 4px solid #47a3da
}

.cbp-contentslider > ul {
	list-style: none;
	height: 100%;
	width: 100%;
	overflow: hidden;
	position: relative;
	padding: 0;
	margin: 0;
}

.cbp-contentslider > ul li {
	position: absolute;
	width: 100%;
	height: 100%;
	left: 0;
	top: 0;
	padding: 1em;
	background: #fff;
}

/* Whithout JS, we use :target */
.cbp-contentslider > ul li:target {
	z-index: 100;
}

.cbp-contentslider nav {
	position: absolute;
	bottom: 0;
	left: 0;
	right: 0;
	height: 3.313em;
	z-index: 1000;
	border-top: 4px solid #47a3da;
	overflow: hidden;
}

.cbp-contentslider nav a {
	float: left;
	display: block;
	width: 20%;
	height: 100%;
	font-weight: 400;
	letter-spacing: 0.1em;
	overflow: hidden;
	color: #47a3da;
	background: #fff;
	outline: none;
	text-align: center;
	line-height: 3;
	position: relative;
	padding-left: 3.125em;
	text-transform: uppercase;
	border-right: 4px solid #47a3da;
	-webkit-transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out;
	-moz-transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out;
	transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out;
}

.cbp-contentslider nav a span {
	display: block;
}

.cbp-contentslider nav a:last-child {
	border: none;
	box-shadow: 1px 0 #47a3da; /* fills gap caused by rounding */
}

.cbp-contentslider nav a:hover {
	background-color: #47a3da;
	color: #fff;
}

.cbp-contentslider nav a.rc-active {
	background-color: #47a3da;
	color: #fff;
}

/* Iconfont for navigation and headings */
.cbp-contentslider [class^="icon-"]:before, 
.cbp-contentslider [class*=" icon-"]:before {
	font-family: 'icomoon';
	font-style: normal;
	text-align: center;
	speak: none;
	font-weight: normal;
	line-height: 2.5;
	font-size: 2em;
	position: absolute;
	left: 10%;
	top: 50%;
	margin: -1.250em 0 0 0;
	height: 2.500em;
	width: 2.500em;
	color: rgba(0,0,0,0.1);
	-webkit-font-smoothing: antialiased;
}

.cbp-contentslider .icon-wolf:before {
	content: "56";
}

.cbp-contentslider .icon-rabbit:before {
	content: "52";
}

.cbp-contentslider .icon-turtle:before {
	content: "54";
}

.cbp-contentslider .icon-platypus:before {
	content: "42";
}

.cbp-contentslider .icon-aligator:before {
	content: "41";
}

.cbp-contentslider [class^="icon-"].rc-active:before, 
.cbp-contentslider [class*=" icon-"].rc-active:before,
.cbp-contentslider nav a:hover:before {
	color: rgba(255,255,255,0.9);
}

.cbp-contentslider h3 {
	font-size: 4em;
	height: 2em;
	line-height: 1.7;
	font-weight: 300;
	margin: 0 0 0.3em;
	position: relative;
	color: #47a3da;
	text-transform: uppercase;
	text-align: right;
	letter-spacing: 0.3em;
	padding: 0 0.2em 0 0;
	border-bottom: 4px solid #47a3da;
}

.cbp-contentslider h3[class^="icon-"]:before, 
.cbp-contentslider h3[class*=" icon-"]:before {
	top: 0;
	left: 0;
	width: 2em;
	line-height: 1;
	height: 1.2em;
	margin: 0;
	color: #47a3da;
}

.cbp-contentslider li > div {
	position: absolute;
	top: 9em;
	bottom: 3.313em;
	width: 100%;
	left: 0;
	padding: 0 1em;
	overflow-x: hidden;
	overflow-y: auto;
}

.cbp-contentslider .cbp-content {
	-webkit-column-rule: 1px dashed #47a3da;
	-moz-column-rule: 1px dashed #47a3da;
	column-rule: 1px dashed #47a3da;
	-webkit-column-count: 2;
	-moz-column-count: 2;
	-o-column-count: 2;
	column-count: 2;
	-webkit-column-gap: 1em;
	-moz-column-gap: 1em;
	-o-column-gap: 1em;
	column-gap: 1em;
	vertical-align: top;	
	padding: 1em 0;
}

.cbp-contentslider p {
	color: #47a3da;
	padding: 0 0.5em 0.4em;
	margin: 0;
	font-size: 1.2em;
	font-weight: 300;
	text-align: justify;
	line-height: 1.6;
}

/* Media queries */

@media screen and (max-width: 70em) { 
	.cbp-contentslider p {
		font-size: 100%;
	}
}

@media screen and (max-width: 67.75em) {

	.cbp-contentslider { font-size: 85%; }

	.cbp-contentslider nav a[class^="icon-"]:before, 
	.cbp-contentslider nav a[class*=" icon-"]:before {
		left: 50%;
		margin-left: -1.250em;
	}

	.cbp-contentslider nav a span {
		display: none;
	}
}

@media screen and (max-width: 43em) {

	.cbp-contentslider h3 {
		font-size: 2em;
	}

	.cbp-contentslider .cbp-content {
		-webkit-column-count: 1;
		-moz-column-count: 1;
		-o-column-count: 1;
		column-count: 1;
	}

	.cbp-contentslider li > div {
		top: 5em;
	}

}

@media screen and (max-width: 25em) { 
	.cbp-contentslider nav a { padding: 0;}
	.cbp-contentslider h3[class^="icon-"]:before, 
	.cbp-contentslider h3[class*=" icon-"]:before { display: none;}
}

The JavaScript

;( function( $, window, undefined ) {

	'use strict';

	// global
	var Modernizr = window.Modernizr;

	$.CBPContentSlider = function( options, element ) {
		this.$el = $( element );
		this._init( options );
	};

	// the options
	$.CBPContentSlider.defaults = {
		// default transition speed (ms)
		speed : 500,
		// default transition easing
		easing : 'ease-in-out',
		// current item´s index
		current : 0
	};

	$.CBPContentSlider.prototype = {
		_init : function( options ) {

			// options
			this.options = $.extend( true, {}, $.CBPContentSlider.defaults, options );
			// the items
			this.$items = this.$el.find( 'ul > li' ).hide();
			// the tabs
			this.$tabs = this.$el.find( 'nav > a' );
			// total tabs
			var tabsCount = this.$tabs.length;
			// set each tab width
			this.$tabs.css( 'width', 100 / tabsCount + '%' );
			// current and old item´s index
			this.current = this.options.current;
			this.old = 0;
			// check if the items are currently moving
			this.isAnimating = false;
			// support for CSS Transitions
			this.support = Modernizr.csstransitions;
			// transition end event name
			var transEndEventNames = {
				'WebkitTransition' : 'webkitTransitionEnd',
				'MozTransition' : 'transitionend',
				'OTransition' : 'oTransitionEnd',
				'msTransition' : 'MSTransitionEnd',
				'transition' : 'transitionend'
			};
			this.transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ] + '.cbpContentSlider';
			// set the transition to the items
			if( this.support ) {
				this.$items.css( 'transition', 'left ' + this.options.speed + 'ms ' + this.options.easing );
			}
			// update current tab
			this._updateTabs();
			// show current item
			this.$items.eq( this.current ).show();
			// initialize/bind the events to the tabs
			this._initEvents();

		},
		_updateTabs : function() {
			this.$tabs.eq( this.old ).removeClass( 'rc-active' ).end().eq( this.current ).addClass( 'rc-active' );
		},
		_initEvents : function() {

			var self = this;
			this.$tabs.on( 'click.cbpContentSlider', function( event ) {
			
				var idx = $( this ).index();
				
				if( idx !== self.current && !self.isAnimating ) {
					
					self.isAnimating = true;

					var direction = idx > self.current ? 'right' : 'left',
						$oldItem = self.$items.eq( self.current ),
						$newItem = self.$items.eq( idx );
					
					// update current and old value
					self.old = self.current;
					self.current = idx;

					// apply initial style..
					if( self.support ) {
						// translate might be more efficient here. Left out because of a rounding and rendering problem in Chrome (Version 24.0.1312.52)
						$newItem.css( 'left', direction === 'right' ? '100%' : '-100%' );
					}
					$newItem.show();

					// ..and bind the transitionend event
					var transitionendfn = function() {
						$oldItem.off( self.transEndEventName ).hide();
						self.isAnimating = false;
					};

					if( self.support ) {
						$oldItem.on( self.transEndEventName, transitionendfn );
					}
					else {
						transitionendfn.call();
					}
					
					// apply final style
					if( self.support ) {
						setTimeout( function() {
							// translate might be more efficient here. Left out because of a rounding and rendering problem in Chrome (Version 24.0.1312.52)
							$oldItem.css( 'left', direction === 'right' ? '-100%' : '100%' );
							$newItem.css( 'left', '0%' );
						}, 25 );
					}

					// update current tab
					self._updateTabs();

				}

				event.preventDefault();

			} );

		},
		destroy : function() {
			if( this.support ) {
				this.$items.css( 'transition', 'none' );
			}
			this.$items.css( 'left', 0 ).show();
			this.$tabs.off( '.cbpContentSlider' ).removeClass( 'rc-active' );
		}
	};

	var logError = function( message ) {
		if ( window.console ) {
			window.console.error( message );
		}
	};

	$.fn.cbpContentSlider = function( options ) {
		if ( typeof options === 'string' ) {
			var args = Array.prototype.slice.call( arguments, 1 );
			this.each(function() {
				var instance = $.data( this, 'cbpContentSlider' );
				if ( !instance ) {
					logError( "cannot call methods on cbpContentSlider prior to initialization; " +
					"attempted to call method '" + options + "'" );
					return;
				}
				if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
					logError( "no such method '" + options + "' for cbpContentSlider instance" );
					return;
				}
				instance[ options ].apply( instance, args );
			});
		} 
		else {
			this.each(function() {	
				var instance = $.data( this, 'cbpContentSlider' );
				if ( instance ) {
					instance._init();
				}
				else {
					instance = $.data( this, 'cbpContentSlider', new $.CBPContentSlider( options, this ) );
				}
			});
		}
		return this;
	};

} )( jQuery, window );

Tagged with:

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

http://www.codrops.com

Receive our bi-weekly Collective or official newsletter right in your inbox.

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.

Feedback 60

Comments are closed.
  1. Hmm very interesting and insightful.

    I would like to suggest another tutorial though, a three column (or 1+n columns) elastic list slider that has on each column an image and text. How can this be implemented and be responsive?

  2. This component is very useful, though I think it’s better if on smaller screens the tabs are floated to the right aligned vertically on each other !!

  3. Hi there! i am new in web design, i was wondering how can i change the icons? for sure its something easy but i don know how to do it, help me please!

  4. interesting use of font dingbats as icons

    where do the values come from?
    i.e. content: “\56”;

  5. is there a function that calls directly a tab?

    Like

    $cbpContentSlider.goToTab(‘3’);

    ?

  6. I am working on a website using this blueprint and it is working very nicely – just what I needed. I have one question, however – a number of the slides have a links on them, and it would be ideal if after visiting a given link the browser would return to the same slide if the back button was pressed. When I navigate back with the back button now, the browser always resets to the first slide. I there a way around this?

  7. Greetings from argentina!
    hello! Nice tutorial. It’really good!
    But how can i change the icons!? I like animals 🙂 but i need others!
    I noticed tha you used iconmoon icons! How can i use other icons from there?

  8. Hello, i need to add a link to open a different page but neither “” tags or input buttons are not working when i put into
    How is it posibble?
    Can you help me please?

    Thanks again for the tutorial!

  9. Hi from Uruguay! Great site! I can´t see scrollbars when viewing in a smartphone…. How can I solve this? Thanks

    • Yes, I have the same problem (almost the same)… When I try my custom page offline it works just fine (on IE10), but when I set it online (calling the page with an PHP include), the script doesn’t work well on IE10!

      Please help!