button.btn Next
.container
  - for (var i = 1; i <= 6; i++)
    div(class='page page-' + i)
      h1
        span Page
        | Transitions             
View Compiled
@import url('https://fonts.googleapis.com/css?family=Lato|Dancing+Script');
$duration: .5s;
$ease: ease-out;
$animations: (
  Move: (
    Right: translate3d(100%, 0, 0),
    Left: translate3d(-100%, 0, 0),
    Top: translate3d(0, -100%, 0),
    Bottom: translate3d(0, 100%, 0),
  ),
  MoveFade: (
    Right: (
      transform: translate3d(100%, 0, 0),
      opacity: 0.2
    ),
    Left: (
      transform: translate3d(-100%, 0, 0),
      opacity: 0.2
    ),
    Top: (
      transform: translate3d(0, -100%, 0),
      opacity: 0.2
    ),
    Bottom: (
      transform: translate3d(0, 100%, 0),
      opacity: 0.2
    )
  ),
);


// ---------------------------
// animations

@function is-map($var) {
  @return type-of($var) == map
}

// Assign animation propertys & keyframe values from animations map.
@each $animationType, $value in $animations {
  @each $prop, $val in $value { 
    @if is-map($val) == true {
      .from#{$prop}Fade {
        animation: from#{$prop}Fade $duration $ease;
      }
      @keyframes from#{$prop}Fade { 
        from { opacity: map-get($val, opacity); transform: map-get($val, transform) } 
      }
      .to#{$prop}Fade {
        animation: to#{$prop}Fade $duration $ease;
      }
      @keyframes to#{$prop}Fade { 
        from { }
        to { opacity: map-get($val, opacity); transform: map-get($val, transform) } 
      }
    } 
    @else {
      .from#{$prop} {
        animation: from#{$prop} $duration $ease;
      }
      @keyframes from#{$prop} {
        from { transform: $val }
      }
      .to#{$prop} {
        animation: to#{$prop} $duration $ease;
      }
      @keyframes to#{$prop} {
        to { transform: $val }
      }
    }
  }
}

// --------------------------
// pages

.page {
  width: 100%;
  height: 100%;
  position: absolute;
  text-align: center;
  top: 0;
  left: 0;
  overflow: hidden;
  visibility: hidden;
  backface-visibility: hidden;
  transform: translate3d(0,0,0);
  transform-style: preserve-3d;
  will-change: transform;
  
  h1 {
    font-size: 4.5rem;
    font-weight: 700;
    font-family: 'Dancing Script';
    letter-spacing: 4px;
    span {
      color: rgba(0,0,0,0.3);
    }
  }
  
  &--current {
    visibility: visible;
    z-index: 1;
  }

}

.page-1 { background: #99B898; }
.page-2 { background: #FECEA8; }
.page-3 { background: #FF847C; }
.page-4 { background: #E84A5F; }
.page-5 { background: #05465A; }
.page-6 { background: #2A363B; }

// ---------------------------
// base

*, *::before, *::after {
  box-sizing: border-box;
}

html, body { height: 100%; margin: 0; padding: 0;}

body {
  font-family: 'Lato', Arial, sans-serif;
  color: #fff;
  background: #333;
  overflow: hidden;
}

.container {
  width: 100%;
  height: 100vh;
  position: relative;
  perspective: 1200px;
}

.btn {
  display: block;
  position: absolute;
  margin: 20px 0;
  padding: 14px 20px;
  width: 250px;
  left: calc(50% - 125px);
  top: 160px;
  font-size: 14px;
  font-weight: 700;
  font-family: inherit;
  letter-spacing: 1px;
  text-transform: uppercase;
  background: #fff;
  color: #888;
  cursor: pointer;
  border: none;
  border-radius: 4px;
  outline: none;
  z-index: 100;
  box-shadow: 0 3px 0 rgba(0,0,0,0.1);
  transform: translateY(0);
  transition: 0.3s ease-out;
  
  &:hover {
    transform: translateY(-5px);
    box-shadow: 0 3px 15px rgba(0,0,0,0.7);
  }
}
View Compiled
const Transitions = (() => {
  
  const pages = Array.from(document.querySelectorAll('.page'));
  const btn = document.querySelector('.btn');
  let pageIndex = 0;
  let animationIndex = 0;
  let isAnimating = false;
  let currentPageEnded = false;
  let nextPageEnded = false;
  
  function init() {
    if (pages.length < 2) {
      throw new Error('Must be at least 2 pages to transition between.');
    }
    // store current classNames.
    pages.forEach(page => page.data = {classList: page.getAttribute('class')});
    pages[pageIndex].classList.add('page--current');
    
    btn.addEventListener('click', function() {
      if (isAnimating) return false;
      if (animationIndex === animations.length) {
        animationIndex = 0;
      }
      transitionPage(animationIndex);
      ++animationIndex;
    });
 
  }
  
  function transitionPage(index) {
    if (isAnimating) {
      return false;
    }
    isAnimating = true;
    
    // update currents value and add className to nextPage.
    const currentPage = pages[pageIndex];
    pageIndex = (pageIndex < pages.length - 1) ? ++pageIndex : 0 ;
    const nextPage = pages[pageIndex];
    nextPage.classList.add('page--current');
    
    // Search through animations and get related classNames for anim at animation index.
    const transitionType = animations[animationIndex];
    const key = Object.keys(transitionType);
    console.log(transitionType, key)
    const {[key]: {inClass, outClass}} = transitionType;
    
    // add eventListeners for page transitions
    currentPage.addEventListener('animationend', function _() {
      currentPage.removeEventListener('animationend', _);
      currentPageEnded = true;
      
      if (nextPageEnded) {
        endAnimation(currentPage, nextPage);
      }
    });
    currentPage.classList.add(...outClass);
    
    nextPage.addEventListener('animationend', function _() {
      nextPage.removeEventListener('animationend', _);
      nextPageEnded = true;
      
      if (currentPageEnded) {
        endAnimation(currentPage, nextPage);
      }
    });
    nextPage.classList.add(...inClass);
  }
  
  function endAnimation(outPage, inPage) {
    currentPageEnded = false;
    nextPageEnded = false;
    isAnimating = false;
    outPage.setAttribute(`class`, `${outPage.data.classList}`);
    inPage.setAttribute(`class`, `${inPage.data.classList} page--current`);
  }
  
  const animations = [
    {
      fromRight: {
        inClass: ['fromRight'],
        outClass: ['toLeft']
      }
    },
    {
      fromLeft: {
        inClass: ['fromLeft'],
        outClass: ['toRight']
      }
    },
    {
      fromBottom: {
        inClass: ['fromBottom'],
        outClass: ['toTop']
      }
    },
    {
      fromTop: {
        inClass: ['fromTop'],
        outClass: ['toBottom']
      }
    },
    {
      fromRightFade: {
        inClass: ['fromRightFade'],
        outClass: ['toLeftFade']
      }
    },
    {
      fromLeftFade: {
        inClass: ['fromLeftFade'],
        outClass: ['toRightFade']
      }
    },
    {
      fromBottomFade: {
        inClass: ['fromBottomFade'],
        outClass: ['toTopFade']
      }
    },
    {
      fromTopFade: {
        inClass: ['fromTopFade'],
        outClass: ['toBottomFade']
      }
    },
  ];
  
  init();

})();

View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.