Circular Scroll Indicator Using Pure CSS

Circular Scroll Indicator Using Pure CSS
Code Snippet:CSS scroll-driven animation timer
Author:
Published: January 4, 2024
Last Updated: January 4, 2024
Downloads: 222
License: MIT
Edit Code online: View on CodePen
Read More

This Pure CSS code snippet helps you to create a circular scroll indicator. It visualizes scrolling progress dynamically. The indicator animates as you scroll down a page, showcasing a timer-like visualization. This is helpful for indicating scrolling progress visually.

You can use this code on websites to add a visual scroll indicator. It helps users track their progress while scrolling, enhancing the overall user experience.

How to Create Circular Scroll Indicator Using Pure CSS

1. First of all, load the Reset CSS by adding the following CDN link into the head tag of your HTML document.

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">

2. Set up the basic HTML structure, including a warning for unsupported browsers and the circular scroll indicator container. Place the warning inside a <div> with the class “warning” and the indicator within a <figure> with the class “component.”

<h2> Scroll down </h2>
<div class="warning">
  <p>⚠️ Scroll-driven animations are not supported in this browser. Try this demo in Chrome 115+.</p>
</div>

<figure class="component" aria-hidden="true" webc:root="override">
  <div class="timer-wrapper">
    <svg class="timer" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentcolor" viewBox="0 0 256 256">
      <rect width="256" height="256" fill="none"></rect>
      <circle cx="128" cy="128" r="88" fill="var(--color-theme)"></circle>
      <circle cx="128" cy="128" r="88" fill="none" stroke="currentcolor" stroke-miterlimit="10" stroke-width="16"></circle>
      <line class="timer-hand" x1="128" y1="128" x2="167.6" y2="88.4" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line>
      <line class="timer-switch" x1="104" y1="8" x2="152" y2="8" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="16"></line>
    </svg>
  </div>
  <figcaption class="caption"></figcaption>
</figure>

3. Apply styles to create the circular scroll indicator and customize its appearance. Set up root-level CSS variables for background color, text color, and theme colors to customize the indicator’s appearance.

Utilize CSS animations to bring the circular scroll indicator to life. The code includes keyframes for progress, turning upright, and plunging animations.

:root {
  --color-bg: #fffefd;
  --color-text: #020617;
  --color-theme: #ffedd5;
  --color-theme-accent: #fed7aa;
}

@property --progress {
  syntax: "<integer>";
  initial-value: 0;
  inherits: false;
}

body {
  color: var(--color-text);
  background-color: var(--color-bg);
  font-family: system-ui, sans-serif;
}

.component {
  --size: 30vmin;

  display: grid;
  grid-template-areas:
    "timer"
    "caption";
  place-items: center;
  place-content: center;
  gap: 0.2em;
  position: fixed;
  inset: 0;
  margin: auto;
}

.timer-wrapper {
  grid-area: timer;
  display: grid;
  place-items: center;
  place-content: center;
  grid-template-areas: "container";
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  background: conic-gradient(
    from 45deg,
    var(--color-theme-accent) calc(var(--progress) * 1%),
    transparent 0
  );
}

.timer-wrapper > * {
  grid-area: container;
}

.timer {
  width: calc(var(--size) / 1.2);
  height: calc(var(--size) / 1.2);
}

.caption {
  grid-area: caption;
}

.caption::before,
.caption::after {
  margin-inline: auto;
  content: counter(progress);
  font-size: calc(0.6em + var(--size) / 6);
  font-weight: bold;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.caption::after {
  content: "%";
}

/* Warning for unsupported browsers */
.warning {
  color: black;
  background: papayawhip;
  padding: 1rem;
  line-height: 1.3;
  text-align: center;
}

@supports (animation-timeline: scroll()) {
  .warning {
    display: none;
  }

  body {
    height: 1000vh;
  }

  :is(.component, .timer-wrapper, .timer, .timer-hand, .timer-switch) {
    -webkit-animation-fill-mode: both;
            animation-fill-mode: both;
    -webkit-animation-timing-function: linear;
            animation-timing-function: linear;
    animation-timeline: scroll();
  }

  .component {
    --plunge-offset: 10rem;
    --plunge-start: calc(100% - var(--plunge-offset) * 2);
    --plunge-end: calc(100% - var(--plunge-offset));

    -webkit-animation-name: progress;

            animation-name: progress;
    animation-range: 0 var(--plunge-start);
    counter-reset: progress var(--progress);
  }

  .timer-wrapper {
    -webkit-animation-name: progress, turn-upright;
            animation-name: progress, turn-upright;
    animation-range: 0 var(--plunge-start),
      var(--plunge-start) var(--plunge-end);
  }

  .timer {
    --plunge-depth: 0.25em;
    transform-origin: 50% 0;
    -webkit-animation-name: plunge;
            animation-name: plunge;
    animation-range: var(--plunge-start) var(--plunge-end);
  }

  .timer-switch {
    --plunge-depth: 1em;
    transform-origin: 50% 0;
    -webkit-animation-name: plunge;
            animation-name: plunge;
    animation-range: var(--plunge-start) var(--plunge-end);
  }

  .timer-hand {
    transform-origin: 50%;
    rotate: calc((var(--progress) / 100) * 360deg);
    -webkit-animation-name: progress;
            animation-name: progress;
    animation-range: 0 var(--plunge-start);
  }

  @-webkit-keyframes progress {
    to {
      --progress: 100;
    }
  }

  @keyframes progress {
    to {
      --progress: 100;
    }
  }

  @-webkit-keyframes turn-upright {
    from {
      rotate: -10deg;
    }
    to {
      rotate: 0;
    }
  }

  @keyframes turn-upright {
    from {
      rotate: -10deg;
    }
    to {
      rotate: 0;
    }
  }

  @-webkit-keyframes plunge {
    50% {
      translate: 0 var(--plunge-depth);
    }
  }

  @keyframes plunge {
    50% {
      translate: 0 var(--plunge-depth);
    }
  }

  @-webkit-keyframes fade-out {
    from {
      opacity: 1;
    }
    to {
      opacity: 0;
    }
  }

  @keyframes fade-out {
    from {
      opacity: 1;
    }
    to {
      opacity: 0;
    }
  }
}

Copy and paste the above HTML and CSS code into your project. Adjust the CSS variables to match your site’s color scheme. Test the indicator in a compatible browser, preferably Chrome 115+, for the optimal scrolling experience.

That’s all! hopefully, you have successfully created a Circular Scroll Indicator Using Pure CSS. If you have any questions or suggestions, feel free to comment below.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

About CodeHim

Free Web Design Code & Scripts - CodeHim is one of the BEST developer websites that provide web designers and developers with a simple way to preview and download a variety of free code & scripts. All codes published on CodeHim are open source, distributed under OSD-compliant license which grants all the rights to use, study, change and share the software in modified and unmodified form. Before publishing, we test and review each code snippet to avoid errors, but we cannot warrant the full correctness of all content. All trademarks, trade names, logos, and icons are the property of their respective owners... find out more...