Experimenting with CSS Number counters with fallback
Note: This experiment is based on examples found in this CSS Tricks article
Over recent years animation has been adopted increasingly within HTML based websites to provide extra sparkle to a webpage. While CSS can now power a lot of this animation, often JavaScript is either used instead of CSS animation techniques or is required to initiate CSS animation.
With progressive enhancement an important consideration I’ve never been happy to rely too heavily on JavaScript to animate a website. Too often I see websites fade in sections of a page individually using techniques that result in the page being inaccessible if the JavaScript does not run for whatever reason.
While the benefits of such enhancements are open to discussion, there are instances where web animation can add an element of delight with minimal negative impact. One such instance is animating number counters. With a spare couple of hours to play with I decided to look into what it would take to create a version of these counters with fallbacks.
Where to start
Looking at existing solutions is always a great place to start; why reinvent the wheel? Finding a great article on CSS Tricks which provides a number of CSS only solutions I thought this would be the perfect starting point for what I was looking for, especially as I wouldn’t need to build a JavaScript fallback at the start.
One example utilising the @property CSS function appeared the most lightweight to work with, but is only supported by Chromium browsers. Though I develop primarily within Firefox, I know it’s user-base is small and so adopting something like this that’s unsupported in some browsers would be fine on the assumption it could be tweaked to provide a fallback for older browsers.
In addition to this I wanted to be able to simplify the CSS so it would be usable over multiple counters, as well as for those counters to be able to be placed further down the page and not start animating before coming into view.
To achieve the latter would require the addition of JavaScript to detect when elements appear within the viewport through use of the Intersection Observer API. I had hoped that the content-visibility property in CSS might provide a solution but when testing, the animation simply would not run.
See the Pen Animated Number in CSS by Kean Richmond (@keanr) on CodePen.
To view the animation above you will need to use a supported browser
What did I add?
Beyond the original code example, I’ve added the following:
- Inline custom property
By defining the upper number of the counter using custom properties this allows this to be set within the HTML and not require multiple CSS classes for different values. - Zero and animate classes
To allow us to reset the number to zero without affecting browsers that don’t support the @property rule, or prefer reduced motion and to initiate the animation on intersection with the viewport we rely on these classes to set up the animation. These wouldn’t be necessary if the counters were in view on initial load. - Prefers reduced motion
I’m always conscious of adding too much animation for users who do not wish to view this. So we ensure the animations do not take place by referencing this both in the JavaScript and the CSS (just in case). - Intersection Observer
This is required for us to detect that the number is visible within the viewport. We have this set so that 50% of the height of the element should be visible before the animation starts, as well as adding a short 500ms delay to the animation so that this is suitably visible before the animation begins.
A couple of questions
Why @property?
Though playing with new toys can be fun, it’s not always obvious what they do when copying other people’s examples. When digging into the details of the @property feature it appears that this is necessary because, by default, custom properties have a string type. For us to be able to animate the number as an integer we require the @property feature to be able to define the type of the custom property correctly.
Accessibility?
As yet I’ve not been able to fully test the impact of this code on accessibility and assistive technologies. Brief screen reader testing suggests the number displayed before the animation starts is what is output to the user. This means for full supportive browsers, like Chrome, users will hear 0, whilst on older browsers they’ll get the actual number.
I believe duplicating the number and utilising aria-attributes may be the best way to provide an accessible fallback in this instance.
Go play
As yet I’ve not tested this on a live website, so it may not be suitable for your particular use case… if it works at all.
Let us know if you have any success using the code on your website, or if you have any ideas for improving it further.