🦒

ハンバーガーメニューの≡を×に変形させるアニメーション

2021/04/05に公開

はじめに

タイトルのとおり、ハンバーガーメニューの≡や=を×に変形させるアニメーションです。
当初は横棒を正方形の対角線にするために正方形の高さを√2で割って無理矢理実装していましたが、今回良い感じに実装できたため同じ悩みを持っている同志がいると信じてシェアします。正直普通過ぎて「はぁ?」となるかもしれませんが、大目に見てください。
また、もっとシンプルにできたり、おしゃれな実装方法を知っている方がいましたらとても知りたいので教えて頂きたいです。

まずは完成品

ソースコード
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hamburger</title>
    <style>
        *,
        *::before,
        *::after {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        :root {
            --bar-thickness: 5px;
        }

        section {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }

        body{background-color: #eee;}

        .hamburger {
            width: 40px;
            height: 40px;
            position: relative;
            transition: transform .5s;
        }

        .hamburger:hover {transform: rotate(90deg);}

        .hamburger div {
            position: absolute;
            width: 100%;
            height: 5px;
            background-color: #333;
            border-radius: 3px;
            transform-origin: 50% 50%;
            transition: .5s .25s;
        }

        .hamburger div:nth-child(1){top: 0;}
        .hamburger div:nth-child(2){top: calc(50% - var(--bar-thickness) / 2);}
        .hamburger div:nth-child(3){top: calc(100% - var(--bar-thickness));}

        .hamburger:hover div{top: calc(50% - var(--bar-thickness) / 2);}
        .hamburger:hover div:nth-child(1){transform: rotate(-135deg);}
        .hamburger:hover div:nth-child(2){opacity: 0;}
        .hamburger:hover div:nth-child(3){transform: rotate( 135deg);}
    </style>
</head>
<body>
    <section>
        <div class="hamburger">
            <div></div>
            <div></div>
            <div></div>
        </div>
    </section>
</body>
</html>

解説

先ずは横棒のtransform-originを棒の中心に設定します。

.hamburger div {
    position: absolute;
    width: 100%;
    height: 5px;
    background-color: #333;
    border-radius: 3px;
    transform-origin: 50% 50%;
    transition: .5s .25s;
}

次に、一番下の棒をbottom: 0ではなく、topから指定します。こうすることによってソースに統一感が出て綺麗です。(正直bottomで指定しても全く問題はありません)

.hamburger div:nth-child(1){top: 0;}
.hamburger div:nth-child(2){top: calc(50% - var(--bar-thickness) / 2);}
.hamburger div:nth-child(3){top: calc(100% - var(--bar-thickness));}

最後に、3つの横棒を中心に寄せてから回転させます。135°にしているのは、45°と比べて軽快さがでるからです。このあたりは好みにお任せします。

.hamburger:hover div{top: calc(50% - var(--bar-thickness) / 2);}
.hamburger:hover div:nth-child(1){transform: rotate(-135deg);}
.hamburger:hover div:nth-child(2){opacity: 0;}
.hamburger:hover div:nth-child(3){transform: rotate( 135deg);}

あとはいい感じにtransitionを設定して完成です。

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hamburger</title>
    <style>
        *,
        *::before,
        *::after {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        :root {
            --bar-thickness: 5px;
        }

        section {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }

        body{background-color: #eee;}

        .hamburger {
            width: 40px;
            height: 40px;
            position: relative;
            transition: transform .5s;
        }

        .hamburger:hover {transform: rotate(90deg);}

        .hamburger div {
            position: absolute;
            width: 100%;
            height: 5px;
            background-color: #333;
            border-radius: 3px;
            transform-origin: 50% 50%;
            transition: .5s .25s;
        }

        .hamburger div:nth-child(1){top: 0;}
        .hamburger div:nth-child(2){top: calc(50% - var(--bar-thickness) / 2);}
        .hamburger div:nth-child(3){top: calc(100% - var(--bar-thickness));}

        .hamburger:hover div{top: calc(50% - var(--bar-thickness) / 2);}
        .hamburger:hover div:nth-child(1){transform: rotate(-135deg);}
        .hamburger:hover div:nth-child(2){opacity: 0;}
        .hamburger:hover div:nth-child(3){transform: rotate( 135deg);}
    </style>
</head>
<body>
    <section>
        <div class="hamburger">
            <div></div>
            <div></div>
            <div></div>
        </div>
    </section>
</body>
</html>

おわり

プログラミングしているときにありがちですが、今思うとなんでこれが思いつかなかったんだろう...

おまけ

=から×はdiv1つで実装できました。

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Hamburger2</title>
  <style>
    *,
    *::before,
    *::after {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    :root {
      --bar-height: 20px;
    }

    section {
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
    }

    body {background: #333;}

    .hamburger {
      width: 100px;
      height: 100px;
      position: relative;
      transition: transform .5s;
    }

    .hamburger:hover {transform: rotate(90deg);}

    .hamburger::before,
    .hamburger::after {
    content: "";
    display: block;
    width: 100%;
    height: var(--bar-height);
    border-radius: 5px;
    background: #eee;
    position: absolute;
    transition: .5s .25s;
    }

    .hamburger::before {top: calc(50% - var(--bar-height) * 1.5);}

    .hamburger::after  {top: calc(50% + var(--bar-height) / 2);}

    .hamburger:hover::before,
    .hamburger:hover::after {top: calc(50% - var(--bar-height) / 2);}

    .hamburger:hover::before {transform: rotate(-135deg);}

    .hamburger:hover::after  {transform: rotate( 135deg);}
  </style>
</head>
<body>
  <section>
    <div class="hamburger"></div>
  </section>
</body>
</html><meta name="viewport" content="width=device-width, initial-scale=1.0">

Discussion