Paper folding animation using only CSS

Some time ago, I was experimenting with CSS3 transformations and transitions using Sass. Then, I decided to port these experiments into a Codepen to share it with the Internet community because I think that they are interesting.

The next experiment consists in a dynamic animation of a plane giving an effect of a paper being folded. To achieve this I have used just a DIV element in the HTML and CSS code using Sass. The animation can be modified in term of number of folds and the speed of each one changing some global variables in the Sass code.

It is important to remark, that the Sass code used is almost unreadable and complex besides of generating a bunch of CSS code when compiles. You should use it just to experiment, get fun coding and see the possibilities of Sass dynamically generating CSS transformations, but I don’t recommend you using a similar code in a real project in production.

If you make a fork of the project and you get something interesting too, I would request you to share it with the Internet community.

HTML code

<div id="fold"></div>

Sass code

/* ------------VARIABLES TO EDIT------------------ */
$folds: 6       // Number of folds
$time: 0.5      // Time of each fold animation
$back: #E25875  // Background color
$base: #EEE     // Paper color
/* ----------------------------------------------- */

$darken: darken($base, 10)
$darken2: darken($base, 20)
$height: 75%
$width: 15%

html
  height: 100%
  
body
  background: linear-gradient(to bottom, $back, darken($back, 10))
  height: 100%
  margin: 0
  padding: 0
  position: relative
  
@function pow($b, $e)
  $v: 1 
  @if $e > 0
    @for $i from 1 through $e
      $v: $v * $b
  @return $v
  
@function foldSizes($step)
  $even: $step % 2 == 0
  $h: $height / if($even, pow(3, $step / 2), pow(3, ($step - 1) / 2))
  $w: $width / if($even, pow(3, $step / 2 - 1), pow(3, ($step - 1) / 2))
  @return $w, $h

@function getSizesSteps($steps)
  $str: ""
  @for $i from 1 to $steps
    $state: if(($steps - $i + 1) % 2 == 0, "even", "odd")
    $delay: (($i - 1) * 2) * $time
    $sdelay1: (($i - 1) * 2) * $time
    $sdelay2: (($i - 1) * 2 + 1) * $time
    $str: $str + "center-" + $i + " " + ($time * 2) + "s " + $delay + "s forwards"
    $str: $str + ",before-shadow-center-" + $state + " " + $time + "s " + $sdelay1 + "s forwards"
    $str: $str + ",after-shadow-center-" + $state + " " + $time + "s " + ($sdelay1 + $time) + "s forwards"
    @if $i < $steps - 1
      $str: $str + ","
  @return unquote($str) 

@function getAnimations($prefix, $steps)
  $str: ""
  @for $i from 1 to $steps
    $state: if(($steps - $i + 1) % 2 == 0, "even", "odd")
    $delay: if($prefix == before, (($i - 1) * 2) * $time, (($i - 1) * 2 + 1) * $time)
    $str: $str + $prefix + "-" + $state + " " + $time + "s " + $delay + "s forwards"
    $str: $str + "," + $prefix + "-shadow-" + $state + " " + $time + "s " + $delay + "s forwards"
    @if $i < $steps - 1
      @if $prefix == after
        $str: $str + ",after-end-" + $state + " " + $time + "s " + ($delay + $time) + "s forwards" 
      $str: $str + ","
  @return unquote($str)      
 
=fold-center($step)
  $sizes: foldSizes($step)  
  height: nth($sizes, 2)
  width: nth($sizes, 1)
  
=shadow-center($prefix, $even, $initial: true)
  @if $prefix == before
    background: linear-gradient(if($even, to right, to bottom), $darken2, $darken2, $base, $base, $base)
    background-position: if($even, if($initial, 0, 100%), if($initial, 0 0, 0 100%))   
  @else
    background: linear-gradient(if($even, to left, to top), $darken2, $darken2, $base, $base, $base)
    background-position: if($even, if($initial, 100%, 0), if($initial, 0 100%, 0 0))
  background-size: 200% 200%
  
=fold-before($even, $initial: true)  
  left: if($even, -100%, 0)
  top: if($even, 0, -100%)
  transform-origin: if($even, 100% 0, 0 100%)
  transform: if($even, rotateY(if($initial, 180deg, 0deg)), rotateX(if($initial, -180deg, 0deg)))

=fold-after($even, $initial: true)  
  right: if($even, -100%, 0)
  bottom: if($even, 0, -100%)
  opacity: 1
  transform: if($even, rotateY(if($initial, -180deg, 0deg)), rotateX(if($initial, 180deg, 0deg)))
    
=shadow-pages($prefix, $even, $initial: true)
  @if $prefix == before
    background: linear-gradient(if($even, to left, to top), $darken, $base, $base)
    background-position: if($even, if($initial, 0, 100%), if($initial, 0 0, 0 100%))   
  @else
    background: linear-gradient(if($even, to right, to bottom), $darken, $base, $base)
    background-position: if($even, if($initial, 100%, 0), if($initial, 0 100%, 0 0))
  background-size: 200% 200%
 
=create-fold($id, $steps)
  $max: $steps + 1
  @for $i from 1 to $max
    $j: $steps - $i + 1    
    @keyframes center-#{$i}
      0%,
      100%
        +fold-center($j)
    
  $states: even odd
  $sides: before after
  @each $state in $states
    $even: $state == even
    @each $side in $sides
      $before: $side == before
      @keyframes #{$side}-#{$state}
        @if $before        
          0%          
            +fold-before($even)          
          100%
            +fold-before($even, false)
        @else
          0%
            +fold-after($even)
          100%
            +fold-after($even, false)      

      @keyframes #{$side}-shadow-#{$state}
        0%,
        100%
          +shadow-pages($side, $even)
        50%
          +shadow-pages($side, $even, false)
  
      @keyframes #{$side}-shadow-center-#{$state}
        0%
          +shadow-center($side, $even)
        100%
          +shadow-center($side, $even, false)
  
      @if $side == after
        @keyframes after-end-#{$state}
          0%,
          100%
            +fold-after(not $even)
            background: $base
            opacity: 0
  
  ##{$id}
    animation: getSizesSteps($max)
    background: $base
    left: 50%
    perspective: 1000
    position: relative
    top: 50%
    transform: translate(-50%, -50%)
  
    &::before,
    &::after
      content: ""
      height: 100%
      position: absolute
      width: 100%
  
    &::before
      animation: getAnimations(before, $max)
      z-index: 2
  
    &::after
      animation: getAnimations(after, $max)
      transform-origin: 0 0 
      z-index: 1
    
+create-fold("fold", $folds)

Codepen

Ver el código en by (@elchininet) on CodePen.3

(4 votes, average: 4.00 Out Of 5)
Share this post:

4 Comments

  1. In all seriousness – the sass code may be complex, but what in particular flags it up for you as a no in production ?
    appears to perform reasonably and you could always support a basic fallback no?

    • The main flag is that it is a hard-to-read code and it would make hard for other developers make changes or improve it, but it will not break the page or anything like that. I made that warning because one should be careful with the setup, the generated code becomes bigger and bigger depending on the number of folds.
      Regards!

It is possible to insert code fragments between <pre></pre> tags and HTML or XML code between <xmp></xmp> tags.

Leave a Reply

Your email address will not be published. Required fields are marked *


The reCAPTCHA verification period has expired. Please reload the page.