Originally constructed a similar plugin with LESS for a project here. Switched over to Sass for fun.
A Pen by Jake Albaugh on CodePen.
| .container | |
| <!-- "start" and "end" variables in scss --> | |
| - (3..12).each do |i| | |
| %div{:class => "stage-viewport s#{i}"} | |
| .stage | |
| .spinner | |
| - (1..i).each do | |
| .facade | |
Originally constructed a similar plugin with LESS for a project here. Switched over to Sass for fun.
A Pen by Jake Albaugh on CodePen.
| /* | |
| * the following vars get plugged into the mixin. | |
| */ | |
| // start and end values of .facade children count | |
| $start: 3; $end: 12; | |
| // width and height of facades | |
| $width: 40px; $height: 60px; | |
| // spacing between stage-viewports / 2 (half each side) | |
| $spacing: 8px / 2; | |
| // speed of the animation | |
| $speed: 4s; | |
| body { | |
| background: #222; | |
| margin: 0; | |
| } | |
| .container { | |
| position: absolute; | |
| top: 50%; left: 50%; | |
| transform: translateY(-50%) translateX(-50%); | |
| width: 100%; | |
| text-align: center; | |
| min-width: ( | |
| ($width * 1.125) + | |
| ($spacing * 2) | |
| ) * ($end - $start + 2); | |
| } | |
| /* | |
| * mixin takes face count, width, height, | |
| * and show_viewport (boolean) | |
| */ | |
| @mixin stage-viewport( | |
| $face_count: 3, | |
| $size_w: 40px, | |
| $size_h: 40px, | |
| $show_viewport: false, | |
| $speed: 6s | |
| ) { | |
| $perspective_factor: $size_w * 1.5; | |
| /* | |
| * only really used for this code, may not be necessary in development. | |
| */ | |
| display: inline-block; | |
| width: $size_w * 1.125; | |
| height: $size_h * 1.125; | |
| position: relative; | |
| // uncomment overflow to see cropped result | |
| //overflow: hidden; | |
| margin: 0px $spacing; | |
| @if ($show_viewport == true) { | |
| &:after { | |
| // viewport outline | |
| content: ''; | |
| position: absolute; | |
| top: 0; bottom: 0; left: 0; right: 0; | |
| box-shadow: inset 0px 0px 0px 2px rgba(255,255,255,0.3); | |
| } | |
| } | |
| .stage { | |
| perspective: $perspective_factor * $face_count; | |
| display: inline-block; | |
| width: $size_w; | |
| height: $size_h; | |
| position: absolute; | |
| top: 50%; left: 50%; | |
| perspective-origin: 50% 50%; | |
| transform: translateY(-50%) translateX(-50%); | |
| } | |
| /* | |
| * spinning them. | |
| */ | |
| .spinner { | |
| animation-name: spinner; | |
| animation-timing-function: linear; | |
| animation-iteration-count: infinite; | |
| animation-duration: $speed; | |
| transform-style: preserve-3d; | |
| transform-origin: 50% 50%; | |
| position: absolute; | |
| top: 0; right: 0; bottom: 0; left: 0; | |
| } | |
| .facade { | |
| display: block; | |
| position: absolute; | |
| width: $size_w; | |
| height: $size_h; | |
| &::after { | |
| // numbers | |
| color: rgba(255,255,255,0.6); | |
| line-height: 1; | |
| font-size: $size_h/4; | |
| font-weight: 200; | |
| font-family: helvetica, arial, sans-serif; | |
| position: absolute; | |
| top: 50%; left: 50%; | |
| transform: translateX(-50%) translateY(-50%); | |
| } | |
| /* | |
| * translateZ = apothem | |
| * distance from polygon center to facade center | |
| * apothem = facade_height / ( 2 * tangent(180 / facade_count) ) | |
| */ | |
| $apothem: ($size_h / ( 2 * tan(180deg / $face_count) )); | |
| @for $i from 1 through $face_count { | |
| $ratio: $i / $face_count; | |
| $zero_ratio: ($i - 1) / $face_count; | |
| $x: $zero_ratio * 360; | |
| &:nth-child(#{$i}) { | |
| transform: rotateX($x+deg) translateZ($apothem); | |
| background-color: hsla((360 * $zero_ratio), 50%, 50%, 0.8); | |
| &::after { | |
| content: '#{$i}'; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| @for $i from $start through $end { | |
| .stage-viewport.s#{$i} { | |
| @include stage-viewport( | |
| /* | |
| * OPTIONS: | |
| * $face_count, $size_w, $size_h, $show_viewport, $speed | |
| */ | |
| $face_count: $i, | |
| $size_w: $width, | |
| $size_h: $height, | |
| $show_viewport: false, | |
| $speed: $speed | |
| ); | |
| } | |
| } | |
| @keyframes spinner { | |
| 0% { transform: rotateX(0deg); } | |
| 20% { transform: rotateX(0deg); } | |
| 100% { transform: rotateX(-360deg); } | |
| } |