- const randomInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min
- const hue = randomInRange(0, 360)
label(for='toggle') Turn shading off
input#toggle(type='checkbox')
.cauldron(style=`--potion-hue: ${hue}`)
  .cauldron__opening
    - let b = 0
    while b < 25
      - const speed = randomInRange(5, 10)
      - const scale = randomInRange(50, 150) / 100
      - const delay = randomInRange(0, 10)
      - const x = randomInRange(25, 75)
      .cauldron__bubble(style=`--delay: ${delay}; --scale: ${scale}; --speed: ${speed}; --x: ${x}`)
      - b++
  .cauldron__handle.cauldron__handle--left
  .cauldron__handle.cauldron__handle--right
  .cauldron__foot.cauldron__foot--left
  .cauldron__foot.cauldron__foot--right
  .cauldron__eye.cauldron__eye--left
  .cauldron__eye.cauldron__eye--right
  .cauldron__mouth
View Compiled
*
  box-sizing border-box
  transition background .15s ease, box-shadow .15s ease

:root
  --cauldron-hue 34
  --potion-hue 120
  --size 200
  --bg #111
  
label
  font-weight bold
  color hsl(0, 0%, 99%)
  margin-bottom 0.5rem
  
[type='checkbox']
  margin-bottom 2rem
  
:checked ~ .cauldron
  background var(--cauldron-color)

  .cauldron__opening
    background var(--potion-color)
    box-shadow none

  &:after
  &:before
    background var(--potion-color)
    box-shadow none

  &:before
    background transparent

  .cauldron__handle
    background var(--rim-color)

  .cauldron__eye
    box-shadow none

  .cauldron__mouth
    box-shadow none

  .cauldron__foot
    background var(--inner-rim-color)

  .cauldron__bubble
    background var(--potion-color)

  

body
  align-items center
  display flex
  justify-content center
  min-height 100vh
  background var(--bg)
  flex-direction column

