Reveal effect with clip-path

In the navbar I’ve added a small indicator next to Posts link. I wanted to draw attention that there is a new blog post. On hover I wanted to show more information: new label (badge).

An indicator awaiting user discovery
An indicator awaiting user discovery

Initially I wrote it this way:

.navbar-link[data-has-new-article] {
  --foreground-color: var(--color-white);
  --background-color: var(--color-red-300);
  position: relative;
}

.navbar-link[data-has-new-article]::after {
  transition-property: width, height, border-radius, text-indent, color;
  transition-duration: 150ms;
  transition-timing-function: ease-in;
  content: "new";
  position: absolute;
  display: inline-flex;
  align-items: center;
  width: 0.5em;
  height: 0.5em;
  padding: 0;
  font-family: var(--body);
  font-size: 0.7rem;
  color: oklch(from var(--background-color) l c h / 0);
  border-radius: calc(infinity * 1px);
  background-color: var(--background-color);
  text-indent: -50%;
}

.navbar-link[data-has-new-article]:hover::after {
  content: "new";
  width: 3ch;
  height: auto;
  padding: 0.125em 0.5em;
  color: var(--foreground-color);
  border-radius: 0.25rem;
  transform: translateY(-0.5em);
  text-indent: 0;
}

It worked, did the job, no single token was burnt. I thought then, if I have the desired state (full label), why not use masking to switch between dot indicator state and the label? Well, it worked even better. See for yourself:

.navbar-link[data-has-new-article]::after {
  transition-property: clip-path;
  transition-duration: 150ms;
  transition-timing-function: ease-in;
  clip-path: circle(0.25em at 0.25em); /* 👈 only dot is visible */
  content: "new";
  position: absolute;
  top: -0.25em;
  display: inline-block;
  padding: 0.125em 0.5em;
  font-family: var(--body);
  font-size: 0.7rem;
  color: var(--foreground-color);
  border-radius: 0.25rem;
  background-color: var(--background-color);
}

.navbar-link[data-has-new-article]:hover::after {
  clip-path: circle(3em at 0.25em); /* 👈 full state is visible */
}

Until you hover over the link, what indicator is, is actually a top-left corner of the label. After the change .navbar-link[data-has-new-article]:hover::after contains just one rule! It’s easier to maintain, too.

I recorded how it looked like before and after the change.

Before: slow
Before: normal speed
With `clip-path`: slow
With `clip-path`: normal speed