LoginSignup
0
0

CSSのanimationとNext.jsでカート追加のアニメーション実装

Posted at

CSSのanimationとNext.jsでカート追加のアニメーション実装

cssanimation を勉強しようと思い、ECサイトで商品を追加した際の動作を再現しました。

概要

  • Next.js で実装
  • ccsanimationkeyframes を使用
  • 「カート追加」ボタン押下 → 「カート追加!」をバッジで表示 → カートのカウントが増える

※ CodePenで実装しました。

animation 使い方

cssanimation は、要素に動きをつけます。
animation-name, animation-delay などのプロパティがありますが、animation プロパティは一括でアニメーションを指定することができます。

参照:公式 - css animation

transition も要素に動きをつけることができますが、animation のほうが keyframes で詳細に動きを指定することができるため、animation を使いました。

今回実装したanimation

下記が今回実装したアニメーションを付けた css です。

  .adding {
    animation: add-cart 1.8s ease-in forwards;
  }
  • 第一引数: アニメーション名 - keyframes の名前を指定 ( 公式 - animation-name )
    add-cart をアニメーション名とし、keyframes で動きをより詳細につけます

  • 第二引数: アニメーションの再生時間 ( 公式 - animation-duration )
    → 1.8sと指定しました

  • 第三引数: アニメーションの進行方法 ( 公式 - animation-timing-function )
    ease-in と指定し、最初ゆっくりと始まり、だんだん加速してアニメーションを終了させます

  • 第四引数: アニメーション前後のスタイル (公式 - animation-fill-mode )
    forwards と指定し、keyframes の最後のスタイルを保持してアニメーションを終了

実装したkeyframes

下記が実装した keyframes です。

@keyframes add-cart {
  0% {
    opacity: 0;
    width: 0;
  }
  25%,
  75% {
    opacity: 1;
    width: 6rem;
  }
  100% {
    opacity: 0;
    width: 0;
  }
}
  • 0~25%の間: opacity が0から1に、width が0から6remに変化
  • 25%~75%の間: opacitywidth どちらも変化しない
  • 75%~100%の間: opacit が1から0に、width が6remから0に変化

上記によって、「カート追加!」をゆっくり伸ばして出現させ、いったん止めて、次は加速しながら縮めます。

カート追加によるアニメーションの実装

Next.jsscss で実装しました。

<div id="app"></div>
next.js
import React, { useState, useEffect } from "https://esm.sh/react";
import ReactDOM from "https://esm.sh/react-dom";
import { Badge, Container, Button } from "https://esm.sh/react-bootstrap";

const App = () => {
  const [cartStatus, setCartStatus] = useState("empty");
  const [cartInCount, setCartInCount] = useState(0);
  const addCart = () => {
    setCartStatus("adding");
    setCartInCount(cartInCount + 1);
  };

  useEffect(() => {
    console.log(cartStatus);

    cartStatus === "adding" &&
      setTimeout(() => {
        setCartStatus("added");
      }, 1800);
  }, [cartStatus]);

  return (
    <>
      <Container className="py-2">
        <div className="header d-flex justify-content-between">
          <h1>Cart</h1>
          <Button
            type="button"
            variant="link"
            size="lg"
            className="text-dark pposition-relative"
          >
            <i className="bi-cart"></i>
            <Badge
              bg={cartStatus === "empty" ? "secondary" : "success"}
              className={`position-absolute top-25 left-0 rounded-pill ${
                cartStatus !== "empty" && "added-badge"
              }`}
            >
              {cartStatus === "adding" ? (
                <div className="added d-flex gap-1">
                  <i className="bi-check"></i>
                  <span className="adding w-0">カート追加!</span>
                </div>
              ) : (
                <span>{cartInCount}</span>
              )}
            </Badge>
          </Button>
        </div>
        <Button
          type="button"
          variant="outline-secondary"
          onClick={() => addCart()}
        >
          カート追加
        </Button>
      </Container>
    </>
  );
};

ReactDOM.render(<App />, document.querySelector("#app"));

上記では、カートが空の状態から、「カート追加」ボタン押下時に adding ステータスとなり、1.8s後に added ステータスとなりカート内のカウントが増えたバッジになるように実装しました。

.header {
  .adding {
    animation: add-cart 1.8s ease-in forwards;
  }
}

@keyframes add-cart {
  0% {
    opacity: 0;
    width: 0;
  }
  25%,
  75% {
    opacity: 1;
    width: 6rem;
  }
  100% {
    opacity: 0;
    width: 0;
  }
}

上記では、先ほど説明したように、add-cartアニメーション名で、1.8s間で「カート追加!」のバッジを伸縮するアニメーションを実装しました。

まとめ

animation を使うことで、より詳細に動きを実装できることができました。
animation プロパティでは、他にも指定できるプロパティがあるので適宜使ってみようと思います。


ご覧いただきありがとうございました

今後もフロントエンド開発で気になったことや分からないことを調べて、共有していきたいと思います。
間違いなどございましたら、教えていただきたいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0