<div class="imgLoader"></div>

<div class="container">

  <h1 class="title">
    Turning pages<br>with css
  </h1>

  <div class="credit">
    * Images loaded randomly from Picsum.photos
  </div>

  <div class="book">
    <div class="gap"></div>
    <div class="pages">
      <div class="page"></div>
      <div class="page"></div>
      <div class="page"></div>
      <div class="page"></div>
      <div class="page"></div>
      <div class="page"></div>
    </div>
    <div class="flips">
      <div class="flip flip1">
        <div class="flip flip2">
          <div class="flip flip3">
            <div class="flip flip4">
              <div class="flip flip5">
                <div class="flip flip6">
                  <div class="flip flip7"></div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<a href="https://twitter.com/amit_sheen" class="twitterLink" target="_blank">
   <img src="https://assets.codepen.io/1948355/twitterLogo2.png" />
</a>
@import url('https://fonts.googleapis.com/css2?family=Indie+Flower&display=swap');

* {
    padding: 0;
    margin: 0 auto;
    box-sizing: border-box;
}

body {
    font-family: 'Indie Flower', cursive;
    background-color: #eee;
    color: #555;
    text-align: center;
    padding: 4em 0;
}

$bookAngle: 60deg;
$speed: 5s;
$borderColor: #555;

$images:
    url('https://picsum.photos/420/300?random=1'),
    url('https://picsum.photos/420/300?random=2'),
    url('https://picsum.photos/420/300?random=3'),
    url('https://picsum.photos/420/300?random=4'),
    url('https://picsum.photos/420/300?random=5'), 
    url('https://picsum.photos/420/300?random=1');

// Preload to images
.imgLoader {
    position: fixed;
    animation: preLoad 1s steps(1);
    width: 1px;
    height: 1px;

    @keyframes preLoad {
        @for $i from 0 through 4 {
            #{$i * 10}% { background-image: nth($images, ($i + 1)); }
        }
        100% { display: none; }
    }
}

.container {
    position: relative;
    width: 420px;
    border: #fff solid 2px;
    border-radius: 4px;
    height: 420px;
}

.title {
    position: absolute;
    top: 45px; left: 0;
    width: 100%;
    font-size: 2em;
    font-weight: normal;
    line-height: 1;
}

.credit {
    position: absolute;
    top: 100%; left: 0;
    font-size: 0.9em;
    text-align: left;

}

.book {
    position: relative;
    perspective: 630px;
    perspective-origin: center 50px; 
    transform: scale(1.2);
    filter: drop-shadow(0px 10px 5px rgba(0,0,0,0.25));
}

.page {
    width: 210px;
    height: 300px;
    background-color: #bbb;
    position: absolute;
    top: 0px; right: 50%;
    transform-origin: 100% 100%;
    border: solid $borderColor 2px;
    background-size: 420px 300px;
    background-position: center;

    &:nth-child(1) {transform: rotateX($bookAngle) rotateY(3deg); }
    &:nth-child(2) { transform: rotateX($bookAngle) rotateY(4.5deg); }
    &:nth-child(3) {
        transform: rotateX($bookAngle) rotateY(6deg);
        animation: nextPage $speed*5 infinite $speed*-4.8 steps(1);
        background-size: 420px 300px;
        background-position: -2px -2px;
    }

    &:nth-child(4) { transform: rotateX($bookAngle) rotateY(177deg); }
    &:nth-child(5) { transform: rotateX($bookAngle) rotateY(175.5deg); }
    &:nth-child(6) {
        transform: rotateX($bookAngle) rotateY(174deg);
        overflow: hidden;

        &::after {
            content: '';
            width: 210px;
            height: 300px;
            position: absolute;
            top: 0px; right: 0%;
            transform-origin: center;
            transform: rotateY(180deg);
            animation: nextPage $speed*5 $speed*-4 infinite steps(1);
            background-size: 420px 300px;
            background-position: 100% -2px;
        }
    }

    @keyframes nextPage {
        @for $i from 0 through 4 {
            #{$i * 20}% { background-image: nth($images, ($i + 1)); }
        }
    }
}

