- const glitches = ['Scroll for variants', 'All together now', 'Random iteration count']

.container
  - const glitchCount = glitches.length
  - let g = 0
  while g < glitchCount
    .page
      p= glitches[g]
      p(aria-hidden='true' data-scroll='out', data-splitting='', class=`reveal--${g}`)= glitches[g]
      - g++
View Compiled
*
  box-sizing border-box
  transition color .25s ease

:root
  --dark #111
  --light #fefefe
  --color var(--dark)
  --bg var(--light)

  @media (prefers-color-scheme: dark)
    --color var(--light)
    --bg var(--dark)

body
  background-color var(--bg)
  display flex
  align-items center
  justify-content center
  min-height 100vh
  font-size 3.5rem
  font-family -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif
  font-weight bold

p
  max-width 300px

  &[data-scroll='in']
    [data-char]:after
      animation-name glitch-switch

.reveal--0 [data-char]:after
  animation-iteration-count calc(var(--char-index) * 0.55)
.reveal--1 [data-char]:after
  animation-iteration-count 4
.reveal--2 [data-char]:after
  animation-iteration-count var(--count)

p:nth-of-type(1)
  position absolute
  opacity 0

.word
  position relative
  display inline-block

[data-char]
  color transparent
  position relative

  &:after
    --txt attr(data-char)
    animation-duration .2s
    animation-delay .5s
    animation-timing-function steps(1)
    animation-fill-mode backwards
    content var(--txt)
    color var(--color)
    position absolute
    left 0
    top 0

@keyframes glitch-switch
  0%
    content var(--char-0)
  10%
    content var(--char-1)
  20%
    content var(--char-2)
  30%
    content var(--char-3)
  40%
    content var(--char-4)
  50%
    content var(--char-5)
  60%
    content var(--char-6)
  70%
    content var(--char-7)
  80%
    content var(--char-8)
  90%
    content var(--char-9)
  100%
    content var(--char-0)

/**
 * Themeing
*/
.page
  align-items center
  display flex
  height 100vh
  justify-content center
  position relative
  scroll-snap-align center
  width 100vw

.container
  height 100vh
  overflow auto
  overflow-x hidden
  scroll-snap-type y mandatory
View Compiled
const { Splitting } = window
const results = Splitting()
const glitches = '`¡™£¢∞§¶•ªº–≠åß∂ƒ©˙∆˚¬…æ≈ç√∫˜µ≤≥÷/?░▒▓<>/'.split('')

for (let r = 0; r < results.length; r++) {
  const chars = results[r].chars
  for (let c = 0; c < chars.length; c++) {
    chars[c].style.setProperty('--count', Math.random() * 5 + 1)
    for (let g = 0; g < 10; g++) {
      chars[c].style.setProperty(
        `--char-${g}`,
        `"${glitches[Math.floor(Math.random() * glitches.length)]}"`
      )
    }
  }
}
window.ScrollOut({
  scrollingElement: '.container',
  targets: 'p',
})
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

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