mixin cube(className)
.cube(class=className)
- let s = 0
while s < 6
.cube__side
- s++
input#toast(type='checkbox')
.rotater.rotater--top
.rotater.rotater--right
.rotater.rotater--bottom
.rotater.rotater--left
.scene
.plane
+cube('table')
.toaster__shadow
label.toaster(for='toast')
.toast__wrapper
.cube.toast
.cube__side
.cube__side
.toast__face
.eyes
.eye.eye--left
.eye.eye--right
.mouth
.cube__side
.cube__side
.cube__side
.cube__side
.toaster__toaster
+cube('toaster__leg toaster__leg--tl')
+cube('toaster__leg toaster__leg--tr')
+cube('toaster__leg toaster__leg--br')
+cube('toaster__leg toaster__leg--bl')
.cube.toaster__body
.cube__side
img(src="https://assets.codepen.io/605876/bear-with-cap.svg")
.toaster__face
.eyes
.eye.eye--left
.eye.eye--right
.mouth
.cube__side
.cube__side
+cube('toaster__handle')
.cube__side
.cube__side
.cube__side
label.cloak(for='toast')
View Compiled
*
*:after
*:before
box-sizing border-box
body
min-height 100vh
background hsl(195, 20%, 70%)
overflow hidden
margin 0
padding 0
:root
--toaster-width 18
--toaster-height 10
--toaster-depth 12
--toast-depth 1
--eye-size 1.75vmin
--feature hsl(0, 0%, 5%)
--shadow hsla(0, 0%, 25%, 1)
--cloth-color-one hsla(320, 60%, 50%, 0.65)
--speed 1
--transition 0.25
--handle hsl(0, 0%, 20%)
--shade-one hsl(0, 0%, 85%)
--shade-two hsl(0, 0%, 75%)
--shade-three hsl(0, 0%, 65%)
--shine hsla(0, 0%, 100%, 0.5)
[type='checkbox']
position absolute
left 100%
opacity 0
height 0
width 0
.rotater
position fixed
height 10vmin
width 100vmax
top 0
left 0
z-index 2
&:hover
& ~ .scene .plane
animation spin-y 1s infinite linear
&--bottom
transform translate(0, calc(100vh - 10vmin))
&:hover
& ~ .scene .plane
animation spin-y 1s infinite reverse linear
&--left
transform rotate(90deg)
transform-origin 0 100%
&:hover
& ~ .scene .plane
animation spin-x 1s infinite reverse linear
&--right
transform rotate(90deg) translate(0, calc(-100vw + 10vmin))
transform-origin 0 100%
&:hover
& ~ .scene .plane
animation spin-x 1s infinite linear
.scene
perspective 800px
transform-style preserve-3d
height 100vh
width 100vw
display flex
align-items center
justify-content center
.plane
height 20vmin
width 40vmin
transform-style preserve-3d
transform rotateX(-24deg) rotateY(-24deg) rotateX(90deg)
// transform rotateX(-0deg) rotateY(-0deg) rotateX(90deg)
@keyframes spin-x
to
transform rotateX(-24deg) rotateY(-24deg) rotateX(90deg) rotateZ(-360deg)
@keyframes spin-y
to
transform rotateX(-24deg) rotateY(-24deg) rotateX(90deg) rotateX(360deg)
.cube
--width 15
--height 10
--depth 4
height calc(var(--depth) * 1vmin)
width calc(var(--width) * 1vmin)
transform-style preserve-3d
position absolute
font-size 1rem
animation spin 1s infinite linear
transform translate3d(0, 0, 5vmin)
& > div:nth-of-type(1)
height calc(var(--height) * 1vmin)
width 100%
transform-origin 50% 50%
transform rotateX(-90deg)
position absolute
top 50%
left 50%
transform translate(-50%, -50%) rotateX(-90deg) translate3d(0, 0, calc((var(--depth) / 2) * 1vmin))
& > div:nth-of-type(2)
height calc(var(--height) * 1vmin)
width 100%
transform-origin 50% 50%
transform translate(-50%, -50%) rotateX(-90deg) rotateY(180deg) translate3d(0, 0, calc((var(--depth) / 2) * 1vmin))
position absolute
top 50%
left 50%
& > div:nth-of-type(3)
height calc(var(--height) * 1vmin)
width calc(var(--depth) * 1vmin)
transform translate(-50%, -50%) rotateX(-90deg) rotateY(90deg) translate3d(0, 0, calc((var(--width) / 2) * 1vmin))
position absolute
top 50%
left 50%
& > div:nth-of-type(4)
height calc(var(--height) * 1vmin)
width calc(var(--depth) * 1vmin)
transform translate(-50%, -50%) rotateX(-90deg) rotateY(-90deg) translate3d(0, 0, calc((var(--width) / 2) * 1vmin))
position absolute
top 50%
left 50%
& > div:nth-of-type(5)
height calc(var(--depth) * 1vmin)
width calc(var(--width) * 1vmin)
transform translate(-50%, -50%) translate3d(0, 0, calc((var(--height) / 2) * 1vmin))
position absolute
top 50%
left 50%
& > div:nth-of-type(6)
height calc(var(--depth) * 1vmin)
width calc(var(--width) * 1vmin)
transform translate(-50%, -50%) translate3d(0, 0, calc((var(--height) / 2) * -1vmin)) rotateX(180deg)
position absolute
top 50%
left 50%
.table
--height 2
--width 40
--depth 30
position absolute
top 50%
left 50%
transform translate(-50%, -50%)
div
background repeating-linear-gradient(90deg, var(--cloth-color-one) 2px, transparent 5px 9px, var(--cloth-color-one) 10px),
repeating-linear-gradient(0deg, var(--cloth-color-one) 5px, transparent 6px 12px, var(--cloth-color-one) 15px), hsl(0, 0%, 90%)
&:nth-of-type(3)
filter brightness(0.75)
&:nth-of-type(5)
filter brightness(0.95)
img
position absolute
height 20%
right 0.5vmin
bottom 0.5vmin
mix-blend-mode overlay
filter grayscale(1)
:checked ~ .scene
.toaster
animation none
.mouth
background var(--feature)
border 0
&:after
content ''
&__handle
transform translate3d(-50%, calc(var(--toaster-height) * 0.4vmin), calc(var(--height) * 0.5vmin))
animation switch calc(var(--speed) * 1s) calc(var(--transition) * 1s) infinite ease-in-out
.toast__wrapper
transform translate3d(-50%, -50%, calc(var(--toaster-height) * 0.3vmin))
animation jump calc(var(--speed) * 1s) calc(var(--transition) * 1s) infinite ease-in-out
.toast
animation flip calc(var(--speed) * 2s) calc(var(--transition) * 1s) infinite ease-in-out
// .toaster__body
// animation squish calc(var(--speed) * 1s) calc(var(--transition) * 1s) infinite ease-in-out
:checked ~ .cloak
height 100vh
width 100vw
position absolute
top 0
left 0
.toaster
height calc(var(--toaster-depth) * 1vmin)
width calc(var(--toaster-width) * 1vmin)
top 50%
left 50%
position absolute
transform translate3d(-50%, -50%, 1vmin)
transform-style preserve-3d
&:hover
animation rock calc(var(--speed) * 0.1s) infinite
.mouth
border 0
&:before
content ''
&__shadow
height calc(var(--toaster-depth) * 1vmin)
width calc(var(--toaster-width) * 1vmin)
top 50%
left 50%
position absolute
transform translate3d(-50%, -50%, 1vmin)
background var(--shadow)
filter blur(10px)
&__leg
--width 1
--depth 1
--height 1
position absolute
transform translate3d(0, 0, 0.5vmin)
--perimeter 5
&--tr
top calc(var(--perimeter) * 1%)
left calc(var(--perimeter) * 1%)
&--tl
top calc(var(--perimeter) * 1%)
right calc(var(--perimeter) * 1%)
&--br
bottom calc(var(--perimeter) * 1%)
right calc(var(--perimeter) * 1%)
&--bl
bottom calc(var(--perimeter) * 1%)
left calc(var(--perimeter) * 1%)
div
background var(--feature)
&__body
--depth var(--toaster-depth)
--width var(--toaster-width)
--height var(--toaster-height)
position absolute
top 50%
left 50%
transform translate3d(-50%, -50%, 6vmin)
& > div:nth-of-type(1)
background linear-gradient(120deg, transparent 10%, var(--shine) 10% 20%, transparent 20% 25%, var(--shine) 25% 30%, transparent 30%), var(--shade-one)
& > div:nth-of-type(2)
background var(--shade-one)
& > div:nth-of-type(3)
background var(--shade-three)
& > div:nth-of-type(4)
background var(--shade-three)
& > div:nth-of-type(5)
background var(--shade-two)
& > div:nth-of-type(6)
background var(--shade-two)
& > div:nth-of-type(3)
transform-style preserve-3d
// handle slot
&:after
content ''
position absolute
width 8%
height 50%
background hsl(0, 0%, 40%)
transform translate(-50%, 0)
left 50%
top 10%
// bread slot
& > div:nth-of-type(5):after
content ''
height 30%
width 65%
background hsl(0, 0%, 15%)
top 50%
left 50%
position absolute
transform translate(-50%, -50%)
&__handle
transform-style preserve-3d
--height 1
--width 3
--depth 1
position absolute
top 10%
left 50%
transform translate3d(-50%, -50%, calc(var(--height) * 0.5vmin))
background-color var(--handle)
transition transform calc(var(--transition) * 1s) ease
& > div
background-color var(--handle)
&__face
height 25%
width 50%
position absolute
top 50%
left 50%
transform translate(-50%, -50%)
&__toaster
&__body
&__leg
transform-style preserve-3d
&__toaster
height calc(var(--toaster-depth) * 1vmin)
width calc(var(--toaster-width) * 1vmin)
top 50%
left 50%
position absolute
transform translate3d(-50%, -50%, 0)
.toast
--depth var(--toast-depth)
--height var(--toaster-height)
--width var(--toaster-height)
position absolute
top 50%
left 50%
transform translate3d(-50%, -50%, calc(var(--toaster-height) * 0.5vmin))
&__face
height 30%
width 80%
top 50%
left 50%
position absolute
transform translate(-50%, -50%)
& > div
background hsl(30, 40%, 80%)
&:nth-of-type(1)
&:nth-of-type(2)
border 0.25vmin solid hsl(30, 80%, 40%)
&:nth-of-type(3)
&:nth-of-type(4)
&:nth-of-type(5)
&:nth-of-type(6)
background hsl(30, 80%, 40%)
// Keyframes that need to match up on the double
// Bread jumps out and flips alternate ways
@keyframes jump
0%, 100%
transform translate3d(-50%, -50%, 3vmin)
5%
transform translate3d(-50%, -50%, 2vmin)
50%
transform translate3d(-50%, -50%, 20vmin)
@keyframes switch
0%, 100%
transform translate3d(-50%, calc(var(--toaster-height) * 0.4vmin), calc(var(--height) * 0.5vmin))
5%
transform translate3d(-50%, calc(var(--toaster-height) * 0.45vmin), calc(var(--height) * 0.5vmin))
50%
transform translate3d(-50%, -50%, calc(var(--height) * 0.5vmin))
@keyframes flip
0%, 10%
transform translate3d(-50%, -50%, calc(var(--toaster-height) * 0.5vmin)) rotateX(0deg) rotateZ(0deg)
40%, 60%
transform translate3d(-50%, -50%, calc(var(--toaster-height) * 0.5vmin)) rotateX(360deg) rotateZ(0deg)
90%, 100%
transform translate3d(-50%, -50%, calc(var(--toaster-height) * 0.5vmin)) rotateX(360deg) rotateZ(360deg)
// Toaster squish and then eject
@keyframes rock
0, 100%
transform translate3d(-50%, -50%, 1vmin) rotateY(1deg)
50%
transform translate3d(-50%, -50%, 1vmin) rotateY(-1deg)
@keyframes squish
0%, 100%
transform translate3d(-50%, -50%, 6vmin) scaleZ(1)
5%
transform translate3d(-50%, -50%, 6vmin) scaleZ(1.02)
50%
transform translate3d(-50%, -50%, 6vmin) scaleZ(0.98)
.toast__wrapper
height calc(var(--toast-depth) * 1vmin)
width calc(var(--toaster-height) * 1vmin)
transform-style preserve-3d
position absolute
top 50%
left 50%
transform translate3d(-50%, -50%, 6vmin)
transition transform calc(var(--transition) * 1s) ease
// animation jump 1s infinite ease-in-out
.eye
position absolute
height var(--eye-size)
width var(--eye-size)
border-radius 50%
background #000
top 0
animation blink 5s infinite
&:after
content ''
height 25%
width 25%
position absolute
top 10%
left 10%
border-radius 50%
background hsl(0, 0%, 100%)
&--left
left 0
&--right
right 0
@keyframes blink
0%, 49%, 51%, 100%
transform scaleY(1)
50%
transform scaleY(0)
.mouth
height 2.5vmin
width 2.5vmin
position absolute
bottom 0
left 50%
transform translate(-50%, 0)
clip-path inset(50% 0 0 0)
clip-path inset(50% 0 0 0)
background #000
border-radius 50%
overflow hidden
border 0.5vmin solid #000
background transparent
&:after
// content ''
height 60%
width 60%
position absolute
top 75%
left 50%
background red
border-radius 50%
&:before
height 50%
width 50%
border-radius 50%
background #000
top 50%
position absolute
left 50%
transform translate(-50%, 0)
View Compiled
// JavaScript is toast in this demo 😅
// Click the toaster for bread flips!
// Hover page edges to rotate!
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.