Slideshow with jmpress.js

Today we will create a slideshow using jmpress.js. The jQuery plugin that is based on impress.js will allow us to use some interesting 3D effects for the slides.

Slideshow with Jmpress

You have for sure already seen impress.js, a really great JavaScript library for creating extraordinary 3D presentations. The jQuery port jmpress.js let’s you use this library as a jQuery plugin with some added options. We want to show you today how to use this great plugin to create a responsive slideshow with 3D effects.

The icons used in the demo is by Artcore Illustration and they are licensed under the
Creative Commons BY-NC-ND 3.0 license.

So, let’s start!

The Markup

We will have a main container which is a section with the class jms-slideshow. Inside, we’ll have sevaral divisions with the class step. These will be our single slides. Each step or slide will get a data-color class for it’s background color and some data attributes of jmpress.js. You can find all (inline) options here: jmpress.js Documentation – Options. We’ll use some attributes in order to define the position and rotation of the slides in 3D space:

<section id="jms-slideshow" class="jms-slideshow">

	<div class="step" data-color="color-1">
		<div class="jms-content">
			<h3>Some headline</h3>
			<p>Some text</p>
			<a class="jms-link" href="#">Read more</a>
		</div>
		<img src="images/1.png" />
	</div>
	
	<div class="step" data-color="color-2" data-y="500" data-scale="0.4" data-rotate-x="30">
		<!-- ... -->
	</div>
	
	<!-- ... -->
	
</section>

Let’s take care of the style.

The CSS

Since we want to make the slideshow responsive, we will give the main container a percentage width, with some min and max values:

.jms-slideshow {
	position: relative;
	width: 80%;
	max-width: 1400px;
	min-width: 640px;
	margin: 20px auto;
	height: 460px;
}

The next wrapper is dynamically added, and this will be the visible slideshow wrapper:

.jms-wrapper {
	width: auto;
	min-width: 600px;
	height: 440px;
	background-color: #fff;
	box-shadow: 0 2px 6px rgba(0, 0, 0, .2);
	-webkit-background-clip: padding;
	-moz-background-clip: padding;     
	background-clip: padding-box;
	border: 10px solid #fff;
	border: 10px solid rgba(255, 255, 255, 0.9);
	outline: none;
	transition: background-color 1s linear;
}

The background color classes will be applied to the previous wrapper. The class is defined in the data atrribute data-color in each step. This gives us the possibility to add a background color for each slide and change it with a transition. (The duration of the transition will be re-defined in the JavaScript.)

.color-1 {
	background-color: #E3D8FF;
	background-color: rgba(227, 216, 268, 1);
}
.color-2 {
	background-color: #EBBBBC;
	background-color: rgba(235, 187, 188, 1);
}
.color-3 {
	background-color: #EED9C0;
	background-color: rgba(238, 217, 192, 1);
}
.color-4 {
	background-color: #DFEBB1;
	background-color: rgba(223, 235, 177, 1);
}
.color-5{
	background-color: #C1E6E5;
	background-color: rgba(193, 230, 229, 1);
}

The steps will have the following style:

.step {	
	width: 900px;
    height: 420px;
	display: block;
	transition: opacity 1s;
}
.step:not(.active) {
	opacity: 0;
}

Inactive steps will have 0 opacity. When the slides are moved, the opacity will be set to 1.

The inner parts of the slides will have the following style:

.jms-content{
	margin: 0px 370px 0px 20px;
	position: relative;
	clear: both;
}
.step h3{
	color: #fff;
	font-size: 52px;
	font-weight: bold;
	text-shadow: 1px 1px 1px rgba(0,0,0,0.1);
	margin: 0;
	padding: 60px 0 10px 0;
}
.step p {
	color: #fff;
	text-shadow: 1px 1px 1px rgba(0,0,0,0.1);
	font-size: 34px;
	font-weight: normal;
	position: relative;
	margin: 0;
}

The “read more” link will have a little transition by itself: once a step becomes active, it will move up wile fading in:

