HTML/CSS を駆使してカービィと花見を作り上げる！

こんにちは、うえむーです！
2月ごろに大宮公園でお花見をしながらLT大会を開催することになったので、テーマを考えていたときに、「HTML/CSS だけで桜やキャラクターを作れたら面白いのでは？」と思いこの作品を作りました。
この記事では、桜の描画やアニメーションの実装方法を詳しく解説します！

# 作品

実際に作ったのがこちらです。
カービィ・ワドルディが花見をしてるアニメーションを作りました。

![完成図.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517490/8a94df73-814d-4420-b8bc-9b0bd8724f4c.gif)

CodepenのURL
https://codepen.io/uemuragame5683/pen/WbNyNog

桜の描画はどうなっているのか、どのようなアニメーションを実装しているのかを説明していきます。

# コードの説明

### 桜の木の作成

木の形状は mask-image のプロパティを利用し、色は background のプロパティでグラデーションを設定しました。

木の画像素材を使用して tree.png というファイル名で格納し、以下のように background を設定しました。

![tree.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517490/7bc7dd24-5e0e-4002-981c-38d1fe553d4b.png)


```
.sakura_content_tree {
    background: linear-gradient(10deg, #5b2234, #B5753F 30%, #B5753F);
    mask-image: url("tree.png");
    mask-size: 600px;
    mask-repeat: no-repeat;
    mask-position: center bottom;
    height: 750px;
    width: 100%;
    position: relative;
    overflow: hidden;
}
```


### 桜の描画

桜の花びらは radial-gradient を活用して表現しました。

radial-gradient(circle at X% Y%, color1 size1, color2 size2, transparent size3) という形式で、円形のグラデーションを作成できます。
radial-gradient を使い、小さな花びらを複数配置して桜の花を表現しています。


```
.sakura_content_leaf {
    content: "";
    background-image:
        radial-gradient(circle at 19% 49%, var(--sakura) 0.25%, var(--sakura2) 2.5%, transparent 11%),
        radial-gradient(circle at 33% 34%, var(--sakura) 0.25%, var(--sakura2) 2.5%, transparent 11%),
        radial-gradient(circle at 20% 61%, var(--sakura) 0.25%, var(--sakura2) 2.5%, transparent 11%),
        radial-gradient(circle at 28% 61%, var(--sakura) 0.25%, var(--sakura2) 2.5%, transparent 11%),
        radial-gradient(circle at 27% 44%, var(--sakura) 0.25%, var(--sakura2) 2.5%, transparent 11%),
        radial-gradient(circle at 27% 53%, var(--sakura) 0.25%, var(--sakura2) 2.5%, transparent 11%),
        radial-gradient(circle at 22% 38%, var(--sakura) 0.25%, var(--sakura2) 2.5%, transparent 11%),
        radial-gradient(circle at 27% 32%, var(--sakura) 0.25%, var(--sakura2) 2.5%, transparent 11%), 
.....
    background-size: 100% 100%;
    display: block;
    width: 600px;
    height: 500px;
    background-repeat: no-repeat;
    position: absolute;
    top: 0px;
    left: -1%;
    z-index: 10;
    transform: translateX(0%) translateY(0%);
}
```

この手法を使うことで、画像を使わずに CSS のみで桜の花を描くことができます。

### 桜吹雪のアニメーション

桜吹雪は li 要素を複数並べてランダムにアニメーションさせることで表現しました。
@keyframes を活用し、落ちる速度や回転の違いを演出しています。

```
<ul class="sakura">
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
    <li class="sakura_inner"></li>
</ul>

```

