Progress Nav with IntersectionObserver

In Table of Contents with IntersectionObserver on CSS-Tricks, Chris Coyier talks about sticky table of contents on long pages whose active state updates as you scroll. When talking about those, you can not not mention the wonderful Progress Nav by Hakim El Hattab.


As Hakim’s demo from 2017 (!!) does not use IntersectionObserver — which was in it’s very early stages back then — Chris hinted that someone should make a version that uses it. Anders Grimsrud took up the challenge, and built it:

See the Pen
Hakim’s Progress Nav Concept using the Intersection Observer API
by Anders Grimsrud (@agrimsrud)
on CodePen.

Cool! 🙂

💡 Be sure to check Hakim’s “Building Better Interfaces” talk, which is full of inspiration to make your interfaces more delightful. Recommended stuff!

😊 I was very happy to see Chris including my 2020 Smooth Scrolling Sticky ScrollSpy Navigation in his post too.

CSS background-clip Demo: Text with Animated Emoji

Fun demo by Elad Shechter:

See the Pen Background-clip: text with Animated Emoji by Elad Shechter (@elad2412) on CodePen.

Behind it are two techniques:

  1. The 👻 emoji is set as the background-image of the text. To do so one must wrap it inside an SVG, and successively inject the SVG using a Data URL.

  2. To clip the emoji to the foreground text, he uses background-clip: text.

I like the fact that these techniques by themselves are not new, yet their combination is (at least to me this was the case):

  1. The “Emoji in SVG”-technique allows you to have an Emoji Mouse Cursor or use an emoji as favicon.
  2. Using background-clip: text works on any background image. As gradients can also be set as background images, you can create gradient links.

SVG Cassette Tape

Past weekend Lou Ottens — inventor of the Casette Tape while working at Philips Hasselt (Belgium) — passed away at the age of 95. Sharing this Greensock-powered SVG Animation by Chris Gannon seems very timely.

See the Pen Cassette Tape Loader by Chris Gannon (@chrisgannon) on CodePen.

Anyone got a pencil? 😅

Getting the Mouse Position using CSS

For his post How to Map Mouse Position in CSS on CSS-Tricks, Amit Sheen created this lovely demo:

The demo does use CSS Custom Properties for the X/Y position of the mouse, but they’re not injected using JavaScript. Instead, Amit uses the same technique as used in CSS-Only Direction Aware Hover: capture the hover on extra injected elements (here: 100 of them 😅).

By means of a General Sibling Combinator he then passes the data of each cell — which knows its location in the grid — to the content.

.cell:nth-child(42):hover ~ .content {
  --positionX: 1;
  --positionY: 3;

Pure CSS Stopwatch ⏱️

Nice demo by Jhey in which he created a Pure CSS Stopwatch:

It uses a clever combination of CSS Animations, CSS Counters, and @property:

  1. Each digit gets its own CSS Animation with its own timing.
  2. Inside each animation the value of a CSS Counter is adjusted.
  3. By defining those values as numbers using CSS @property, CSS knows how how to “animate” (read: interpolate) the values.

The animation play state is controlled using a checkbox, as detailed here.

💁‍♂️ CSS Counters is one of the 9 Underutilized CSS Features

About Us Pop-Out Effect

Cool demo that uses clip-path: path(…);, a feature that recently shipped with Chromium, making it supported in all three major rendering engines.

See the Pen About Us Pop-Out Effect by Mikael Ainalem (@ainalem) on CodePen.

Peeking under the hood – using the SVG Path Visualizer — you can see that it’s the .container-inner that is clipped not in a circular way, but a vertical rectangle with a circular bottom. The photo of the person itself already is transparent and using scale and translate the pop-out effect is created.

CSS Sticky Parallax Sections Demo

Nice demo on CodePen by Ryan Mulligan, featuring some sections with a sticky parallax background image:

See the Pen CSS Sticky Parallax Sections by Ryan Mulligan (@hexagoncircle) on CodePen.

I expected to find the the translateZ() + scale() method to create the parallax layers in there, but turns out Ryan took another approach:

  1. Scale down each enclosing section, using a scaleY transform with a number lower than 1, e.g. scaleY(0.9)
  2. Scale up each contained direct child of those sections using an inverse scaleY transform, e.g. scaleY(1.11111111)

As the second scaling (1.11111) undoes the first scaling (0.9), the content is rendered at the original scale of 1 again (e.g. 0.9 * 1.11111 = 1).

:root {
  --speed: 0.1;

.section {
  transform-origin: center top;
  transform: scaleY(calc(1 - var(--speed)));

.section > * {
  transform-origin: center top;
  transform: scaleY(calc(1 / (1 - var(--speed))));

Note that I’ve renamed Ryan’s --scale parameter to --speed here, as that’s what it affects.


I like this demo. Very pleasing on the eyes.

To easily create WebGL demos the author created a little library called RGBA.js which is used under the hood.

Focusing on hiding WebGL/JavaScript code from you and giving ability to write fragment shader code only

Once included, this is the only code one has to write:

float channel(vec2 p, float t) {
  float a = atan(p.x, -p.y);
  float w = sin(a*8.0 + t*2.0)*sin(t+a);  
  float d = length(p) - w*0.013 * smoothstep(0.85, 1.4, abs(a*0.5));
  d = abs(d - 0.25);
  return smoothstep(0.005, 0.0005, d);

void main() {
  vec2 p = gl_FragCoord.xy/resolution-0.5;
  p.x *= resolution.x/resolution.y;
  gl_FragColor = vec4(
    channel(p, time*0.7),
    channel(p, time*0.9+1.0),
    channel(p, time*1.1+2.0),

More demos in this CodePen Collection

CSS Paper Snowflakes

Nice demo by Michelle Barker, in which she recreates snowflakes based on those folded paper cutouts we all made as a child.

⚠️ Warning: quite a heavy demo.

Uses both a clip-path and mask-image to generate the cutout shapes. And oh, everything’s defined using Custom Properties.

Love the attention to detail on this one too:

  • The fine inner shadow on each segment is defined by the --bg1 Custom Property, and creates a depth effect. It gets flipped for the even segments.
  • The white fade on each segment which starts from the center is also a gradient.
  • Both of these are applied using multiple backgrounds: one being the fade, the other being the --bg1 one.