a.jms-link{
	color: #fff;
	text-transform: uppercase;
	background: linear-gradient(top, #969696 0%,#727272 100%); 
	padding: 8px 15px;
	display: inline-block;
	font-size: 16px;
	font-weight: bold;
	color: #fff;
	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
	box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
	border: 1px solid #444;
	border-radius: 4px;
	opacity: 1;
	margin-top: 40px;
	clear: both;
	transition: all 0.4s ease-in-out 1s;
}
.step:not(.active) a.jms-link{
	opacity: 0;
	margin-top: 80px;
}

The image will be positioned absolutely on the right side of each slide:

.step img{
	position: absolute;
	right: 0px;
	top: 30px;
}

The navigation dots will positioned at the bottom:

.jms-dots{
	width: 100%;
	position: absolute;
	text-align: center;
	left: 0px;
	bottom: 20px;
	z-index: 2000;
	user-select: none;
}

With “user-select: none” the text of an element and its sub-elements will appear as if they can’t be selected.
The span will be a dark little dot:

.jms-dots span{
	display: inline-block;
	position: relative;
	width: 12px;
	height: 12px;
	border-radius: 50%;
	background: #777;
	margin: 3px;
	cursor: pointer;
	box-shadow: 
		1px 1px 1px rgba(0,0,0,0.1) inset, 
		1px 1px 1px rgba(255,255,255,0.3);
}

And we’ll style a pseudo-element to look like a little white dot:

.jms-dots span.jms-dots-current:after{
	content: '';
	width: 8px;
	height: 8px;
	position: absolute;
	top: 2px;
	left: 2px;
	border-radius: 50%;
	background: linear-gradient(top, #ffffff 0%,#f6f6f6 47%,#ededed 100%);
}

The arrow navigation spans will be positioned on the left and on the right side of the slideshow. We’ll use background images for the arrows:

.jms-arrows{
	user-select: none;
}
.jms-arrows span{
	position: absolute;
	top: 50%;
	margin-top: -40px;
	height: 80px;
	width: 30px;
	cursor: pointer;
	z-index: 2000;
	box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.1);
	border-radius: 3px;
}
.jms-arrows span.jms-arrows-prev{
	background: #fff url(../images/arrow_left.png) no-repeat 50% 50%;
	left: -10px;
}
.jms-arrows span.jms-arrows-next{
	background: #fff url(../images/arrow_right.png) no-repeat 50% 50%;
	right: -10px;
}

Now we have styled the slideshow. Let’s move on to the JavaScript!

The JavaScript

We will be using the jmpress.js plugin to create our slideshow. Although you can make use of a lot of its functionality, we will just use the necessary parts to build our script. You can read more about the possibilities and options that jmpress.js offers here.

We will create a jQuery plugin for the slideshow. We can call the plugin like this:

	
$( '#jms-slider' ).jmslideshow();

The options for the jmpress plugin are defined as default options in our plugin (note that you can specify more than the ones listed):


jmpressOpts	: {
	// set the viewport
	viewPort 		: {
		height	: 400,
		width	: 1300,
		maxScale: 1
	},
	fullscreen		: false,
	hash			: { use : false },
	mouse			: { clickSelects : false },
	keyboard		: { use : false },
	animation		: { transitionDuration : '1s' }
},

You can either change them inside the slideshow plugin, or pass a specific value when you initialize the plugin. As an example:


// specify the jmpress options
var jmpressOpts	= {
	animation		: { transitionDuration : '0.8s' }
};

// call the jmslideshow plugin
$( '#jms-slideshow' ).jmslideshow( $.extend( true, { jmpressOpts : jmpressOpts }, {
	autoplay	: true,
	bgColorSpeed: '0.8s',
	arrows		: false
}));

The following are the set of available options that are available for the slideshow plugin:


$.JMSlideshow.defaults 		= {
	// options for the jmpress plugin.
	// you can add more options...
	jmpressOpts	: {
		// set the viewport
		viewPort 		: {
			height	: 400,
			width	: 1300,
			maxScale: 1
		},
		fullscreen		: false,
		hash			: { use : false },
		mouse			: { clickSelects : false },
		keyboard		: { use : false },
		animation		: { transitionDuration : '1s' }
	},
	// for this specific plugin we will have the following options:
	// shows/hides navigation arrows
	arrows		: true,
	// shows/hides navigation dots/pages
	dots		: true,
	// each step's bgcolor transition speed
	bgColorSpeed: '1s',
	// slideshow on / off
	autoplay	: false,
	// time between transitions for the slideshow
	interval	: 3500
};

Once the slideshow plugin is called, the first function to be executed is the init function:


_init : function( options ) {
			
	this.options 		= $.extend( true, {}, $.JMSlideshow.defaults, options );
	
	// the slides
	this.$slides		= $('#jms-slider').children('div');
	// total number of slides
	this.slidesCount	= this.$slides.length;
	// step's bgcolor
	this.colors			= $.map( this.$slides, function( el, i ) { return $( el ).data( 'color' ); } ).join( ' ' );
	// build the necessary structure to run jmpress
	this._layout();
	// initialize the jmpress plugin
	this._initImpress();
	// if support (function implemented in jmpress plugin)
	if( this.support ) {
	
		// load some events
		this._loadEvents();
		// if autoplay is true start the slideshow
		if( this.options.autoplay ) {
		
			this._startSlideshow();
		
		}
		
	}
	
},

In the _layout function we are building the necessary structure for the jmpress plugin. Also, we will be adding the navigation arrows / dots in case these are set to true in the options.


_layout				: function() {
			
	// adds a specific class to each one of the steps
	this.$slides.each( function( i ) {
	
		$(this).addClass( 'jmstep' + ( i + 1 ) );
	
	} );
	
	// wrap the slides. This wrapper will be the element on which we will call the jmpress plugin
	this.$jmsWrapper	= this.$slides.wrapAll( '<div class="jms-wrapper"/>' ).parent();
	
	// transition speed for the wrapper bgcolor 
	this.$jmsWrapper.css( {
		'-webkit-transition-duration' 	: this.options.bgColorSpeed,
		'-moz-transition-duration' 		: this.options.bgColorSpeed,
		'-ms-transition-duration' 		: this.options.bgColorSpeed,
		'-o-transition-duration' 		: this.options.bgColorSpeed,
		'transition-duration' 			: this.options.bgColorSpeed
	} );
	
	// add navigation arrows
	if( this.options.arrows ) {
	
		this.$arrows	= $( '<nav class="jms-arrows"/>' );
		
		if( this.slidesCount > 1 ) {
		
			this.$arrowPrev	= $( '<span class="jms-arrows-prev"/>' ).appendTo( this.$arrows );
			this.$arrowNext	= $( '<span class="jms-arrows-next"/>' ).appendTo( this.$arrows );
			
		}

		this.$el.append( this.$arrows )
	
	}
	
	// add navigation dots
	if( this.options.dots ) {
	
		this.$dots		= $( '<nav class="jms-dots"/>' );
		
		for( var i = this.slidesCount + 1; --i; ) {
		
			this.$dots.append( ( i === this.slidesCount ) ? '<span class="jms-dots-current"/>' : '<span/>' );
		
		}
		
		if( this.options.jmpressOpts.start ) {
			
			this.$start		= this.$jmsWrapper.find( this.options.jmpressOpts.start ), idxSelected = 0;
			
			( this.$start.length ) ? idxSelected = this.$start.index() : this.options.jmpressOpts.start = null;
			
			this.$dots.children().removeClass( 'jms-dots-current' ).eq( idxSelected ).addClass( 'jms-dots-current' );
		
		}
		
		this.$el.append( this.$dots )
	
	}
	
},

We will initialize the jmpress plugin in the _initImpress function. We will also redefine the “setActive” method of jmpress in order to switch the active navigation dot.


_initImpress		: function() {
			
	var _self = this;
	
	this.$jmsWrapper.jmpress( this.options.jmpressOpts );
	// check if supported (function from jmpress.js):
	// it adds the class not-suported to the wrapper
	this.support	= !this.$jmsWrapper.hasClass( 'not-supported' );
	
	// if not supported remove unnecessary elements
	if( !this.support ) {
	
		if( this.$arrows ) {
		
			this.$arrows.remove();
		
		}
		
		if( this.$dots ) {
		
			this.$dots.remove();
		
		}
		
		return false;
	
	}
	
	// redefine the jmpress setActive method
	this.$jmsWrapper.jmpress( 'setActive', function( slide, eventData ) {
		
		// change the pagination dot active class			
		if( _self.options.dots ) {
			
			// adds the current class to the current dot/page
			_self.$dots
				 .children()
				 .removeClass( 'jms-dots-current' )
				 .eq( slide.index() )
				 .addClass( 'jms-dots-current' );
		
		}
		
		// delete all current bg colors
		this.removeClass( _self.colors );
		// add bg color class
		this.addClass( slide.data( 'color' ) );
		
	} );
	
	// add step's bg color to the wrapper
	this.$jmsWrapper.addClass( this.$jmsWrapper.jmpress('active').data( 'color' ) );
	
},

The _startSlideshow and _stopSlideshow will start and stop the slideshow respectively if the option autoplay is set to true.


// start slideshow if autoplay is true
	_startSlideshow		: function() {
	
		var _self	= this;
		
		this.slideshow	= setTimeout( function() {
			
			_self.$jmsWrapper.jmpress( 'next' );
			
			if( _self.options.autoplay ) {
			
				_self._startSlideshow();
			
			}
		
		}, this.options.interval );
	
	},
	// stops the slideshow
	_stopSlideshow		: function() {
	
		if( this.options.autoplay ) {
				
			clearTimeout( this.slideshow );
			this.options.autoplay	= false;
		
		}
	
	},

Finally, we load the events for the navigation arrows and dots. The touchend event is already defined in the jmpress plugin, but we will need to stop the slideshow in case this event is triggered:


_loadEvents			: function() {
			
	var _self = this;
	
	// navigation arrows
	if( this.$arrowPrev && this.$arrowNext ) {
	
		this.$arrowPrev.on( 'click.jmslideshow', function( event ) {
			
			_self._stopSlideshow();
		
			_self.$jmsWrapper.jmpress( 'prev' );

			return false;
		
		} );
		
		this.$arrowNext.on( 'click.jmslideshow', function( event ) {
			
			_self._stopSlideshow();
			
			_self.$jmsWrapper.jmpress( 'next' );
			
			return false;
		
		} );
		
	}
	
	// navigation dots
	if( this.$dots ) {
	
		this.$dots.children().on( 'click.jmslideshow', function( event ) {
			
			_self._stopSlideshow();
			
			_self.$jmsWrapper.jmpress( 'goTo', '.jmstep' + ( $(this).index() + 1 ) );
			
			return false;
		
		} );
	
	}
	
	// the touchend event is already defined in the jmpress plugin.
	// we just need to make sure the slideshow stops if the event is triggered
	this.$jmsWrapper.on( 'touchend.jmslideshow', function() {
	
		_self._stopSlideshow();
	
	} );
	
}

And that’s it! I hope you enjoyed this tutorial and find it useful!

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.