Skip to content

Animation

This is a card

Use it to provide a small amount of information, link to another webpage, and give your page visual interest.

---
const { customClasses } = Astro.props;
const defaultClasses = "card theme container";
const classes = customClasses
  ? `${defaultClasses} ${customClasses}`
  : defaultClasses;
---

<div class={classes}>
  <div class="image">
    <img src="/images/card-padilla.jpg" alt="" />
  </div>
  <div class="card-body l-stack">
    <h2>
      <a href="#">This is a card</a>
    </h2>
    <p>
      Use it to provide a small amount of information, link to another webpage,
      and give your page visual interest.
    </p>
  </div>
</div>

I like this drop shadow generator

This is a card

Use it to provide a small amount of information, link to another webpage, and give your page visual interest.

.card.-animation-lift {
  box-shadow: 0 0 0 rgba(0, 0, 0, 0);
  translate: 0 0;
  transition: all 150ms linear;

  &:hover {
    box-shadow: var(--shadow-elevation-medium);
    translate: 0 -3px;
  }
}

Arrow Reveal

<div class="l-stack">
  <a class="button -animation-arrow" href="/" style="margin-right: auto;">
    Learn More
    <svg width="20" viewBox="0 0 23 23">
      <g id="chevron">
        <polygon
          points="11.3 0 9.7 1.6 18.3 10.2 18.3 10.2 19.5 11.3 18.3 12.5 18.3 12.5 9.7 21.1 11.3 22.7 22.7 11.3 11.3 0"
          fill="currentColor"></polygon>
      </g>
      <g id="stem">
        <polygon
          points="18.3 10.2 15.1 10.2 0 10.2 0 12.5 15.1 12.5 18.3 12.5 19.5 11.3 18.3 10.2"
          fill="currentColor"></polygon>
      </g>
    </svg>
  </a>
</div>

Arrow Bounce

Note: animating path d attribute is not supported by Safari.

<div class="l-stack">
  <a
    class="button -animation-arrow-bounce"
    href="/"
    style="margin-right: auto;"
  >
    Learn More

    <svg
      width="20"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      class="lucide lucide-arrow-right-icon lucide-arrow-right"
    >
      <path class="shaft" d="M5 12h14"></path>
      <path class="tip" d="m12 5 7 7-7 7"></path>
    </svg>
  </a>
</div>

Plus/Minus Toggle

Learn More
function attacheMouseEnterAnimation(triggerNode, applyAnimation, removeAnimation, animationDuration = 150) {
  triggerNode.addEventListener("mouseenter", () => {
    applyAnimation();

    window.setTimeout(() => {
      removeAnimation();
    }, animationDuration);
  });
}

const btns = document.querySelectorAll(".-animation-scale");

btns.forEach((btn) => {
  attacheMouseEnterAnimation(
    btn,
    () => btn.classList.add("-animating"),
    () => btn.classList.remove("-animating")
  );
});
.button.-animation-fill {
  position: relative;
  overflow: hidden;

  >* {
    color: var(--black);
    transition: color 300ms linear;
    position: relative;
    z-index: 2;
  }

  &:before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: var(--black);
    translate: 0 100%;
    transition: translate 200ms var(--ease-out-5);
    z-index: 1;
  }

  &:hover>* {
    color: var(--white);
  }

  &:hover:before {
    translate: 0 0;
  }
}

This requires using a variable font to transition the weight and box-shadow to transition the border.

.button.-animation-border-font-weight {
  transition: all 150ms ease;

  >* {
    transition: all 150ms ease;
    font-weight: 500;
  }

  &:hover {
    box-shadow: 0 0 0 3px currentColor;

    >* {
      font-weight: 800;
    }
  }
}
.loading-spinner-wrapper {
  width: 250px;
  height: 250px;
  position: relative;
  border: 1px solid rgb(0 0 0 / 0.1);
}

.loading-spinner {
  --icon-loading-spinner: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLWxvYWRlci1jaXJjbGUtaWNvbiBsdWNpZGUtbG9hZGVyLWNpcmNsZSI+PHBhdGggZD0iTTIxIDEyYTkgOSAwIDEgMS02LjIxOS04LjU2Ii8+PC9zdmc+);

  position: absolute;
  inset: 50%;
  translate: -50% -50%;
  width: 35px;
  aspect-ratio: 1 / 1;
  background-image: var(--icon-loading-spinner);
  background-size: contain;
  background-position: center;
  animation-name: rotate;
  animation-duration: 750ms;
  animation-iteration-count: infinite;
  animation-timing-function: linear;

  &:before {
    content: "";
    position: absolute;
    width: 100%;
    height: 100%;
    background-color: rgba(0 0 0 / 0.15);
    border-radius: 100%;
    scale: 1.5;
  }
}

@keyframes rotate {
  to {
    rotate: 360deg;
  }
}