{ CF }

30 CSS Badges

Reading Time Indicator

Three states — not started, in progress, done. A 2px bar at the bottom fills to 100% on hover so the user can see what completion looks like. Clean type, no decoration.

Pure CSS MIT licensed

Reading Time Indicator the 20th of 30 designs in the 30 CSS Badges collection. The design is implemented in pure CSS — no JavaScript required. Copy the HTML and CSS panels below into your project. Because the demo is pure CSS, it works in any framework or templating engine you happen to use. The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.

Live preview

Open in playground

The code

<div class="read-stage">
  <div class="read-stack">
    <div class="read-badge" style="--read-progress: 0%">
      <span class="read-icon">⌛</span>
      <div class="read-main">
        <div class="read-duration">2 min</div>
        <div class="read-label">reading time</div>
      </div>
      <div class="read-divider"></div>
      <div class="read-status read-status-unread"><span class="read-dot"></span>Not started</div>
    </div>

    <div class="read-badge" style="--read-progress: 55%">
      <span class="read-icon">⌛</span>
      <div class="read-main">
        <div class="read-duration">7 min</div>
        <div class="read-label">reading time</div>
      </div>
      <div class="read-divider"></div>
      <div class="read-status read-status-progress"><span class="read-dot"></span>In progress</div>
    </div>

    <div class="read-badge" style="--read-progress: 100%">
      <span class="read-icon">⌛</span>
      <div class="read-main">
        <div class="read-duration">14 min</div>
        <div class="read-label">reading time</div>
      </div>
      <div class="read-divider"></div>
      <div class="read-status read-status-done"><span class="read-dot"></span>Finished</div>
    </div>

    <div class="read-hint">↑ hover any badge to complete it</div>
  </div>
</div>
.read-stage {
  background: #fafaf7;
  padding: 60px 48px;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 360px;
}
.read-stack {
  display: flex;
  flex-direction: column;
  gap: 20px;
  align-items: flex-start;
}
.read-badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px 10px 12px;
  border: 1.5px solid #1a1612;
  font-family: system-ui, "Bricolage Grotesque", sans-serif;
  position: relative;
  overflow: hidden;
  cursor: default;
}
.read-badge::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  height: 2px;
  background: #1a1612;
  width: var(--read-progress, 0%);
  transition: width 0.8s cubic-bezier(0.4, 0, 0.2, 1);
}
.read-badge:hover::after { width: 100% !important; }
@media (prefers-reduced-motion: reduce) {
  .read-badge::after { transition: none; }
}
.read-icon {
  font-size: 16px;
  line-height: 1;
  flex-shrink: 0;
}
.read-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.read-duration {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: #1a1612;
  line-height: 1;
}
.read-label {
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #4a4239;
  line-height: 1;
}
.read-divider {
  width: 1px;
  height: 28px;
  background: #cfc6b1;
  flex-shrink: 0;
}
.read-status {
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  line-height: 1.2;
}
.read-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  vertical-align: middle;
  margin-right: 4px;
  margin-bottom: 1px;
}
.read-status-done { color: #1d8f4a; }
.read-status-progress { color: #b8442d; }
.read-status-unread { color: #aaa; }
.read-hint {
  font-family: system-ui, "Bricolage Grotesque", sans-serif;
  font-size: 9px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: #bbb;
  text-align: center;
  margin-top: 8px;
}

Search CodeFronts

Loading…