CSSのanimationとNext.jsでカート追加のアニメーション実装
css
の animation
を勉強しようと思い、ECサイトで商品を追加した際の動作を再現しました。
概要
-
Next.js
で実装 -
ccs
のanimation
とkeyframes
を使用 - 「カート追加」ボタン押下 → 「カート追加!」をバッジで表示 → カートのカウントが増える
※ CodePenで実装しました。
animation 使い方
css
の animation
は、要素に動きをつけます。
animation-name
, animation-delay
などのプロパティがありますが、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%の間:
opacity
、width
どちらも変化しない - 75%~100%の間:
opacit
が1から0に、width
が6remから0に変化
上記によって、「カート追加!」をゆっくり伸ばして出現させ、いったん止めて、次は加速しながら縮めます。
カート追加によるアニメーションの実装
Next.js
と scss
で実装しました。
<div id="app"></div>
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
プロパティでは、他にも指定できるプロパティがあるので適宜使ってみようと思います。
ご覧いただきありがとうございました
今後もフロントエンド開発で気になったことや分からないことを調べて、共有していきたいと思います。
間違いなどございましたら、教えていただきたいです。