Skip to content
CoDdleCoDoodle home
UI DoodlesBeginnerHTML + CSS

Sleepy Toggle

A chunky little dark-mode switch slides from sunshine to moonlight with a sleepy face tucked inside the knob. It blinks, yawns, and still somehow remembers to be useful.

← you, in 25 minutes.

what you'll build

Here's the plan

A chunky cream dark-mode toggle drawn with plain divs and CSS only: navy outline, soft ground shadow, sleepy face knob, sunshine side, moon side, tiny stars, and one plus-shaped sparkle. The finished switch rests, slides, blinks, yawns, and fades in a soft night tint when the knob reaches the moon.

You’ll learn

  • Building a pure CSS UI doodle from a wrapper, track, knob, and tiny props
  • Using border-radius, overlap, and z-index to draw a sun, crescent moon, and face
  • Timing one long toggle loop with holds so the motion feels calm instead of rushed
  • Animating transformed face details without losing their translateX(-50%) alignment
Skill level
Beginner
Time
~25 min
Tools
Just a browser
Code type
HTML + CSS
Lines
~220

the steps

Build it, one change at a time

  1. Shape the chunky switch

    Start with the wrapper, a soft navy oval shadow, and one big cream pill track. The track gets its chunky border and hidden overflow now, so later props can live inside the switch without spilling out.

    <div class="st-wrap">
      <div class="st-shadow"></div>
      <div class="st-track"></div>
    </div>
    
    .st-wrap {
      position: relative;
      width: 240px;
      height: 180px;
    }
    .st-shadow {
      position: absolute;
      left: 50%;
      bottom: 18px;
      transform: translateX(-50%);
      width: 170px;
      height: 22px;
      background: #2B3A55;
      border-radius: 50%;
      opacity: 0.14;
    }
    .st-track {
      position: absolute;
      left: 50%;
      top: 40px;
      transform: translateX(-50%);
      width: 200px;
      height: 92px;
      background: #FFFDF7;
      border: 6px solid #2B3A55;
      border-radius: 999px;
      box-sizing: border-box;
      overflow: hidden;
    }
    

    a pill switch with excellent nap potential.

  2. Add the sleepy knob

    Drop a round cream knob inside the track, then give it flat sleepy eyes, coral blush, and a tiny oval mouth. The mouth already uses translateX(-50%) with scaleY, which matters when we animate the yawn later.

        <div class="st-knob">
          <div class="st-eye st-eye-left"></div>
          <div class="st-eye st-eye-right"></div>
          <div class="st-blush st-blush-left"></div>
          <div class="st-blush st-blush-right"></div>
          <div class="st-mouth"></div>
        </div>
    
    .st-knob {
      position: absolute;
      left: 10px;
      top: 4px;
      width: 72px;
      height: 72px;
      background: #FFFDF7;
      border: 6px solid #2B3A55;
      border-radius: 50%;
      box-sizing: border-box;
      z-index: 3;
    }
    .st-eye {
      position: absolute;
      top: 26px;
      width: 14px;
      height: 5px;
      background: #2B3A55;
      border-radius: 999px;
      transform-origin: center;
    }
    .st-eye-left { left: 10px; }
    .st-eye-right { right: 10px; }
    .st-blush {
      position: absolute;
      top: 39px;
      width: 10px;
      height: 8px;
      background: #FFB3AD;
      border-radius: 50%;
      opacity: 0.86;
    }
    .st-blush-left { left: 12px; }
    .st-blush-right { right: 12px; }
    .st-mouth {
      position: absolute;
      top: 41px;
      left: 50%;
      transform: translateX(-50%) scaleY(0.45);
      width: 10px;
      height: 9px;
      background: #2B3A55;
      border-radius: 50%;
      transform-origin: center;
    }
    

    the knob is awake enough to be sleepy.

  3. Set the sun and moon scene

    Now tuck a sunshine disc on the left, a crescent moon on the right, and two little star dots inside the track. The sparkle sits outside the pill so the switch feels like a tiny CoDoodle character instead of a plain settings control.

        <div class="st-night"></div>
        <div class="st-sun"></div>
        <div class="st-moon"></div>
        <div class="st-star st-star-one"></div>
        <div class="st-star st-star-two"></div>
      </div>
      <div class="st-sparkle"></div>
    
    .st-night {
      position: absolute;
      inset: 0;
      background: #6FA8FF;
      opacity: 0;
      z-index: 1;
    }
    .st-sun {
      position: absolute;
      left: 25px;
      top: 26px;
      width: 34px;
      height: 34px;
      background: #FFD84D;
      border: 4px solid #2B3A55;
      border-radius: 50%;
      box-sizing: border-box;
      z-index: 2;
    }
    .st-moon {
      position: absolute;
      right: 25px;
      top: 24px;
      width: 38px;
      height: 38px;
      background: #6FA8FF;
      border: 4px solid #2B3A55;
      border-radius: 50%;
      box-sizing: border-box;
      z-index: 2;
    }
    .st-moon::after {
      content: "";
      position: absolute;
      right: -5px;
      top: 2px;
      width: 30px;
      height: 30px;
      background: #FFFDF7;
      border-radius: 50%;
    }
    .st-star {
      position: absolute;
      width: 7px;
      height: 7px;
      background: #FFD84D;
      border-radius: 50%;
      z-index: 2;
    }
    .st-star-one {
      right: 62px;
      top: 20px;
    }
    .st-star-two {
      right: 45px;
      bottom: 22px;
      width: 5px;
      height: 5px;
    }
    .st-sparkle {
      position: absolute;
      top: 24px;
      right: 12px;
      width: 18px;
      height: 18px;
    }
    .st-sparkle::before,
    .st-sparkle::after {
      content: "";
      position: absolute;
      background: #FFD84D;
      border-radius: 2px;
    }
    .st-sparkle::before {
      left: 50%;
      top: 0;
      transform: translateX(-50%);
      width: 4px;
      height: 18px;
    }
    .st-sparkle::after {
      top: 50%;
      left: 0;
      transform: translateY(-50%);
      width: 18px;
      height: 4px;
    }
    

    sun on one side, moon on the other, one sparkle supervising.

  4. Make it slide and yawn

    The final pass runs one seven-second loop: rest on sunshine, slide to moonlight, rest, then slide back. The eye blink stays open most of the time, the mouth keeps translateX(-50%) in every keyframe, and the night tint fades in only while the knob is on the moon side.

    .st-knob {
      transform-origin: center;
      animation: st-slide 7s ease-in-out infinite;
    }
    .st-eye {
      animation: st-blink 7s ease-in-out infinite;
    }
    .st-mouth {
      animation: st-yawn 7s ease-in-out infinite;
    }
    .st-night {
      animation: st-night-tint 7s ease-in-out infinite;
    }
    .st-sparkle {
      transform-origin: center;
      animation: st-twinkle 2.8s ease-in-out infinite;
    }
    @keyframes st-slide {
      0%, 18% { transform: translateX(0); }
      36%, 58% { transform: translateX(96px); }
      78%, 100% { transform: translateX(0); }
    }
    @keyframes st-blink {
      0%, 13%, 16%, 44%, 47%, 68%, 71%, 100% { transform: scaleY(1); }
      14.5%, 45.5%, 69.5% { transform: scaleY(0.14); }
    }
    @keyframes st-yawn {
      0%, 40%, 58%, 100% { transform: translateX(-50%) scaleY(0.45); }
      49% { transform: translateX(-50%) scaleY(1.55); }
    }
    @keyframes st-night-tint {
      0%, 28%, 82%, 100% { opacity: 0; }
      38%, 62% { opacity: 0.28; }
    }
    @keyframes st-twinkle {
      0%, 100% { opacity: 0.5; transform: scale(0.82) rotate(0deg); }
      50% { opacity: 1; transform: scale(1.12) rotate(8deg); }
    }
    

    a sleepy little switch doing the night shift.

