無料で誰にでも手軽に導入でき、利便性が高くチーム体制での作業にも向いているデザインツールFigma(公式サイト)。この記事ではFigmaを使ってSVG形式のリストアイコンの作成して、それがクリックされた時のアニメーションを作成していきます。
作成したアイコンをアニメーションさせたい
Figmaで作成したSVG形式のアイコンをアニメーションさせます
ファイル構成と必要なもの
|-- dir/
|-- index.html
|-- style.css
`-- script.js
Figmaでアイコンを作成する方法
Figma SVG形式のリストアイコンの作成・適用させる方法
2023年01月10日
FigmaできたSVGタグ
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="17" cy="20" r="10" fill="#EC7E7E" />
<circle cx="17" cy="50" r="10" fill="#EC7E7E" />
<circle cx="17" cy="80" r="10" fill="#EC7E7E" />
<rect x="33" y="12.5" width="60" height="15" rx="2" fill="#5DB6D2" />
<rect x="33" y="42.5" width="60" height="15" rx="2" fill="#5DB6D2" />
<rect x="33" y="72.5" width="60" height="15" rx="2" fill="#5DB6D2" />
</svg>
以下のようにアニメーションさせて、バツ印を作っていきます。
アイコンをクリックした際に、activeクラスを追加・削除させます。
activeクラスが追加された状態のときに transform プロパティでバツ印の状態に変形させてアニメーションを作成します。
アイコンを表示する
index.htmlファイルにsvgタグを追加します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>icon</title>
</head>
<body>
<div class="wrapper">
<svg class="icon" width="100" height="100" viewBox="0 0 100 100" fill="none"
xmlns="http://www.w3.org/2000/svg">
<rect x="33" y="12.5" width="60" height="15" rx="2" fill="#5DB6D2" />
<rect x="33" y="42.5" width="60" height="15" rx="2" fill="#5DB6D2" />
<rect x="33" y="72.5" width="60" height="15" rx="2" fill="#5DB6D2" />
<circle cx="17" cy="20" r="10" fill="#EC7E7E" />
<circle cx="17" cy="50" r="10" fill="#EC7E7E" />
<circle cx="17" cy="80" r="10" fill="#EC7E7E" />
</svg>
</div>
<script src="script.js"></script>
</body>
</html>
11行目 css, javascriptで扱うために、icon クラスを追加します。
16-19行目 アニメーション後に丸が四角のオブジェクトの上に配置されるように、circle タグをrectタグの下に移動させます。
.wrapper {
display: flex;
height: 100vh;
width: 100%;
align-items: center;
justify-content: center;
}
.wrapper svg {
cursor: pointer;
user-select: none;
width: 50px;
height: 50px;
background: rgba(255, 184, 84, 0.4);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 184, 84, 0.5);
border-right: 1px solid rgba(255, 184, 84, 0.2);
border-bottom: 1px solid rgba(255, 184, 84, 0.2);
}
見た目をstyle.cssで指定します。
javascriptでクラスを追加・削除する
script.jsファイルに追加します。
let icon = document.querySelector('.icon');
icon?.addEventListener('click', function () {
this.classList.toggle('active');
list_wrapper.classList.toggle('active');
});
アイコンをクリックすると、activeクラスがない場合は付与され、既にある場合は削除されます。
変形させる
active クラスが付与された場合にバツ印に変形していきます。
オブジェクトがなめらかに動くように circle rect タグにtransitionプロパティを追加します。
circle, rect {
transition: all .3s ease-in;
}
aのオブジェクトを左側へフェードアウト
.wrapper svg.active circle:nth-of-type(1) {
transform: translateX(-27%);
}
.wrapper svg.active circle:nth-of-type(3) {
transform: translateX(-27%);
}
左側へ水平方向の移動は、 transform: プロパティに translateX(-27%);を指定します。オブジェクトの位置関係は上の画像の様になっており、27%以上左へ動かしたらフェードアウトします。
bのオブジェクトをフレームの中心へ移動
.wrapper svg.active circle:nth-of-type(2) {
transform: translateX(calc(40% - 7%));
}
こちらも水平方向の移動なので、 translateX を指定します。右方向なので正の値を指定します。
左へ7%で左端に接して、右へ40%で中央に配置と考えた方がわかりやすいです。
calc() はプロパティ値を計算する際に使用します。
cのオブジェクトを右へフェードアウト
.wrapper svg.active rect:nth-of-type(2) {
transform: translateX(calc(100% - 33%));
}
こちらも水平方向の移動なので、 translateX を指定します。右方向なので正の値を指定します。
※ ギリギリでフェードアウトさせていますが、ギリギリである必要はありません
d, eのオブジェクトを斜め中央に配置
- 45°回転させるため、回転の原点を指定
- 原点を対角線上へ移動
- 45°回転
- オブジェクトを変倍して変形
① 原点を指定するには、 transform-origin プロパティを使用します。
.wrapper svg rect:nth-of-type(1) {
transform-origin: 90% 20%;
}
原点を対角線上へ移動、45°回転、変倍して変形させます。
.wrapper svg.active rect:nth-of-type(1) {
transform: translate(-5%, -5%) rotate(-45deg) scaleX(1.8);
}
まとめて指定します。指定する順番が違うと、うまく行かないので注意。
transform-origin
scaleX
translate
同様にeにも指定します。
.wrapper svg rect:nth-of-type(3) {
transform-origin: 90% 80%;
}
.wrapper svg.active rect:nth-of-type(3) {
transform: translate(-5%, 5%) rotate(45deg) scaleX(1.8);
}
以上アイコンをアニメーションすることができました。
コード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>icon</title>
</head>
<body>
<div class="wrapper">
<svg class="icon" width="100" height="100" viewBox="0 0 100 100" fill="none"
xmlns="http://www.w3.org/2000/svg">
<rect x="33" y="12.5" width="60" height="15" rx="2" fill="#5DB6D2" />
<rect x="33" y="42.5" width="60" height="15" rx="2" fill="#5DB6D2" />
<rect x="33" y="72.5" width="60" height="15" rx="2" fill="#5DB6D2" />
<circle cx="17" cy="20" r="10" fill="#EC7E7E" />
<circle cx="17" cy="50" r="10" fill="#EC7E7E" />
<circle cx="17" cy="80" r="10" fill="#EC7E7E" />
</svg>
</div>
<script src="script.js"></script>
</body>
</html>
* {
margin: 0;
padding: 0;
box-sizing: border-box
}
.wrapper {
height: 100vh;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.wrapper svg {
cursor: pointer;
user-select: none;
width: 200px;
height: 200px;
background: rgba(255, 184, 84, 0.4);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 184, 84, 0.5);
border-right: 1px solid rgba(255, 184, 84, 0.2);
border-bottom: 1px solid rgba(255, 184, 84, 0.2);
}
circle, rect {
transition: all .3s ease-in;
}
.wrapper svg.active circle:nth-of-type(1) {
transform: translateX(-27%);
}
.wrapper svg.active circle:nth-of-type(3) {
transform: translateX(-27%);
}
.wrapper svg.active circle:nth-of-type(2) {
transform: translateX(calc(-7% + 40%));
}
.wrapper svg rect:nth-of-type(1) {
transform-origin: 90% 20%;
}
.wrapper svg.active rect:nth-of-type(1) {
transform: translate(-5%, -5%) rotate(-45deg) scaleX(1.8);
}
.wrapper svg.active rect:nth-of-type(2) {
transform: translateX(calc(100% - 33%));
}
.wrapper svg rect:nth-of-type(3) {
transform-origin: 90% 80%;
}
.wrapper svg.active rect:nth-of-type(3) {
transform: translate(-5%, 5%) rotate(45deg) scaleX(1.8);
}
let icon = document.querySelector('.icon');
icon?.addEventListener('click', function () {
this.classList.toggle('active');
list_wrapper.classList.toggle('active');
});