Created
December 9, 2015 10:47
-
-
Save Robbertdk/a37b55c440528e072511 to your computer and use it in GitHub Desktop.
Vertical Orbit Slider
This file contains hidden or 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="orbit-wrapper"> | |
<button type="button" class="orbit__move-up" href="#">Previous slides</button> | |
<ul class="orbit inline row" data-orbit> | |
<li> | |
<h3>Slide 1</h3> | |
<div class="orbit__content"> | |
<div class="orbit__meta"> | |
<p>Slide content</p> | |
</div> | |
<button>Slide action</button> | |
</div> | |
</li> | |
<li> | |
<h3>Slide 2</h3> | |
<div class="orbit__content"> | |
<div class="orbit__meta"> | |
<p>Slide content</p> | |
</div> | |
<button>Slide action</button> | |
</div> | |
</li> | |
<li> | |
<h3>Slide 3</h3> | |
<div class="orbit__content"> | |
<div class="orbit__meta"> | |
<p>Slide content</p> | |
</div> | |
<button>Slide action</button> | |
</div> | |
</li> | |
<li> | |
<h3>Slide 4</h3> | |
<div class="orbit__content"> | |
<div class="orbit__meta"> | |
<p>Slide content</p> | |
</div> | |
<button>Slide action</button> | |
</div> | |
</li> | |
<li> | |
<h3>Slide 5</h3> | |
<div class="orbit__content"> | |
<div class="orbit__meta"> | |
<p>Slide content</p> | |
</div> | |
<button>Slide action</button> | |
</div> | |
</li> | |
<li> | |
<h3>Slide 6</h3> | |
<div class="orbit__content"> | |
<div class="orbit__meta"> | |
<p>Slide content</p> | |
</div> | |
<button>Slide action</button> | |
</div> | |
</li> | |
</ul> | |
<button type="button" class="orbit__move-down" href="#">More slides</button> | |
</div> |
This file contains hidden or 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
var OrbitSlider = { | |
$sliderWrapper: $('.orbit-wrapper'), | |
$slider: $('.orbit'), | |
$slides: undefined, | |
$prevButton: $('button.orbit__move-up'), | |
$nextButton: $('button.orbit__move-down'), | |
transformSupport: Modernizr.csstransforms, | |
transitionSupport: Modernizr.csspseudotransitions, | |
breakpoint: Modernizr.mq('(min-width: 721px)'), | |
sliderHeight: undefined, | |
currentPos: 150, //150px for the fade on top | |
init: function() { | |
this.getSlides(); | |
this.setInitialState(); | |
this.setSliderHeight(); | |
this.bindUIActions(); | |
Menu.AnchorToActive(); // Calculate height when everything is loaded and ready | |
}, | |
bindUIActions: function(){ | |
this.$prevButton.on('click', this.slideUp); | |
this.$nextButton.on('click', this.slideDown); | |
$(window).on('resize', function(){ | |
OrbitSlider.setBreakpoint(); | |
OrbitSlider.setSliderHeight(); | |
OrbitSlider.setOffset(); | |
}); | |
}, | |
/* | |
* Helper function to get slides of slider | |
*/ | |
getSlides: function(){ | |
this.$slides = this.$slider.children('li'); | |
}, | |
/* | |
* Make first slides active | |
*/ | |
setInitialState: function(){ | |
this.$sliderWrapper.addClass('slider-active'); | |
this.$slides.slice(0,4).addClass('active'); | |
}, | |
/* | |
* Set the sliders height based on the height of each slide | |
*/ | |
setSliderHeight: function(){ | |
if(this.$slides){ | |
if(this.$slides.length < 5){ | |
this.$prevButton.hide(); | |
this.$nextButton.hide(); | |
} | |
var sliderHeight = 0; | |
// On desktop slides are in rows, so only the first and third would be enough | |
if(this.breakpoint){ | |
var $active = this.$slides.filter('.active'); | |
sliderHeight = $active.eq(0).outerHeight() + $active.eq(2).outerHeight(); | |
} | |
//On mobile we need the height of the four active slides | |
else { | |
this.$slides.filter('.active').each(function(){ | |
sliderHeight += $(this).outerHeight(); | |
}); | |
} | |
sliderHeight += 300; // for the fade effect | |
//store in object to acces later | |
this.sliderHeight = sliderHeight; | |
this.$sliderWrapper.css('height', sliderHeight); | |
} | |
}, | |
/* | |
* Decide if we are up or under 721px breakpoint | |
* Uses Modernizr. Breakpoint also used in CSS | |
* @return Boolean | |
*/ | |
setBreakpoint: function(){ | |
this.breakpoint = Modernizr.mq('(min-width: 721px)'); | |
}, | |
setOffset: function(){ | |
var offset = 150; | |
var firstactive = this.$slides.filter('.active').first().index(); | |
if (firstactive !== 0){ | |
if( !this.breakpoint){ | |
this.$slides.slice(0, firstactive).each(function(){ | |
offset -= $(this).outerHeight(); | |
}); | |
} else { | |
this.$slides.slice(0, firstactive).each(function(index, el){ | |
if(index % 2 === 0){ | |
offset -= $(this).outerHeight(); | |
} | |
}); | |
} | |
} | |
// 150 for the top-fade effect | |
this.currentPos = offset; | |
this.animate(offset); | |
}, | |
/* | |
* Get the slides that needs to be shown, based on the current active slides | |
* @param direction [string] | |
* @param $activeSlide [jQuery object] | |
* @param amount [integer] | |
* @return jQuery Object | |
*/ | |
getNextSlides: function(direction,$activeSlides,amount){ | |
if(direction === 'up'){ | |
var firstactive = $activeSlides.first().index(); | |
if(firstactive > 0){ | |
return this.$slides.slice(firstactive - amount, firstactive); | |
} | |
} else { //down | |
var firstNewActive = $activeSlides.last().index() + 1; | |
if(firstNewActive > 0){ | |
return this.$slides.slice(firstNewActive, firstNewActive + amount); | |
} | |
} | |
}, | |
/* | |
* Update slider heigt based on new slider views | |
* | |
* Different slides can have different heights | |
* | |
* @param removedSlideHeight [integer] height old slide | |
* @param addedSlideHeight [integer] height new slide | |
*/ | |
updateSliderHeight: function(addedSlideHeight, removedSlideHeight){ | |
// Stop update if heights are the same | |
if( removedSlideHeight === addedSlideHeight ) return false; | |
var newHeight = this.sliderHeight + addedSlideHeight - removedSlideHeight; | |
this.sliderHeight = newHeight; | |
this.$sliderWrapper.css('height', newHeight); | |
return addedSlideHeight - removedSlideHeight; | |
}, | |
/* | |
* Move slides up or down | |
*/ | |
slide: function(direction){ | |
// Amount of slides to be moved depends on media query | |
var amount = this.breakpoint ? 2 : 1; | |
// Current active slides | |
var $active = this.$slides.filter('.active'); | |
//Slides that will be added | |
var $upcomingSlides = this.getNextSlides(direction,$active,amount); | |
if(typeof $upcomingSlides === 'undefined') return false; | |
var newPos = 0; | |
var removedSlideHeight = 0; | |
var addedSlideHeight = $upcomingSlides.eq(0).outerHeight(); | |
if(direction === 'up'){ | |
// Get sliderHeight of first slider that will be removed | |
removedSlideHeight = $active.last().outerHeight(); | |
// Set new position | |
newPos = this.currentPos + removedSlideHeight; | |
// Update slider classes | |
$active.slice($active.length - amount).removeClass('active'); | |
} else { //down | |
// Set new position | |
newPos = this.currentPos - addedSlideHeight; | |
// Get sliderHeight of first slider that will be removed | |
removedSlideHeight = $active.eq(0).outerHeight(); | |
// Update slider classes | |
$active.slice(0,amount).removeClass('active'); | |
} | |
$upcomingSlides.addClass('active'); | |
var newHeight = this.updateSliderHeight(addedSlideHeight,removedSlideHeight); | |
// This was a interesting bug. If we change the height of the slider, because we have bigger sliders, | |
// the offset shoudl change according to that height | |
if(newHeight){ | |
newPos = newPos + newHeight; | |
} | |
this.animate(newPos); | |
this.currentPos = newPos; | |
this.toggleButtons(direction); | |
}, | |
/* | |
* Controls animation of sliding | |
*/ | |
animate: function(newPos){ | |
if(this.transformSupport || this.transitionSupport){ | |
this.$slider.css({ | |
'-webkit-transform':'translateY(' + newPos +'px)', | |
'-ms-transform':'translateY(' + newPos +'px)', | |
'transform':'translateY(' + newPos +'px)' | |
}); | |
} else { | |
this.$slider.animate({top:newPos}, 500); | |
} | |
}, | |
/* | |
* Moves the slider in the up direction | |
*/ | |
slideUp: function(event){ | |
OrbitSlider.slide('up'); | |
event.preventDefault(); | |
}, | |
/* | |
* Moves the slider in the down direction | |
*/ | |
slideDown: function(event){ | |
OrbitSlider.slide('down'); | |
//Disable button to prevent clicks while js-action is looping | |
var $button = $(this); | |
$button.attr("disabled", true); | |
setTimeout(function() { OrbitSlider.enableSubmit($button); }, 700); | |
event.preventDefault(); | |
}, | |
enableSubmit: function($button){ | |
$button.removeAttr("disabled"); | |
}, | |
/* | |
* Toggles the visibility up bottom if first slides aren't visible | |
* Toggles the visibility down bottom if last slides aren't visible | |
*/ | |
toggleButtons: function(direction){ | |
//if the last slide isn't active, show next-button | |
if( this.$slides.eq(-1).hasClass('active') ){ | |
this.$nextButton.fadeTo('200', 0, function(){ | |
$(this).css('display', 'none'); | |
}); | |
} else { | |
this.$nextButton.fadeTo('200', 1, function(){ | |
$(this).css('display', 'block'); | |
}); | |
} | |
//if the first slide isn't active, show prev-button | |
if( this.$slides.eq(0).hasClass('active') ){ | |
this.$prevButton.fadeTo('200', 0, function(){ | |
$(this).css('display', 'none'); | |
}); | |
} else { | |
this.$prevButton.fadeTo('200', 1, function(){ | |
$(this).css('display', 'block'); | |
}); | |
} | |
} | |
}; | |
OrbitSlider.init() |
This file contains hidden or 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
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js"></script> |
This file contains hidden or 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
* { | |
box-sizing:border-box; | |
} | |
body { | |
color:#fff; | |
background:#000; | |
} | |
.orbit-wrapper { | |
margin-bottom:3rem; | |
transition: height 0.5s ease-in-out; | |
} | |
ul.orbit{ | |
padding:0; | |
margin:0; | |
list-style-type: none; | |
padding-top:25px; | |
} | |
.orbit li { | |
width:100%; | |
min-height:150px; | |
} | |
.orbit__content h3 { | |
display:block; | |
word-wrap: break-word; | |
} | |
.orbit__meta{ | |
font-size:0.9rem; | |
} | |
@media screen and (min-width:721px){ | |
.orbit { | |
display: flex; | |
flex-wrap: wrap; | |
} | |
.orbit li { | |
width:49.99%; | |
background-color:#444; | |
border:1px solid #333; | |
padding:50px 10px; | |
} | |
.no-flexbox .orbit li{ | |
float:left; | |
} | |
} | |
//ORBIT BUTTONS | |
.orbit__move-up, | |
.orbit__move-down { | |
display: none; // only show when slider works | |
outline: none; | |
margin-top: 0; | |
padding: 0; | |
-ms-touch-action: manipulation; | |
touch-action: manipulation; | |
cursor: pointer; | |
font-size: 1rem; | |
background-image: none; | |
background-color: transparent; | |
border: none; | |
color:#fff; | |
font-weight:700; | |
text-transform: uppercase; | |
text-decoration:none; | |
position:absolute; | |
width:250px; | |
z-index:10; | |
left: 0; | |
right: 0; | |
margin-left: auto; | |
margin-right: auto; | |
transition: 0.15s color ease-in-out; | |
&:hover, | |
&:focus { | |
color:#D95B00; | |
background:transparent; | |
box-shadow:none; | |
outline:none; | |
} | |
&:focus {outline:none;} | |
&::-moz-focus-inner {border:0;} | |
} | |
.orbit__move-up{ | |
top: 50px; | |
display:none; //initial latest concert visible no concerts before | |
padding: 51px 30px 0; // extra padding for bigger touch area | |
} | |
.orbit__move-down{ | |
bottom: 50px; | |
padding: 0 30px 51px; // extra padding for bigger touch area | |
} | |
.orbit__move-up::before, | |
.orbit__move-down::before { | |
content: " "; | |
position: absolute; | |
left: 0; | |
right: 0; | |
margin-left: auto; | |
margin-right: auto; | |
width: 0px; | |
border: 26px solid rgba(0, 0, 0, 0); | |
border-left-width: 30px; | |
border-right-width: 30px; | |
transition: 0.15s border-color ease-in-out; | |
} | |
.orbit__move-up::before { | |
border-bottom-color: #FFF; | |
bottom: 40px; | |
} | |
.orbit__move-down::before { | |
border-top-color: #FFF; | |
top: 40px; | |
} | |
.orbit__move-up:hover::before, | |
.orbit__move-up:focus::before { | |
border-bottom-color:#D95B00; | |
} | |
.orbit__move-down:hover::before, | |
.orbit__move-down:focus::before { | |
border-top-color:#D95B00; | |
} | |
//Orbit Sliding functionality. | |
.slider-active{ | |
overflow:hidden; | |
position:relative; | |
.orbit__move-down { | |
display:inline-block; | |
} | |
} | |
.slider-active .orbit__content h3, | |
.slider-active .orbit__meta, | |
.slider-active .btn{ | |
visibility:hidden; | |
transition:0.2s visibility ease-in-out; | |
} | |
.slider-active .active .orbit__content, | |
.slider-active .active .orbit__content h3, | |
.slider-active .active .orbit__meta, | |
.slider-active .active .btn{ | |
visibility:visible; | |
} | |
.slider-active::before{ | |
content: " "; | |
width: 100%; | |
height: 150px; | |
position: absolute; | |
z-index: 1; | |
left: 0; | |
top:0; | |
background: #060606; | |
background: linear-gradient(to bottom, #060606 0%,rgba(06,06,06,0.65) 50%,rgba(06,06,06,0.1) 100%); | |
} | |
.slider-active::after{ | |
content: " "; | |
width: 100%; | |
height: 150px; | |
position: absolute; | |
z-index: 1; | |
left: 0; | |
bottom:0; | |
background: #060606; | |
background: linear-gradient(to bottom, rgba(06,06,06,0.1) 0%,rgba(06,06,06,0.65) 50%,#060606 100%); | |
} | |
.csstransforms .slider-active .orbit { | |
padding-top:0; | |
-webkit-transform: translateY(150px); | |
-moz-transform: translateY(150px); | |
-ms-transform: translateY(150px); | |
-o-transform: translateY(150px); | |
transform: translateY(150px); | |
-webkit-transition: -webkit-transform 0.5s ease-in-out; | |
-moz-transition: -moz-transform 0.5s ease-in-out; | |
-o-transition: -o-transform 0.5s ease-in-out; | |
transition: transform 0.5s ease-in-out; | |
} | |
.no-csstransforms .slider-active .orbit | |
.no-csstransitions .slider-active .orbit { | |
padding-top:0; | |
position:absolute; | |
top:150px; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment