AI CSS Animations

Back to Top Button Hover

The arrow slides up and out of the circle while an identical arrow rises in from below, reading as motion toward the top. Two stacked icons in one grid cell, clipped by the button.

Also known as: scroll to top button css, arrow up icon hover, icon slide swap.

HTML

<button class="hfx-back-to-top-swap" aria-label="Back to top">
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5"/><path d="m5 12 7-7 7 7"/></svg>
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5"/><path d="m5 12 7-7 7 7"/></svg>
</button>

CSS

.hfx-back-to-top-swap {
  --c: var(--hfx-color, #3b82f6);
  font-size: var(--hfx-size, 16px);
  position: relative;
  display: grid;
  place-items: center;
  width: 3.5em;
  height: 3.5em;
  padding: 0;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  overflow: hidden;
  background: color-mix(in srgb, var(--c) 12%, transparent);
  color: var(--c);
  transition: background-color 0.3s ease, color 0.3s ease;}
.hfx-back-to-top-swap svg {
  grid-area: 1 / 1;
  width: 1.5em;
  height: 1.5em;
  transition: transform 0.45s cubic-bezier(0.65, 0, 0.35, 1);
}
.hfx-back-to-top-swap svg:nth-of-type(2) { transform: translateY(2.6em); }
.hfx-back-to-top-swap:is(:hover, :focus-visible) {
  background: var(--c);
  color: #fff;
}
.hfx-back-to-top-swap:is(:hover, :focus-visible) svg:nth-of-type(1) { transform: translateY(-2.6em); }
.hfx-back-to-top-swap:is(:hover, :focus-visible) svg:nth-of-type(2) {
  transform: translateY(0);
  transition-delay: 0.05s;
}

@media (prefers-reduced-motion: reduce) {
  .hfx-back-to-top-swap, .hfx-back-to-top-swap *, .hfx-back-to-top-swap::before, .hfx-back-to-top-swap::after, .hfx-back-to-top-swap *::before, .hfx-back-to-top-swap *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Tailwind CSS version

The same effect using Tailwind utility classes. No custom CSS or config needed.

<button aria-label="Back to top" class="group grid h-12 w-12 place-items-center overflow-hidden rounded-full bg-blue-500/10 text-blue-500 transition-colors duration-300 hover:bg-blue-500 hover:text-white">
  <svg class="h-6 w-6 transition-transform duration-500 ease-[cubic-bezier(0.65,0,0.35,1)] [grid-area:1/1] group-hover:-translate-y-10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5"/><path d="m5 12 7-7 7 7"/></svg>
  <svg class="h-6 w-6 translate-y-10 transition-transform duration-500 ease-[cubic-bezier(0.65,0,0.35,1)] [grid-area:1/1] group-hover:translate-y-0 group-hover:delay-75" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5"/><path d="m5 12 7-7 7 7"/></svg>
</button>

Customizing this snippet

  • Color: set --hfx-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --hfx-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 16px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar hover effects