jackmiwamiwa devblog

フロントエンドをメインに行ったことをまとめていくサイトになります。

cssだけでアンパンマンの目をいい感じに動かす

以下の記事の続きのものになります。

qiita.com

遊びでcssを使ったアンパンマンを制作したのですが、意外とcssの学びが多かったので、学べたことをメインで共有します。

完成物

See the Pen css-only-Anpanman's face by miwa_shuntaro (@miwashutaro0611) on CodePen.

cssだけで目の動きを実装

windowにマウス乗せた時にマウスを見ているような動きをcssのみで行う場合、大まかには以下の手順でできます。

  1. 画面全体に要素をたくさん配置(今回は400個作成)
  2. .trigger:nth-child(1):hover ~ 動かしたい要素のような感じで1-400までのの状態をそれぞれ記載(cssのみだと大変なので、scssを使用。)
  3. 目の動きについては、 translateY, translateXを使用。

1. 何かの要素にホバー時に〇〇するために、要素自体を画面全体に配置。

<div class="container">
  <div class="trigger"><!-- これが400個 --></div>
</div>

display: gridを使用することで、400個の要素がいい感じに並びます。

.container {
  position: relative;
  display: grid;
  grid-template-rows: repeat(20, 5vh);
  grid-template-columns: repeat(20, 5vw);
}

表示の状態だと以下のような状態になります。

スクリーンショット 2021-07-08 1.11.59.png

2. 動かしたい要素にそれぞれの状態を記載

1つ1つcssの記載(cssのみだときついので、scssで記載) 今回は要素を動かしたいのみなので、 translateY, translateXの値を設定

.trigger {
  @for $i from 1 through 20 {
    @for $j from 1 through 20 {
      $key: ($i - 1) * 20 + $j;
      
      &:nth-child(#{$key}) {
        &:hover ~ .monitor {
          .camera {            
            &.-x .eye-x {
              transform: translateY(($i + 0.05) - (10 + 0.02) * 1px);
            }
            &.-y .eye-y {
              transform: translateX(($j - 0.05) - (10 + 0.02) * 1px);
            }
          }
        }
      }
    }
  }
}

一部ではありますが、以下のようなものが出力されます。

.trigger:nth-child(1):hover ~ .monitor .camera.-x .eye-x {
  transform: translateY(-8.97px);
}
.trigger:nth-child(1):hover ~ .monitor .camera.-y .eye-y {
  transform: translateX(-9.07px);
}
.trigger:nth-child(252):hover ~ .monitor .camera.-x .eye-x {
  transform: translateY(3.03px);
}
.trigger:nth-child(252):hover ~ .monitor .camera.-y .eye-y {
  transform: translateX(1.93px);
}
.trigger:nth-child(400):hover ~ .monitor .camera.-x .eye-x {
  transform: translateY(10.03px);
}
.trigger:nth-child(400):hover ~ .monitor .camera.-y .eye-y {
  transform: translateX(9.93px);
}

3. 目の動きについては、 translateY, translateXを使用。

<div class="eye-x">
  <div class="eye-y">
    <div class="eye eye--left">
    </div>
  </div>
</div>

3-1. eye-x, eye-yを使用して、translateを各々に指定

まとめて記載を行う場合

.hoge1 {
  transform: translateX(9.93px) translateY(10.03px);
}

.hoge2 {
  transform: translate(9.93px, 10.03px);
}

参考: https://developer.mozilla.org/ja/docs/Web/CSS/transform

のようにもできるのですが、後々以下の変更を行う場合は難しいため、eye-x, eye-yを使用して、translateを各々に指定。 (今回の制作物の場合は問題なくできます)

  • アニメーションループで各々の時間が違う場合、調整を行うことができない(xが1s, yが2sのようなもの)

実装の注意点

  • 無駄なHTML&CSSが多い(今回のものの場合、HTML430行,CSSが2500行)
  • triggerにhoverイベントを置いているため、要素自体には pointer-events: noneなどを設定しなければならない。なので、要素自体に対してhoverの登録ができない。(要素自体にhoverを設定するとtriggerのhoverイベントが消える)