.page
  .text Scroll for cascading text effects!
  - const effects = ['random', 'enter', 'swapsies', 'fading', 'flipping', 'slide', 'karaoke', 'spinning', 'filling', 'blocks', 'scaling', 'turning', 'folding', 'bulge', 'tumbling', 'rolling', 'perspective', 'zipping', 'swinging', 'bubbling', 'blowing', 'meeting', 'conveyor']
  each val in effects
    .text(data-scroll='out', data-splitting='', class=`text--${val}`)= `${val.charAt(0).toUpperCase()}${val.substr(1)}`
View Compiled
@import url('https://fonts.googleapis.com/css?family=Lato:700')

*
  box-sizing border-box

body
  font-family 'Lato', sans-serif
  margin 0
  padding 0

.page
  height 100vh
  overflow auto

.text
  align-items center
  color #fff
  display flex
  font-size 3rem
  height 100vh
  justify-content center
  overflow hidden
  text-align center
  width 100vw

  @media(min-width 768px)
    font-size 5rem

  &:nth-child(n)
    background #7e05d7
  &:nth-child(2n)
    background #f21e56
  &:nth-child(3n)
    background #bd04a9

  // Splitting related code
  .char
    display inline-block
    animation-delay calc(.25s + var(--char-index) * .1s)
    transition all .25s calc(.25s + var(--char-index) * .1s)

random(min, max)
  return floor(math(0, 'random')*(max - min + 1)) + min

