mixin flaps(taped)
  .package__flap.package__flap--top
    if taped
      .package__tape.package__tape--top
  .package__flap.package__flap--bottom
    if taped
      .package__tape.package__tape--bottom

input#package(type="checkbox")
input#one(type="radio" name='size')
label.size-label.one(for="one") S
input#two(type="radio" name='size' checked)
label.size-label.two(for="two") M
input#three(type="radio" name='size')
label.size-label.three(for="three") L
input#four(type="radio" name='size')
label.size-label.four(for="four") XL
label.close(for="package") Close Package
label.open(for="package") Open Package
.scene
  .package__wrapper
    .package__shadow
    .package
      .package__content
        svg.package__icon.package__icon--css(role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg")
          title CSS3
          path(d="M1.5 0h21l-1.91 21.563L11.977 24l-8.565-2.438L1.5 0zm17.09 4.413L5.41 4.41l.213 2.622 10.125.002-.255 2.716h-6.64l.24 2.573h6.182l-.366 3.523-2.91.804-2.956-.81-.188-2.11h-2.61l.29 3.855L12 19.288l5.373-1.53L18.59 4.414z")
        svg.package__icon.package__icon--html(role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg")
          title HTML5
          path(d="M1.5 0h21l-1.91 21.563L11.977 24l-8.564-2.438L1.5 0zm7.031 9.75l-.232-2.718 10.059.003.23-2.622L5.412 4.41l.698 8.01h9.126l-.326 3.426-2.91.804-2.955-.81-.188-2.11H6.248l.33 4.171L12 19.351l5.379-1.443.744-8.157H8.531z")
        svg.package__icon.package__icon--js(role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg")
          title JavaScript
          path(d="M0 0h24v24H0V0zm22.034 18.276c-.175-1.095-.888-2.015-3.003-2.873-.736-.345-1.554-.585-1.797-1.14-.091-.33-.105-.51-.046-.705.15-.646.915-.84 1.515-.66.39.12.75.42.976.9 1.034-.676 1.034-.676 1.755-1.125-.27-.42-.404-.601-.586-.78-.63-.705-1.469-1.065-2.834-1.034l-.705.089c-.676.165-1.32.525-1.71 1.005-1.14 1.291-.811 3.541.569 4.471 1.365 1.02 3.361 1.244 3.616 2.205.24 1.17-.87 1.545-1.966 1.41-.811-.18-1.26-.586-1.755-1.336l-1.83 1.051c.21.48.45.689.81 1.109 1.74 1.756 6.09 1.666 6.871-1.004.029-.09.24-.705.074-1.65l.046.067zm-8.983-7.245h-2.248c0 1.938-.009 3.864-.009 5.805 0 1.232.063 2.363-.138 2.711-.33.689-1.18.601-1.566.48-.396-.196-.597-.466-.83-.855-.063-.105-.11-.196-.127-.196l-1.825 1.125c.305.63.75 1.172 1.324 1.517.855.51 2.004.675 3.207.405.783-.226 1.458-.691 1.811-1.411.51-.93.402-2.07.397-3.346.012-2.054 0-4.109 0-6.179l.004-.056z")
      .package__side.package__side--main
        +flaps(true)
        .package__side.package__side--tabbed
          img.package__branding.package__branding--shadow(src="https://assets.codepen.io/605876/avatar.png")
          img.package__branding(src="https://assets.codepen.io/605876/avatar.png")
          +flaps()
        .package__side.package__side--extra
          +flaps()
          .package__side.package__side--flipped
            span.package__direction
              svg(viewBox="0 0 256 512" title="long-arrow-alt-up")
                path(d="M88 166.059V468c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12V166.059h46.059c21.382 0 32.09-25.851 16.971-40.971l-86.059-86.059c-9.373-9.373-24.569-9.373-33.941 0l-86.059 86.059c-15.119 15.119-4.411 40.971 16.971 40.971H88z")
              span THIS WAY UP
              svg(viewBox="0 0 256 512" title="long-arrow-alt-up")
                path(d="M88 166.059V468c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12V166.059h46.059c21.382 0 32.09-25.851 16.971-40.971l-86.059-86.059c-9.373-9.373-24.569-9.373-33.941 0l-86.059 86.059c-15.119 15.119-4.411 40.971 16.971 40.971H88z")
            span.package__label.package__label--shadow
            span.package__label
            +flaps()
View Compiled
*
*:after
*:before
  box-sizing border-box
  transform-style preserve-3d

body
  background hsl(180, 20%, 92%)
  min-height 100vh
  display grid
  place-items center
  perspective 100vmin
  overflow hidden

:root
  --packaged 0
  --steps 23
  --delay 0.2
  --speed 0.2
  // Colors
  --face-1 hsl(28, 41%, 57%)
  --face-2 hsl(29, 58%, 66%)
  --face-3 hsl(30, 69%, 70%)
  --face-4 hsl(31, 82%, 74%)
  --face-5 hsl(30, 72%, 70%)
  --face-6 hsl(21, 75%, 28%)
  --tape hsl(26, 37%, 51%)

.close
.open
  position fixed
  height 100vh
  width 100vw
  z-index 2
  transform scale(1) translate3d(0, 0, 50vmin)
  transition transform 0s calc(((var(--steps) + 2) * var(--delay)) * 1s)

.open
  transform scale(0) translate3d(0, 0, 50vmin)
  transition transform 0s 0s

#package:checked ~ .close
  transition transform 0s 0s
  transform scale(0) translate3d(0, 0, 50vmin)

#package:checked ~ .open
  transition transform 0s calc(((var(--steps) + 2) * var(--delay)) * 1s)
  transform scale(1) translate3d(0, 0, 50vmin)

input
  position fixed
  top 0
  left 0
  width 1px
  height 1px
  padding 0
  margin -1px
  overflow hidden
  clip rect(0, 0, 0, 0)
  white-space nowrap
  border-width 0

[for='one']
[for='two']
[for='three']
[for='four']
  position fixed
  top var(--top)
  right 1rem
  z-index 3

[for='one']
  --top 1rem
[for='two']
  --top calc(1rem + 49px)
[for='three']
  --top calc(1rem + 98px)
[for='four']
  --top calc(1rem + 147px)

#one:checked ~ .one
#two:checked ~ .two
#three:checked ~ .three
#four:checked ~ .four
  border-color hsl(10, 80%, 50%)

.size-label
  font-family sans-serif
  font-weight bold
  color hsl(0, 0%, 15%)
  height 44px
  width 44px
  display grid
  place-items center
  background hsl(0, 0%, 99%)
  border-radius 50%
  cursor pointer
  border 4px solid hsl(180, 20%, 62%)
  transform translate(0, calc(var(--y, 0) * 1%)) scale(var(--scale, 1))
  transition transform 0.1s

  &:hover
    --y -5

  &:active
    --y 2
    --scale 0.9

#one:checked ~ .scene .package__wrapper
  --height 10
  --width 20
  --depth 20
#two:checked ~ .scene .package__wrapper
  --height 20
  --width 20
  --depth 20
#three:checked ~ .scene .package__wrapper
  --height 20
  --width 30
  --depth 20
#four:checked ~ .scene .package__wrapper
  --height 30
  --width 20
  --depth 30

#package:checked ~ .scene
  .package__side--main > .package__flap--top:before
    --bg-step 9

#package:checked ~ .scene
  --packaged 1
  // Annoyingly we can't do a trick where we use the number of steps and reverse the order.
  /**
    * Handles all the steps of packaging up the box. Quite long winded.
    * 1. Start with package rotated so that all sides are flat
    * 2. Extra Side
    * 3. Then Tabbed Side
    * 4. Then Flipped Side and Tab
    * 5. Then go through the bottom flaps in order
    * 6. Tilt the box up.
    * 7. Close the top.
  */

  .package__side--extra
    --step 0

  .package__side--tabbed
    --step 1

  .package__side--tabbed:after
    --step 2

  .package__side--flipped
    --step 2

  // Bottom Flaps before the flip
  .package__side--extra > .package__flap--bottom
    --step 3
  .package__side--tabbed > .package__flap--bottom
    --step 4
  .package__side--main > .package__flap--bottom
    --step 5
  .package__side--flipped > .package__flap--bottom
    --step 6

  // Tape
  .package__tape--bottom
    --step 7

  // Move the package upright
  .package__wrapper
    --step 8
  .package
  .package__shadow
    --step 9

  // Load the content
  .package__icon--html
    --step 10
  .package__icon--css
    --step 11
  .package__icon--js
    --step 12

  // Top Flaps Last after a little gap for the content
  .package__side--extra > .package__flap--top
    --step 16
  .package__side--tabbed > .package__flap--top
    --step 17
  .package__side--main > .package__flap--top
    --step 18
  .package__side--flipped > .package__flap--top
    --step 19

  // Then tape the top
  .package__tape--top
    --step 20

  .package__branding
  .package__label
  .package__branding--shadow
  .package__label--shadow
    --step 21

  .package__label:after
    --step 22
  .package__label:before
    --step 23

.scene
  transform rotateX(-24deg) rotateY(-32deg) rotateX(90deg)

.package
.package__wrapper
.package__flap
.package__flap--top
.package__flap--bottom
.package__side
.package__side:after
.package__icon
.package__tape--top
.package__tape--bottom
.package__branding
.package__label
.package__label:after
.package__label:before
.package__shadow
.package__label--shadow
.package__branding--shadow
  --delay 0.2
  --speed 0.2
  transition transform calc(var(--speed, 0.2) * 1s) calc((var(--step, 1) * var(--delay, 1)) * 1s), opacity 0.1s calc(((var(--step, 1) * var(--delay, 1)) + ((var(--speed) - 0.1) * (1 - var(--packaged)))) * 1s), height calc(var(--speed, 0.2) * 1s), width calc(var(--speed, 0.2) * 1s)
  transition-timing-function ease-in-out

// Uncomment for instant scaling changes
// #one:focus ~ .scene
// #two:focus ~ .scene
// #three:focus ~ .scene
// #four:focus ~ .scene
//   .package
//   .package__wrapper
//   .package__flap
//   .package__flap--top
//   .package__flap--bottom
//   .package__side
//   .package__side:after
//   .package__icon
//   .package__tape--top
//   .package__tape--bottom
//   .package__branding
//   .package__label
//   .package__label:after
//   .package__label:before
//   .package__shadow
//   .package__label--shadow
//   .package__branding--shadow
//     transition none
//     transition-timing-function ease-in-out

// Transition steps for closing
.package__side--extra
  --step 23

.package__side--tabbed
  --step 22

.package__side--tabbed:after
  --step 21

.package__side--flipped
  --step 20

// Bottom Flaps before the flip
.package__side--extra > .package__flap--bottom
  --step 19
.package__side--tabbed > .package__flap--bottom
  --step 18
.package__side--main > .package__flap--bottom
  --step 17
.package__side--flipped > .package__flap--bottom
  --step 16

// Tape
.package__tape--bottom
  --step 15

// Move the package upright
.package__wrapper
  --step 14
.package
.package__shadow
  --step 13

// Load the content
.package__icon--html
  --step 8
.package__icon--css
  --step 7
.package__icon--js
  --step 6

// Top Flaps Last after a little gap for the content
.package__side--extra > .package__flap--top
  --step 5
.package__side--tabbed > .package__flap--top
  --step 4
.package__side--main > .package__flap--top
  --step 3
.package__side--flipped > .package__flap--top
  --step 2

// Then tape the top
.package__tape--top
  --step 1

.package__branding
.package__label
.package__label--shadow
.package__branding--shadow
  --step 0

// Don't need to erase these. Just move the label.
.package__label:after
  --step 5
.package__label:before
  --step 5


.package
  height calc(var(--depth) * 1vmin)
  width calc(var(--width) * 1vmin)
  // background hsla(280, 80%, 50%, 0.3)
  transform-origin 50% 0
  transform rotateX(calc((1 - var(--packaged, 0)) * 90deg))

  &__shadow
    background hsl(0, 0%, 35%)
    opacity 0.75
    position absolute
    height 99%
    width 99%
    top 0
    left 50%
    transform-origin 50% 0
    transform translate(-50%, 0) scaleY(var(--packaged))

  &__tape
    background var(--tape)
    height min(4vmin, 50%)
    width 94%
    left 50%
    position absolute
    transform-origin 0 50%
    transform translate3d(-50%, var(--offset-y), 2px) scaleX(var(--packaged, 0))

    &--bottom
      --offset-y 50%
      bottom 100%
    &--top
      --offset-y -50%
      top 100%

  &__direction
    display inline-flex
    align-items center
    font-family sans-serif
    font-weight bold
    font-size 1.75vmin
    transform rotate(180deg) translate3d(0, 0, 1px)
    position absolute
    top 0
    right 0
    padding 5%
    justify-content flex-end
    color hsl(0, 0%, 10%)
    backface-visibility hidden
    -webkit-backface-visibility hidden

    svg
      fill currentColor
      width 8%
      min-width 2vmin

  &__wrapper
    // --height 20
    // --width 30
    // --depth 20
    // background hsla(210, 80%, 50%, 0.3)
    transform translate3d(0, calc(((1 - var(--packaged, 0)) * var(--height)) * 1vmin), calc(var(--height) * -0.5vmin))

  &__label
    height 20%
    width 30%
    background hsl(0, 0%, 98%)
    position absolute
    right 10%
    bottom 20%
    border-radius 5%
    opacity var(--packaged)
    -webkit-backface-visibility hidden
    backface-visibility hidden
    transform rotate(180deg) translate3d(0, 0, calc((1 - (var(--packaged, 0))) * 5vmin))

    &--shadow
      transform rotate(180deg) translate3d(0, 0, 0) scale(var(--packaged))
      background hsl(0, 0%, 10%)

    &:after
    &:before
      content ''
      position absolute
      height 20%
      width var(--line-length, 70%)
      top var(--line, 20%)
      left 10%
      background hsl(0, 0%, 10%)
      transform-origin 0 50%
      transform scaleX(var(--packaged, 0))

    &:before
      --line 50%
      --line-length 40%

  &__branding
    height 30%
    position absolute
    bottom 10%
    left 10%
    transform rotate(-160deg) translate3d(0, 0, calc((1 - (var(--packaged, 0))) * 5vmin))
    opacity var(--packaged)
    -webkit-backface-visibility hidden
    backface-visibility hidden

    &--shadow
      transform rotate(-160deg) translate3d(0, 0, 0) scale(var(--packaged))
      filter brightness(0)
      opacity var(--packaged)

  &__icon
    --speed 1
    position absolute
    top 50%
    left 50%
    width 40%
    transform translate(-50%, -50%) translate3d(calc(var(--x, 0) * 1%), calc((((1 - var(--packaged,0)) * (var(--y, 0) * (max(var(--height), var(--depth), var(--width)))))) * -1vmin), calc(var(--z, 0) * 1vmin))
    opacity var(--packaged)

    &--js
      --x 60
      --y 1.4
      --z 0
      fill #F7DF1E
    &--html
      --x 0
      --y 1.6
      --z -3
      fill #E34F26
    &--css
      --x -50
      --y 1.2
      --z 3
      fill #1572B6

  &__content
    width calc(min(var(--height), var(--width)) * 1vmin)
    height calc(var(--height) * 1vmin)
    // background hsla(280, 80%, 50%, 0.5)
    position absolute
    left 50%
    bottom 50%
    transform-origin 50% 100%
    transform translate(-50%, 0) rotateX(-90deg) rotateY(45deg)

  &__flap
    width 99.5%
    height 49.5%
    background var(--face-4)
    position absolute
    left 50%

    &--bottom
      transform-origin 50% 100%
      bottom 100%
      transform translate(-50%, 0) rotateX(calc(var(--packaged, 0) * 90deg))

    &--top
      top 100%
      transform-origin 50% 0%
      transform translate(-50%, 0) rotateX(calc(var(--packaged, 0) * -90deg))


  &__side
    background 'hsla(%s, 30%, 30%, 0.3)' % var(--hue, 0)
    height calc(var(--height) * 1vmin)
    position absolute
    top 50%

    &--main > .package__flap--top:before
      --bg-step 13
      content ''
      height 100%
      width 100%
      position absolute
      transform rotateY(180deg)
      backface-visibility hidden
      -webkit-backface-visibility hidden
      background var(--face-2)
      opacity var(--packaged)
      transition opacity calc(var(--speed, 0.2) * 1s) calc((var(--bg-step, 1) * var(--delay, 1)) * 1s)
      transition-timing-function ease-in-out

    &--extra
    &--tabbed
      & > .package__flap--top
        top 99%
      & > .package__flap--bottom
        bottom 99%

    &--extra > .package__flap.package__flap--top
      background hsl(32, 76%, 70%)
    &--extra > .package__flap.package__flap--bottom
      background hsl(32, 76%, 74%)
    &--tabbed > .package__flap.package__flap--bottom
      background hsl(32, 72%, 72%)
    &--flipped > .package__flap.package__flap--bottom
      background hsl(32, 78%, 76%)
    &--main > .package__flap.package__flap--top
      background hsl(32, 78%, 72%)

    &--main
      --hue 2
      background var(--face-5)
      left 50%
      transform translate(-50%, -50%) rotateX(90deg) rotateY(0deg) translate3d(0, 0, calc(var(--depth) * 0.5vmin)) translate(0, 50%)
      width calc(var(--width) * 1vmin)


      & > .package__flap
        height calc(var(--depth) * 0.495vmin)

    &--tabbed
      --hue 90
      top 0
      left 100%
      background var(--face-2)
      width calc(var(--depth) * 1vmin)
      transform-origin 0% 50%
      transform rotateY(calc(var(--packaged, 0) * 90deg))

      & > .package__flap
        height calc(var(--width) * 0.495vmin)
        background var(--face-3)

      &:after
        content ''
        position absolute
        left 99.5%
        top 0
        height 100%
        width 10%
        background var(--face-3)
        $clip = polygon(0 0%, 100% 20%, 100% 80%, 0 100%)
        clip-path $clip
        -webkit-clip-path $clip
        transform-origin 0% 50%
        transform rotateY(calc(var(--packaged, 0) * 91deg))

    &--extra
      --hue 120
      right 100%
      top 0
      background var(--face-2)
      width calc(var(--depth) * 1vmin)
      transform-origin 100% 50%
      transform rotateY(calc(var(--packaged, 0) * -90deg))

      & > .package__flap
        height calc(var(--width) * 0.495vmin)
        background var(--face-3)

    &--flipped
      --hue 320
      background var(--face-3)
      top 0
      right 100%
      width calc(var(--width) * 1vmin)
      transform-origin 100% 50%
      transform rotateY(calc(var(--packaged, 0) * -90deg))

      & > .package__flap
        height calc(var(--depth) * 0.495vmin)
        background var(--face-4)
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.