form.stopwatch
  input#start(type="checkbox")
  input#pause(type="checkbox")
  label.stopwatch__pause(for="pause")
    span Pause
  label.stopwatch__start(for="start")
    span Start
  button#reset.stopwatch__reset(type="reset")
    span Reset
  .stopwatch__restart.stopwatch__control
    .reset-button
  .stopwatch__stop-start.stopwatch__control
    .start-button
  .stopwatch__shadows
  .stopwatch__content
    img.stopwatch__branding(src="https://assets.codepen.io/605876/avatar.png")
    .stopwatch__face
      .digit.m.m--tens 0
      .digit.m.m--singles 0
      span :
      .digit.second.s.s--tens 0
      .digit.second.s.s--singles 0
      span .
      .digit.digit--small.ms.ms--tens 0
      .digit.digit--small.ms.ms--singles 0
View Compiled
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@500&display=swap')

*
*:after
*:before
  box-sizing border-box
  user-select none

// By default the play state is paused
:root
  --state paused
  --bg hsl(280, 50%, 90%)
  --digit hsl(90, 50%, 90%)
  --face hsl(90, 50%, 5%)
  --content hsl(0, 0%, 40%)
  --shadow hsla(0, 0%, 0%, 0.25)
  --glare hsla(0, 0%, 100%, 0.2)
  --watch-bg hsl(210, 80%, 50%)
  --watch-bg--light hsl(210, 80%, 90%)
  --watch-bg--dark hsl(210, 80%, 20%)
  --stroke hsl(0, 0%, 15%)
  --start hsl(10, 80%, 40%)
  --start-two hsl(10, 80%, 60%)
  --restart hsl(0, 0%, 70%)
  --restart-two hsl(0, 0%, 90%)

// Trick to stop/start the stopwatch
// If neither are checked the animation-name is "none"
// And that resets the counters to their initial value
#start:checked ~ .stopwatch__content
#pause:checked ~ .stopwatch__content
  .ms--tens
    --name ms-tens
  .ms--singles
    --name ms-singles
  .s--tens
    --name s-tens
  .s--singles
    --name s-singles
  .m--tens
    --name m-tens
  .m--singles
    --name m-singles

// What handles the playback. When "Start" is checked,
// the play state is running. Then we can use "Pause" to
// toggle the play start of the animations.
#start:checked ~ .stopwatch__content
  --state running
#pause:checked ~ .stopwatch__content
  --state paused
// Trick to hide the start button
#start:checked ~ .stopwatch__start
  z-index -1

.stopwatch__start:active ~ .stopwatch__stop-start
.stopwatch__pause:active ~ .stopwatch__stop-start
  --y 25
.stopwatch__reset:active ~ .stopwatch__restart
  --y 15

// The properties for animating each digit
// We should be able to declare these all as a chain
// But the syntax listed at: https://web.dev/at-property/#multiple-declarations
// doesn't work for me.
@property --ms-tens
  initial-value 0
  inherits false
  syntax '<integer>'

@property --ms-singles
  initial-value 0
  inherits false
  syntax '<integer>'

@property --s-tens
  initial-value 0
  inherits false
  syntax '<integer>'

@property --s-singles
  initial-value 0
  inherits false
  syntax '<integer>'

@property --m-tens
  initial-value 0
  inherits false
  syntax '<integer>'

@property --m-singles
  initial-value 0
  inherits false
  syntax '<integer>'

body
  min-height 100vh
  display grid
  font-family 'Orbitron', sans-serif
  background var(--bg)
  place-items center

form
  margin 0

button
  appearance none
  border 0
  outline transparent
  background none

label span
button span
[type="checkbox"]
  position absolute
  width 1px
  height 1px
  padding 0
  margin -1px
  overflow hidden
  clip rect(0, 0, 0, 0)
  white-space nowrap
  border-width 0

label
button
  cursor pointer

.reset-button
  width 100%
  height 50%
  position absolute
  top 10%
  left 50%
  transform translate(-50%, 0)
  border 0.5vmin solid var(--stroke)
  border-radius 1vmin
  background var(--restart)
  overflow hidden

  &:after
    height 100%
    width 100%
    position absolute
    top 0
    left 0
    background repeating-linear-gradient(90deg, transparent 0 18%, var(--stroke) 18% 22%) 50% 0 / 100% 30% no-repeat,
               repeating-linear-gradient(90deg, transparent 0 18%, var(--stroke) 18% 22%) 50% 100% / 100% 30% no-repeat
    content ''

  &:before
    content ''
    height 100%
    width 100%
    border-radius 1vmin
    background var(--restart-two)
    position absolute
    bottom 100%
    left 0
    transform translate(-20%, 45%)

