AI CSS Animations

Direction Aware Hover Effect

The caption slides in from whichever edge the pointer entered through. Four invisible triangles do it without JavaScript: the one you cross grows over the card, so the direction holds until you leave.

Also known as: css direction aware hover, overlay from mouse direction, direction aware hover pure css.

HTML

<a class="hfx-direction-aware" href="#">
  <span class="hfx-direction-aware-zone" aria-hidden="true"></span>
  <span class="hfx-direction-aware-zone" aria-hidden="true"></span>
  <span class="hfx-direction-aware-zone" aria-hidden="true"></span>
  <span class="hfx-direction-aware-zone" aria-hidden="true"></span>
  <span class="hfx-direction-aware-photo"></span>
  <span class="hfx-direction-aware-overlay">
    <strong>Mountain weekend</strong>
    <span>24 photos, view album</span>
  </span>
</a>

CSS

.hfx-direction-aware {
  --c: var(--hfx-color, #3b82f6);
  font: 400 var(--hfx-size, 16px) system-ui, sans-serif;
  position: relative;
  isolation: isolate;
  display: block;
  width: 16em;
  height: 10em;
  overflow: hidden;
  border-radius: 0.75em;
  color: #fff;
  text-decoration: none;
}
.hfx-direction-aware-photo {
  position: absolute;
  inset: 0;
  background: radial-gradient(75% 42% at 18% 112%, color-mix(in srgb, var(--c) 45%, #0f172a) 99%, transparent),
    radial-gradient(66% 36% at 92% 108%, color-mix(in srgb, var(--c) 60%, #0f172a) 99%, transparent),
    conic-gradient(from 128deg at 70% 42%, transparent 0, color-mix(in srgb, var(--c) 78%, #1e293b) 0.4deg 103.6deg, transparent 104deg),
    conic-gradient(from 120deg at 92% 55%, transparent 0, color-mix(in srgb, var(--c) 78%, #1e293b) 0.4deg 119.6deg, transparent 120deg),
    conic-gradient(from 124deg at 28% 38%, transparent 0, color-mix(in srgb, var(--c) 45%, #fff) 0.4deg 111.6deg, transparent 112deg),
    conic-gradient(from 126deg at 50% 52%, transparent 0, color-mix(in srgb, var(--c) 45%, #fff) 0.4deg 107.6deg, transparent 108deg),
    radial-gradient(circle at 70% 26%, #fff 0 0.75em, rgb(255 255 255 / 0.45) 0.85em, transparent 3em),
    linear-gradient(color-mix(in srgb, var(--c) 60%, #fff), color-mix(in srgb, var(--c) 14%, #fff7ed) 75%);
  transition: transform 0.5s cubic-bezier(0.25, 0.8, 0.25, 1);
}
/* four hit zones, one triangle per edge: top, right, bottom, left */
.hfx-direction-aware-zone {
  position: absolute;
  inset: 0;
  z-index: 3;
}
.hfx-direction-aware-zone:nth-child(1) { clip-path: polygon(0 0, 100% 0, 50% 50%); }
.hfx-direction-aware-zone:nth-child(2) { clip-path: polygon(100% 0, 100% 100%, 50% 50%); }
.hfx-direction-aware-zone:nth-child(3) { clip-path: polygon(0 100%, 100% 100%, 50% 50%); }
.hfx-direction-aware-zone:nth-child(4) { clip-path: polygon(0 0, 0 100%, 50% 50%); }
/* the zone you came in through covers the card, so crossing into another triangle changes nothing */
.hfx-direction-aware-zone:hover {
  z-index: 4;
  clip-path: inset(0);
}
.hfx-direction-aware-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 0.2em;
  padding: 1em 1.1em;
  background: linear-gradient(to top, color-mix(in srgb, var(--c) 88%, #000) 10%, color-mix(in srgb, var(--c) 55%, transparent) 55%, color-mix(in srgb, var(--c) 15%, transparent));
  opacity: 0;
  transition: opacity 0.3s ease;
}
.hfx-direction-aware-overlay strong {
  font-size: 1.1em;
}
.hfx-direction-aware-overlay span {
  font-size: 0.85em;
  opacity: 0.85;
}
.hfx-direction-aware:is(:hover, :focus-visible) .hfx-direction-aware-photo {
  transform: scale(1.06);
}
/* in instantly (the slide is the entrance), out with a fade */
.hfx-direction-aware-zone:hover ~ .hfx-direction-aware-overlay,
.hfx-direction-aware:focus-visible .hfx-direction-aware-overlay {
  opacity: 1;
  transition-duration: 0s;
}
.hfx-direction-aware-zone:nth-child(1):hover ~ .hfx-direction-aware-overlay { animation: hfx-direction-aware-top 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); }
.hfx-direction-aware-zone:nth-child(2):hover ~ .hfx-direction-aware-overlay { animation: hfx-direction-aware-right 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); }
.hfx-direction-aware-zone:nth-child(3):hover ~ .hfx-direction-aware-overlay,
.hfx-direction-aware:focus-visible .hfx-direction-aware-overlay { animation: hfx-direction-aware-bottom 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); }
.hfx-direction-aware-zone:nth-child(4):hover ~ .hfx-direction-aware-overlay { animation: hfx-direction-aware-left 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); }
@keyframes hfx-direction-aware-top { from { transform: translateY(-100%); } }
@keyframes hfx-direction-aware-right { from { transform: translateX(100%); } }
@keyframes hfx-direction-aware-bottom { from { transform: translateY(100%); } }
@keyframes hfx-direction-aware-left { from { transform: translateX(-100%); } }

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

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