the complete code

Everything, in one place

Skipped straight to the end? Welcome. Copy the whole thing, download it, or open it in the Playground to start remixing.

<div class="st-wrap">
  <div class="st-shadow"></div>
  <div class="st-track">
    <div class="st-night"></div>
    <div class="st-sun"></div>
    <div class="st-moon"></div>
    <div class="st-star st-star-one"></div>
    <div class="st-star st-star-two"></div>
    <div class="st-knob">
      <div class="st-eye st-eye-left"></div>
      <div class="st-eye st-eye-right"></div>
      <div class="st-blush st-blush-left"></div>
      <div class="st-blush st-blush-right"></div>
      <div class="st-mouth"></div>
    </div>
  </div>
  <div class="st-sparkle"></div>
</div>
Open in Playground

tips & gotchas

Mistakes we actually made

I compute the knob's travel from the track's inner width: 188px inside the 6px borders, minus two 10px margins and the 72px knob, gives 96px.

I put the night tint behind the sun, moon, stars, and knob so it changes the mood without muddying the face.

I leave the blink open for most of the 7s loop, because too many squashes make the knob look nervous instead of sleepy.

I repeat translateX(-50%) in the yawn keyframes, because transform animations replace the whole transform value.

make it yours

Remix it

  • Change the faceeasy

    Swap the sleepy bars for dot eyes, a tiny smile, or a surprised yawn.

  • Add tiny rayseasy

    Use pseudo-elements or small div dots around the sun while keeping the palette simple.

  • Make it tappablemedium

    Turn the loop into a real button state and move the knob with a class instead of keyframes.

  • Build a weather rowmedium

    Duplicate the track into smaller switches for rain, wind, and sparkle settings.

challenge extension

Turn this into a tiny settings panel with three sleepy toggles, staggered animations, and a shared navy shadow style so the controls feel like one little UI family.

keep sketching

Pick another small recipe and borrow one technique for your next doodle.