.start-button
  width 100%
  height 60%
  position absolute
  bottom 0
  border 0.5vmin solid var(--stroke)
  border-radius 1vmin
  background var(--start)
  overflow hidden

  &:after
    content ''
    height 100%
    width 100%
    border-radius 1vmin
    background var(--start-two)
    position absolute
    bottom 100%
    left 0
    transform translate(-20%, 35%)

.stopwatch
  height 45vmin
  width 45vmin
  background-color var(--watch-bg)
  border-radius 50%
  border 0.5vmin solid var(--stroke)
  position relative

  &__pause
  &__start
  &__reset
  &__control
    --size min(48px, 10vmin)
    height var(--size)
    width var(--size)
    position absolute
    top 50%
    left 50%
    transition transform 0.05s
    transform translate(-50%, -50%) rotate(var(--rotation, 0deg)) translate(0, -25vmin) translateY(calc(var(--y, 0) * 1%))
    z-index 10

  &__control
    z-index -1

  &__restart:before
    content ''
    position absolute
    bottom 0
    left 50%
    transform translate(-50%, 0)
    width 60%
    height 75%
    border 0.5vmin solid var(--stroke)
    background linear-gradient(90deg, var(--restart-two) 0 80%, transparent 81%) 50% 50% / 100% 100% no-repeat
    background-color var(--restart)
    z-index -1

  &__start
  &__pause
  &__stop-start
    --rotation 40deg

  &__shadows
    height 100%
    width 100%
    border-radius 100%
    position absolute
    top 50%
    left 50%
    transform translate(-50%, -50%)
    overflow hidden

    &:after
      content ''
      position absolute
      height 100%
      width 106%
      top 50%
      left 50%
      border-radius 50%
      transform translate(-50%, -50%) translate(0, 2%)
      box-shadow 0 0 0 5vmin var(--watch-bg--light)

    &:before
      content ''
      position absolute
      height 100%
      width 100%
      top 50%
      left 50%
      border-radius 50%
      transform translate(-50%, -50%) translate(0, -2%)
      box-shadow 0 0 0 5vmin var(--watch-bg--dark)

  &__content
    height 40vmin
    border 0.5vmin solid var(--stroke)
    width 40vmin
    background-color var(--content)
    border-radius 50%
    position absolute
    top 50%
    left 50%
    transform translate(-50%, -50%)
    overflow hidden

    &:before
      box-shadow 0 0 0 5vmin var(--shadow)
      border-radius 50%
      content ''
      position absolute
      top 50%
      left 50%
      height 100%
      width 100%
      transform translate(-50%, -50%) translate(0, 2%)

    &:after
      content ''
      position absolute
      top 50%
      left 50%
      height 100%
      width 100%
      transform translate(-50%, -50%) rotate(-50deg)
      background linear-gradient(transparent 0 15%, var(--glare) 16% 35%, transparent 36% 40%, var(--glare) 41% 45%, transparent 46%)

  &__branding
    height 7vmin
    position absolute
    left 50%
    top 75%
    transform translate(-50%, 0)
    opacity 0.5
    filter saturate(0)

  &__face
    color var(--digit)
    display flex
    font-size 6vmin
    position absolute
    top 50%
    left 50%
    transform translate(-50%, -50%)
    padding 1.75vmin
    border-radius 1vmin
    background var(--face)

.digit
  position relative
  color transparent
  counter-reset var(--counter-name) var(--counter-variable)
  animation var(--name, none) var(--duration, 1s) infinite steps(var(--steps)) var(--state)

  &:after
    content counter(var(--counter-name))
    font-variant tabular-nums
    color var(--digit)
    position absolute
    bottom 0
    right 0

.ms
  font-size 4vmin
  transform translate(0, -6%)

  &--tens
    --duration 1s
    --steps 10
    --counter-name ms-tens
    --counter-variable var(--ms-tens)

  &--singles
    --duration 0.1s
    --steps 10
    --counter-name ms-singles
    --counter-variable var(--ms-singles)

.s
  &--tens
    --duration 60s
    --steps 6
    --counter-name s-tens
    --counter-variable var(--s-tens)

  &--singles
    --duration 10s
    --steps 10
    --counter-name s-singles
    --counter-variable var(--s-singles)

.m
  &--tens
    --duration 3600s
    --steps 6
    --counter-name m-tens
    --counter-variable var(--m-tens)

  &--singles
    --duration 600s
    --steps 10
    --counter-name m-singles
    --counter-variable var(--m-singles)

// The different animations requires for each digit
@keyframes ms-tens
  to
    --ms-tens 10

@keyframes ms-singles
  to
    --ms-singles 10

@keyframes s-tens
  to
    --s-tens 6

@keyframes s-singles
  to
    --s-singles 10

@keyframes m-tens
  to
    --m-tens 6

@keyframes m-singles
  to
    --m-singles 10
View Compiled
// 404
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.