.text
  &--enter
    [data-scroll='out'] .char
      opacity 0
      transform translate(0, -150%)

    .char
      opacity 1
      transform translate(0, 0)

  &--random
    random()
      return floor(math(0, 'random')*(250 - 25 + 1) + 25)

    [data-scroll='out'] .char
      for $i in (1..6)
        &:nth-of-type({$i})
          $x = random()
          $y = random()
          if ($x % 2 eq 1)
            $x = $x * -1
          if ($y % 2 eq 1)
            $y = $y * -1

          transform translateX($x * 1%) translateY($y * 1%)

  &--swapsies
    [data-scroll='in'] .char
    [data-scroll='out'] .char
      &:nth-of-type(odd)
        transform translateX(100%)
      &:nth-of-type(even)
        transform translateX(-100%)

    [data-scroll='in'] .char
      animation-duration .5s
      animation-fill-mode forwards
      &:nth-of-type(odd)
        animation-name swap-left
      &:nth-of-type(even)
        animation-name swap-right

    @keyframes swap-right
      25%
        transform translateX(-100%) translateY(-100%)
      75%
        transform translateX(0) translateY(-100%)
      100%
        transform translateX(0) translateY(0)

    @keyframes swap-left
      25%
        transform translateX(100%) translateY(100%)
      75%
        transform translateX(0) translateY(100%)
      100%
        transform translateX(0) translateY(0)

  &--fading
    [data-scroll='out'] .char
      opacity 0

  &--flipping
    [data-scroll='out'] .char
      transform rotateY(180deg)

  &--slide
    .char
      transition-delay calc((var(--char-total) - var(--char-index)) * .1s)

    [data-scroll='out'] .char
      opacity 0
      transform translate(-300%, 0) skewX(20deg)

  &--karaoke
    .char
      color rgba(255, 255, 255, 0.15)
      transition-duration .1s

      &:after
        color #fff
        visibility visible

    [data-scroll='in'] .char:after
      clip-path inset(0 0 0 0)

    [data-scroll='out'] .char:after
      clip-path inset(0 100% 0 0)

  &--filling
    .char
      color rgba(255, 255, 255, 0.15)

      &:after
        color #fff
        visibility visible

    [data-scroll='in'] .char:after
      clip-path inset(0 0 0 0)

    [data-scroll='out'] .char:after
      clip-path inset(100% 0 0 0)

  &--blocks
    [data-scroll='out'] .char
      visibility hidden

    [data-scroll='in']
      overflow hidden
      position relative

      .char
        transition-delay .5s

      &:after
        content ''
        height 100%
        width 100%
        position absolute
        top 0
        right 0
        bottom 0
        left 0
        background #fff
        animation block .5s .25s both


        @keyframes block
          0%
            transform translate(-110%, 0)
          45%, 55%
            transform translate(0, 0)
          100%
            transform translate(110%, 0)

  &--scaling
    [data-scroll='out'] .char
      transform scale(0)

  &--turning
    [data-scroll='out'] .char
      transform rotateY(90deg)

  &--folding
    [data-scroll='out'] .char
      transform rotateX(90deg)
      transform-origin bottom

  &--bulge
    [data-scroll='in'] .char
      animation-name bulge
      animation-duration .25s

      @keyframes bulge
        50%
          transform scale(1.5)

  &--perspective
    perspective 1000px
    .char
      transition transform .25s calc(.25s + var(--char-index) * .1s), opacity .05s calc(.25s + var(--char-index) * .1s)
    [data-scroll='out'] .char
      opacity 0
      transform translate3d(-25px, -20px, -800px)

  &--zipping
    .char
      transition transform .25s calc(.25s + var(--char-index) * .1s), opacity .05s calc(.25s + var(--char-index) * .1s)
    [data-scroll='out'] .char
      opacity 0
      &:nth-of-type(odd)
        transform translate(0, -100%)
      &:nth-of-type(even)
        transform translate(0, 100%)

  &--spinning
    [data-scroll='out'] .char
      transform rotateY(-360deg)

  &--tumbling
    .char
      transition-delay calc((var(--char-total) - var(--char-index)) * .1s)
    [data-scroll='out'] .char
      opacity 0
      transform translate(-300%, -50%) rotate(1080deg) scale(0)

  &--bubbling
    .char
      for $i in (1..8)
        &:nth-of-type({$i})
          transition-delay (random(8, 1) * .1s)
      transition-timing-function cubic-bezier(0.75, -2, .75, 2)
    [data-scroll='out'] .char
      transform scale(0.5)

  &--swinging
    .char
      transform-origin calc((var(--char-total) - var(--char-index)) * 100%) -100%
      transition-delay calc((var(--char-total) - var(--char-index)) * .1s)

    [data-scroll='out'] .char
      opacity 0
      transform rotate(90deg)


  &--rolling
    .char
      transition transform 1s, opacity .2s
      transition-delay calc((var(--char-total) - var(--char-index)) * .1s)

    [data-scroll='out'] .char
      opacity 0
      transform translate(-500%, 0) scale(0) rotate(-1440deg)

  &--blowing
    .char
      animation-duration 1s
      animation-fill-mode both
      transform-origin left bottom
      animation-delay calc(var(--char-index) * .025s)

    [data-scroll='in'] .char
      animation-name blowing

    @keyframes blowing
      50%, 60%, 70%
        transform skewX(-35deg)
      55%, 65%, 75%
        transform skewX(-40deg)

  &--meeting
    .char
      transition-delay calc((var(--char-total) - var(--char-index)) * .1s)
      &:nth-of-type(even)
        transform-origin top right
      &:nth-of-type(odd)
        transform-origin bottom left

    [data-scroll='out'] .char
      transform rotate(180deg)


  &--conveyor
    [data-scroll='in'] .char
      transform-origin left bottom
      animation convey 1s both linear
      animation-delay calc((var(--char-total) - var(--char-index)) * .15s)
      transition none

      @keyframes convey
        0%
          transform translate(calc((var(--char-total) - (var(--char-total) - var(--char-index))) * -100%), 0) rotate(-180deg) translate(calc((var(--char-total) - var(--char-index)) * -100%), 0)
        40%
          transform translate(calc((var(--char-total) - (var(--char-total) - var(--char-index))) * -100%), 0) rotate(-180deg) translate(0, 0)
        50%
          transform translate(calc((var(--char-total) - (var(--char-total) - var(--char-index))) * -100%), 0) rotate(0deg) translate(0, 0)
        100%
          transform translate(0, 0) rotate(0deg) translate(0, 0)
const { Splitting, ScrollOut } = window
Splitting()
ScrollOut({
  targets: '.word',
  scrollingElement: '.page',
})
View Compiled

External CSS

  1. https://unpkg.com/splitting/dist/splitting.css

External JavaScript

  1. https://unpkg.com/splitting/dist/splitting.js
  2. https://unpkg.com/scroll-out/dist/scroll-out.min.js