.cauldron
  --rim-color 'hsl(%s, 100%, 60%)' % (var(--cauldron-hue))
  --inner-rim-color 'hsl(%s, 100%, 25%)' % (var(--cauldron-hue))
  --potion-color 'hsl(%s, 100%, 50%)' % (var(--potion-hue))
  --cauldron-color 'hsl(%s, 100%, 50%)' % (var(--cauldron-hue))
  --darkness 'hsl(%s, 100%, 10%)' % (var(--cauldron-hue))
  --lightness 'hsl(%s, 100%, 85%)' % (var(--cauldron-hue))
  --potion-stain-light 'hsl(%s, 100%, 70%)' % (var(--potion-hue))
  --potion-stain-dark 'hsl(%s, 100%, 30%)' % (var(--potion-hue))
  border-radius 100%
  height calc(var(--size) * 1px)
  width calc(var(--size) * 1px)
  background radial-gradient(25% 25% at 25% 55%, var(--rim-color), transparent), radial-gradient(100% 100% at -2% 50%, transparent, transparent 92%, var(--cauldron-color)), radial-gradient(100% 100% at -5% 50%, transparent, transparent 80%, var(--darkness)), linear-gradient(310deg, var(--inner-rim-color) 25%, transparent), var(--cauldron-color)
  position relative
  
  &__opening
    width 100%
    position absolute
    top 0
    left 0
    height 35%
    background linear-gradient(90deg, transparent, var(--potion-stain-dark)), var(--potion-color)
    border calc(var(--size) * 0.05px) solid var(--rim-color)
    box-shadow 0 0px calc(var(--size) * 0.05px) calc(var(--size) * 0.005px) var(--rim-color) inset,
               0 calc(var(--size) * 0.025px) 0 calc(var(--size) * 0.025px) var(--inner-rim-color) inset,
               0 10px 20px 0px var(--darkness),
               0 10px 20px -10px var(--inner-rim-color)
    border-radius 100%

    &:after
      content ''
      position absolute
      background linear-gradient(90deg, transparent, var(--potion-stain-dark), transparent, var(--potion-stain-light), transparent, var(--potion-stain-dark), transparent)
      border-radius 100%
      top 8px
      right 0
      bottom 4px
      left 0

    &:before
      content ''
      position absolute
      box-shadow 0 0 calc(var(--size) * 0.025px) 0 var(--darkness) inset,
                 0 -1px calc(var(--size) * 0.015px) 0px var(--darkness) inset,
                 0 2px calc(var(--size) * 0.015px) 0px var(--lightness) inset,
                 0 0 calc(var(--size) * 0.075px) calc(var(--size) * 0.05px) var(--rim-color) inset
      border-radius 100%
      top calc(var(--size) * -0.05px)
      right calc(var(--size) * -0.05px)
      bottom calc(var(--size) * -0.05px)
      left calc(var(--size) * -0.05px)

  &__handle
    height calc(var(--size) * 0.3px)
    width calc(var(--size) * 0.3px)
    position absolute
    // border calc(var(--size) * 0.075px) solid var(--rim-color)
    background linear-gradient(0deg, var(--darkness), transparent), radial-gradient(100% 100% at 50% 50%, var(--inner-rim-color), transparent), var(--rim-color)
    border-radius 100%
    top 30%
    z-index -1

    &:after
      content ''
      background var(--bg)
      height 50%
      width 50%
      position absolute
      top 50%
      left 50%
      transform translate(-50%, -50%)
      border-radius 100%

    &--left
      left -14%

    &--right
      right -14%

  &__foot
    background var(--inner-rim-color)
    position absolute
    z-index -1
    height calc(var(--size) * 0.3px)
    width calc(var(--size) * 0.3px)
    bottom -5%
    border-radius 200% 0 200% 50%/200% 0 200% 50%

    &--left
      left 10%
      background radial-gradient(110% 110% at 25% 50%, transparent, var(--darkness) 75%), var(--inner-rim-color)

    &--right
      right 10%
      background radial-gradient(110% 110% at 25% 50%, transparent, var(--darkness)), var(--inner-rim-color)
      transform rotateY(180deg)


  &__bubble
    height calc(var(--size) * .2px)
    width calc(var(--size) * .2px)
    position absolute
    border-radius 100%
    top 0
    left calc(var(--x) * 1%)
    border 1px solid var(--potion-stain-light)
    background radial-gradient(100% 115% at 25% 25%, #fff, transparent 33%), radial-gradient(15% 15% at 75% 75%, var(--cauldron-color), transparent), radial-gradient(100% 100% at 50% 25%, transparent, var(--potion-color) 98%)
    pointer-events none
    animation rise calc(var(--speed) * 1s) calc(var(--delay) * -1s) infinite ease

  &__mouth
    position absolute
    top 60%
    left 50%
    transform translate(-50%, 0)
    height calc(var(--size) * .1px)
    width calc(var(--size) * .15px)
    border-radius 100%
    border-bottom 4px solid black
    box-shadow 0px 1px 0 0 var(--lightness)
    -webkit-clip-path inset(50% 0 -10% 0)
    clip-path inset(50% 0 -10% 0)

  &__eye
    height calc(var(--size) * .075px)
    width calc(var(--size) * .075px)
    background #111
    border-radius 100%
    position absolute
    top 50%
    box-shadow 1px 1px 1px 0px var(--lightness), -1px -1px 1px 0 var(--inner-rim-color)
    animation blink 4s infinite linear both

    &--left
      left 20%

    &--right
      right 20%


@keyframes rise
  0%
    transform scale(0) translate(-50%, 0)

  100%
    transform scale(var(--scale)) translate(-50%, -50vh)
    opacity 0

@keyframes blink
  9%
    transform scaleY(1)
  10%
    transform scaleY(0)
  11%
    transform scaleY(1)
  12%
    transform scaleY(0)
  13%
    transform scaleY(1)
View Compiled
/**
  * I take no credit for the brilliant work of Gal Shir:
  * https://dribbble.com/shots/7664202-Cauldron
  * This is purely a recreation with CSS to practice lighting etc.
*/
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.