.gap {
    width: 10px;
    height: 300px;
    background: none;
    transform: rotateX($bookAngle);
    transform-origin: bottom;
    position: absolute;
    top: 0px; left: calc(50% - 5px);

    &::after {
        content: '';
        position: absolute;
        bottom: 0;
        left: 50%;
        transform: translate(-50%, 50%);
        background-color: $borderColor;
        width: 10px;
        height: 5px;
        border-radius: 50%;
    }
}

.flip {
    width: 32px;
    height: 300px;
    position: absolute;
    top: 0px;
    transform-origin: 100% 100%;
    right: 100%;
    border: solid $borderColor;
    border-width: 2px 0px;
    perspective: 4200px;
    perspective-origin: center; 
    transform-style: preserve-3d;
    background-size: 420px 300px;

    &::after {
        content: '';
        position: absolute;
        top: 0px; right: 0%;
        width: 100%; height: 100%;
        transform-origin: center;
        background-size: 420px 300px;
    }

    &.flip1 {
        right: 50%;
        animation: flip1 $speed infinite ease-in-out;
        border-width: 2px 2px 2px 0;

        &::after {
            animation: nextFlip1 $speed*5 $speed*-4 infinite steps(1);
        }
    }

    &:not(.flip1) {
        right: calc(100% - 2px);
        top: -2px;
        transform-origin: right;
        animation: flip2 $speed ease-in-out infinite;
    }

    @for $i from 2 through 7 {
        &.flip#{$i}::after { animation: nextFlip#{$i} $speed*5 $speed*-4 infinite steps(1); }
    }
    
    &.flip7 {
        width: 30px;
        border-width: 2px 0px 2px 2px;
        &::after { animation: nextFlip7 $speed*5 $speed*-4 infinite steps(1); }
    }

    @keyframes flip1 {
        0%, 20% { transform: rotateX($bookAngle) rotateY(6deg); }
        80%, 100% { transform: rotateX($bookAngle) rotateY(174deg); }
    }

    @keyframes flip2 {
        0%, 20% { transform: rotateY(0deg) translateY(0px); }
        50% { transform: rotateY(-15deg) translateY(0px); }
    }
}

@keyframes nextFlip1 {
    @for $i from 0 through 4 {
        #{$i * 20}% { background-image: nth($images, ($i + 1)); background-position: -178px -2px; transform: rotateY(0deg); }
        #{10 + ($i * 20)}% { background-image: nth($images, ($i + 2)); background-position: -210px -2px; transform: rotateY(180deg); }
    }
}

@for $i from 2 through 6 {
    @keyframes nextFlip#{$i} {
        @for $j from 0 through 4 {
            #{$j * 20}% { background-image: nth($images, ($j + 1)); background-position: #{-148 + (($i - 2) * 30)}px -2px; transform: rotateY(0deg); }
            #{((10 + ($j * 20)) + (($i - 1) * 0.5))}% { background-image: nth($images, ($j + 2)); background-position: #{-238 - (($i - 2) * 30)}px -2px; transform: rotateY(180deg); }
        }
    }
}

@keyframes nextFlip7 {
    @for $i from 0 through 4 {
        #{$i * 20}% { background-image: nth($images, ($i + 1)); background-position: -2px -2px; transform: rotateY(0deg); }
        #{13 + ($i * 20)}% { background-image: nth($images, ($i + 2)); background-position: -388px -2px; transform: rotateY(180deg); }
    }
}

.twitterLink {
  position: fixed;
  bottom: 0.5em; right: 0.5em;
  & img {
    width: 2em;
    filter: grayscale(100%);
    transition: filter 0.25s;
    &:hover {
      filter: grayscale(0%);
    }
  }
}
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.