Skip to content

Instantly share code, notes, and snippets.

@Robbertdk
Created December 9, 2015 10:47
Show Gist options
  • Save Robbertdk/a37b55c440528e072511 to your computer and use it in GitHub Desktop.
Save Robbertdk/a37b55c440528e072511 to your computer and use it in GitHub Desktop.
Vertical Orbit Slider
<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>
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()
<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>
* {
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