```
 .sakura {
    position: absolute;
    padding: 0px;
    margin: 0px;
    width: 100%;
    height: 75%;
    display: flex;
    justify-content: center;
    align-items: center;
    bottom: 10px;
    left: 0px;
    overflow: hidden;
    perspective: 50px;
    border-radius: 0% 70%;
    & .sakura_inner {
        padding: 10px;
        position: absolute;
        list-style: none;
        background: var(--sakura);
        border-radius: 0% 80% 0% 60% / 0% 70% 0% 90%;
        top: 0px;
        &:nth-child(2n) {
            background: var(--sakura2);
            border-radius: 0% 70% 0% 90% / 0% 90% 0% 70%;
        }
        &:nth-child(1) {
            left: 0px;
            animation:
                10s ease-in-out 0s infinite normal none running fall,
                3s ease-in-out 0s infinite alternate none running sakura_rotate2;
        }
        &:nth-child(2) {
            left: 5%;
            animation:
                15s ease-in-out 0s infinite normal none running fall,
                2s ease-in-out 0s infinite alternate none running sakura_rotate3;
        }
・・・
        &:nth-child(12) {
            left: 90%;
            animation:
                10s ease-in-out 0s infinite normal sakura_fall,
                3.5s ease-in-out 0s infinite alternate sakura_rotate1;
        }
    }
}

...

@keyframes sakura_fall {
    0% {
        top: 0%;
    }
    100% {
        top: 150%;
    }
}
@keyframes sakura_rotate1 {
    0% {
        transform: translateX(0px) translateZ(-50px) rotate(0deg);
    }
    100% {
        transform: translateX(100px) translateZ(-30px) rotateY(10deg);
    }
}
@keyframes sakura_rotate2 {
    0% {
        transform: translateX(0px) translateZ(-40px) rotate(0deg);
    }
    100% {
        transform: translateX(100px) translateZ(-60px) rotateY(20deg);
    }
}
@keyframes sakura_rotate３ {
    0% {
        transform: translateX(0px) translateZ(-40px) rotate(10deg);
    }
    100% {
        transform: translateX(100px) translateZ(-60px) rotateY(0deg);
    }
}
    
```

### media queryの指定について

従来の media query の範囲指定は以下だったのですが

```
// 420px 〜 600px の時
@media (min-width: 420px) and (max-width: 600px) {
    ...
}

// 420px 以下の時（SMPの時）
@media (max-width: 420px) {
    ...
}
```

モダンなmedia query の範囲指定はいかになり、
可読性が高くなり、数学の不等号のように書けるので、直感的に理解しやすくなります。

```

// 420px 〜 600pxの時
@media (420px <= width <= 600px ) {
    ...
}

// 420px 以下の時（SMPの時）
@media (420px >= width){
    ...
}
```

### zoomの設定について

木の部分がpx固定で設定しており、SMPの場合はレイアウトが崩れてしまうので、
それを解決するにはzoomというプロパティを利用しました。

```
#container  {
    & .sakura_content, & .kirby_content, & .wado_content, & .bento_content, & .sheet_content {
        zoom: 0.5;
    }
}

```

以前は transform: scale() を利用しましたが、top や left の位置がずれる問題ありました。しかし、 zoom を使うとその問題が解消され、簡単に調整できます。

### その他

キャラクターやお弁当も **すべて CSS で作成** しています！  
特に、カービィやワドルディの丸みのあるフォルム、アニメ調の目や口、  
さらにお弁当の細かい装飾まで、すべてCSSだけで表現しました。

**実際のコード**  
https://codepen.io/uemuragame5683/pen/WbNyNog

### まとめ

今回、HTML/CSS を駆使して「カービィと花見」を作成しました。

・桜の木 ： mask-image を利用し、グラデーションで色を設定
・桜の描画 ： radial-gradient を活用して花びらを表現
・桜吹雪のアニメーション ： @keyframes を使って落下＆回転の動きを実装
・モダンな Media Query ： @media (420px <= width <= 600px ) で可読性を向上
・レスポンシブ対応 ： zoom を使い、SMP（スマホ）でもレイアウト崩れを防止

 
もし「ここをもっと知りたい！」という点があれば、コメントで教えてください！