Last active
December 14, 2015 18:19
-
-
Save tjFogarty/5128243 to your computer and use it in GitHub Desktop.
A CodePen by T.J. Fogarty. Touch/keyboard content slider - I wanted to build a simple, reusable content slider just to understand how it works. There's definitely improvements to be made, but it works :) Supports keyboard navigation, and swiping on touch-based devices.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="container"> | |
<div id="slider-container"> | |
<ul class="slider-images clearfix"> | |
<li><img class="scale" src="http://dummyimage.com/500x200/000/fff.gif&text=Slide+1" alt=""></li> | |
<li><img class="scale" src="http://dummyimage.com/500x200/fff/000.gif&text=Slide+2" alt=""></li> | |
<li><img class="scale" src="http://dummyimage.com/500x200/000/fff.gif&text=Slide+3" alt=""></li> | |
<li><img class="scale" src="http://dummyimage.com/500x200/fff/000.gif&text=Slide+4" alt=""></li> | |
</ul> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//requires Hammer.js and Modernizr to check if CSS transform is supported | |
var slider = slider || {}; | |
(function($) { | |
$( document ).ready( function() { | |
slider = { | |
mainContainer: $( '.container' ), | |
container: $( '#slider-container' ), | |
content: $( '.slider-images' ), | |
controls: null, | |
nextSlide: null, | |
prevSlide: null, | |
activeSlide: null, | |
totalSlides: null, | |
imageWidth: null, | |
distance: 0, | |
maxDistance: 0, | |
touchEvent: null, | |
moveTimer: null, | |
timerDelay: 7000, //time between auto-rotation of slides | |
win: $( window ), | |
canTransform3d: Modernizr.csstransforms3d, | |
init: function() { | |
//create our controls and other UI elements | |
slider.createUI(); | |
//bind our events for clicks, swipes etc... | |
slider.bindUI(); | |
// width of image - ^TODO: need to fix this to one statement | |
if( slider.win.width() > 960 ) { | |
slider.imageWidth = slider.container.width(); | |
} else { | |
slider.imageWidth = slider.mainContainer.width(); | |
} | |
// detect how many slides there are | |
slider.totalSlides = slider.container.find('img').length; | |
// set width of ul - ^TODO: this doesn't work correctly on smaller devices | |
//slider.content.css( 'width', slider.totalSlides * slider.imageWidth ); | |
// set max distance - the minus 1 accounts for one slide always being visible | |
slider.maxDistance = -( slider.totalSlides - 1 ) * slider.imageWidth; | |
// when everything has loaded, show the slider | |
slider.win.load(function(){ | |
slider.container.addClass( 'is-visible' ); | |
}); | |
//starts the auto-rotation | |
slider.moveTimer = slider.timer(); | |
}, | |
timer: function() { | |
return setInterval(function(){ | |
slider.animate( 'next' ); | |
}, slider.timerDelay); | |
}, | |
createUI: function() { | |
slider.container.append( '<ul class=slider-controls />' ); | |
slider.controls = $( '.slider-controls' ); | |
slider.controls.append('<li><a class=next-slide href="#">Next</a></li>'); | |
slider.controls.append('<li><a class=prev-slide href="#">Previous</a></li>'); | |
slider.nextSlide = $( '.next-slide' ); | |
// since we're starting on the first slide, we'll hide the previous button | |
slider.prevSlide = $( '.prev-slide' ).hide(); | |
// ^TODO: Create pagination elements | |
}, | |
bindUI: function() { | |
// Hammer.js for touch-based events | |
slider.touchEvent = new Hammer( document.getElementById('slider-container') ); | |
slider.touchEvent.onswipe = function(e) { | |
switch( e.direction ) { | |
case 'left': | |
slider.animate( 'next' ); | |
break; | |
case 'right': | |
slider.animate( 'previous' ); | |
break; | |
} | |
} | |
// halt auto-rotation on hover and reset when mouse leaves the slider container | |
slider.container.hover(function(){ | |
clearInterval( slider.moveTimer ); | |
}, function() { | |
slider.moveTimer = slider.timer(); | |
}); | |
//keyboard controls | |
$( document ).keydown(function(e){ | |
switch( e.keyCode ) { | |
case 37: //left arrow | |
slider.animate( 'previous' ); | |
break; | |
case 39: //right arrow | |
slider.animate( 'next' ); | |
break; | |
} | |
}); | |
slider.nextSlide.on( 'click', function(e) { | |
slider.animate( 'next' ); | |
e.preventDefault(); | |
}); | |
slider.prevSlide.on( 'click', function(e) { | |
slider.animate( 'previous' ); | |
e.preventDefault(); | |
}); | |
}, | |
animate: function( dir ) { | |
//stop auto-rotation | |
clearInterval( slider.moveTimer ); | |
// set direction | |
if( dir === 'previous' && slider.distance != 0 ) { | |
slider.distance += slider.imageWidth; | |
} else if( dir === 'next' && slider.distance != slider.maxDistance ) { | |
slider.distance -= slider.imageWidth; | |
} else if( dir ==='next' && slider.distance === slider.maxDistance ) { | |
//more to compensate for swipe and keyboard presses | |
//if there isn't a slide ahead, we just move back to the first | |
slider.distance = 0; | |
} else if( dir === 'previous' && slider.distance === 0 ) { | |
//same as above, but in reverse - move to last slide | |
slider.distance = slider.maxDistance; | |
} else { | |
return; | |
} | |
// showing/hiding of controls relevant to slider position | |
if( slider.distance === 0 ) { | |
slider.prevSlide.hide(); | |
} else { | |
slider.prevSlide.show(); | |
} | |
if ( slider.distance === slider.maxDistance ) { | |
slider.nextSlide.hide(); | |
} else { | |
slider.nextSlide.show(); | |
} | |
// move the slider content with CSS if supported | |
if( slider.canTransform3d ) { | |
slider.content.css( 'transform', 'translate3d('+slider.distance+'px,0,0)' ); | |
} else { | |
slider.content.stop().animate({ | |
'margin-left': slider.distance | |
}, 200); | |
} | |
//reset the auto-rotation | |
slider.moveTimer = slider.timer(); | |
}, | |
}; | |
slider.init(); | |
}); | |
})( jQuery ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import "compass"; | |
$headerHeight: 60px; | |
$containerWidth: 500px; | |
body { | |
font-weight: 300; | |
color: #333; | |
background: #f5f6f7; | |
} | |
h1, h2, h3, h4, h5, h6 { font-weight: 400; } | |
h1 { font-size: 50px; } | |
#slider-container { | |
opacity: 0; | |
overflow: hidden; | |
width: 100%; | |
-webkit-transition: opacity ease 0.4s; | |
-moz-transition: opacity ease 0.4s; | |
-ms-transition: opacity ease 0.4s; | |
-o-transition: opacity ease 0.4s; | |
transition: opacity ease 0.4s; | |
&.is-visible { | |
opacity: 1; | |
} | |
.slider-images { | |
list-style: none; | |
margin: 0; | |
padding: 0; | |
max-height: 380px; | |
-webkit-transition: all ease 0.4s; | |
-moz-transition: all ease 0.4s; | |
-ms-transition: all ease 0.4s; | |
-o-transition: all ease 0.4s; | |
transition: all ease 0.4s; | |
width: 9999px; // ridiculous width will be overidden by js calculated value (image width * total images) | |
li { | |
float: left; | |
width: $containerWidth; | |
overflow: hidden; | |
} | |
} | |
.slider-controls { | |
list-style: none; | |
margin: 0; | |
padding: 0; | |
} | |
} | |
.scale { | |
max-width: 100%; | |
height: auto; | |
} | |
.container { | |
width: 500px; | |
margin: 0 auto; | |
} | |
.next-slide { | |
float: right; | |
} | |
.prev-slide { | |
float: left; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment