Animación de papel plegado usando solo CSS

Hace un tiempo atrás estuve experimentando con transformaciones y transiciones en CSS3 usando para ello Sass. Decidí entonces pasar estos experimentos a un Codepen para compartirlo con la comunidad porque me parecieron intersantes.

El siguiente experimento consiste en la animación dinámica de un plano dando el efecto de un papel plegado. Para lograrlo solo he utilizado un elemento DIV en el HTML y código CSS usando Sass. La animación puede ser variada en cuanto a cantidad de dobleces y la velocidad de cada doblez modificando unas variables globales en Sass.

Es importante aclarar que el código Sass es ilegible y complejo de leer aparte de generar una ingente cantidad de código CSS al compilar. Solo deberías utilizarlo para experimentar, divertirte codificando y ver las posibilidades de Sass generando transformaciones dinámicamente, pero no te recomendaría que usaras un código similar para un proyecto en producción.

Si haces algún fork del proyecto y logras algo que crees que pudiera ser interesante también te agradecería que lo compartieras con la comunidad.

Código HTML

<div id="fold" />

Código Sass

/* ------------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

(3 votos, promedio: 3,67 de 5)
Comparte este artículo:

Puedes situar fragmentos de código dentro de etiquetas <pre></pre> y código HTML o XML entre etiquetas <xmp></xmp>.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *