LoginSignup
1
1

More than 5 years have passed since last update.

CSS animation で遊び倒す - ボタン Gooey Effect、Sass-

Last updated at Posted at 2019-02-07

CSS animation day17 となりました。

本日は、Gooey Effect を使って、別のボタンを作ります。

1. 完成版

ダウンロード (43).gif

2. 参考文献

Codepen: Gooey Menu

3. 分解してみる

❶.

まずは、前回 のコードを使って、ボタンを5つに増やしましょう。

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="css/styles.css" />
    <link
      rel="stylesheet"
      href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"
      integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <div class="container">
      <div class="gooey">
        <input type="checkbox" id="start" />
        <label for="start">
          <div class="menu-open-button">
            <i class="fas fa-plus plus"></i>
          </div>
        </label>
        <div class="circle1">
          <i class="far fa-envelope mail"></i>
        </div>
        <div class="circle2">
          <i class="far fa-question-circle question"></i>
        </div>
        <div class="circle3">
          <i class="far fa-envelope mail"></i>
        </div>
        <div class="circle4">
          <i class="far fa-question-circle question"></i>
        </div>
        <div class="circle5">
          <i class="far fa-question-circle question"></i>
        </div>
      </div>

      <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
        <defs>
          <filter id="filter">
            <feGaussianBlur
              in="SourceGraphic"
              stdDeviation="20"
              result="blur"
            />
            <feColorMatrix
              in="blur"
              mode="matrix"
              values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 17 -7"
              result="filter"
            />
            <feBlend in="SourceGraphic" in2="filter" />
          </filter>
        </defs>
      </svg>
    </div>
  </body>
</html>
styles.css
body {
  margin: 0;
  padding: 0;
}

.container {
  position: relative;
  width: 100%;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.gooey {
  width: 100%;
  height: 100vh;
  margin: 0 auto;
  filter: url("#filter");
}

.plus {
  font-size: 3em;
  color: #fff;
  padding: 27px 29px;
}

.mail {
  font-size: 3em;
  color: #fff;
  padding: 26px;
}

.question {
  font-size: 3em;
  color: #fff;
  padding: 26px;
}

#start {
  display: none;
}

.menu-open-button {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: green;
  cursor: pointer;
  transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  transition-duration: 400ms;
  transform: scale(1, 1);
  z-index: 2;
}

.menu-open-button:hover {
  transform: scale(1.1, 1.1);
}

.circle1,
.circle2,
.circle3,
.circle4,
.circle5 {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: green;
  transition: transform ease-out 200ms;
  transform: translate3d(0, 0, 0);
}

次に、これらにアニメーションを設定します。
イメージは、ボタンを押したら、下側に半円を描くようにボタンが動くようにします。

styles.css
#start:checked ~ .circle2 {
  transform: translate3d(120px, 130px, 0);
  transition-timing-function: ease;
  transition-duration: 600ms;
}

#start:checked ~ .circle3 {
  transform: translate3d(0, 200px, 0);
  transition-timing-function: ease;
  transition-duration: 600ms;
}

#start:checked ~ .circle4 {
  transform: translate3d(-120px, 130px, 0);
  transition-timing-function: ease;
  transition-duration: 600ms;
}

#start:checked ~ .circle5 {
  transform: translate3d(-200px, 20px, 0);
  transition-timing-function: ease;
  transition-duration: 600ms;
}

#start:checked ~ div i {
  animation: blight 600ms ease-in forwards;
}

#start:checked + label div i {
  transform: rotateZ(-45deg);
  transition-timing-function: ease;
  transition-duration: 300ms;
}

@keyframes blight {
  0% {
    opacity: 0.6;
  }
  100% {
    opacity: 1;
  }
}

ダウンロード (43).gif

できました! 

・・・

ただ、なんというか・・・
コードが長いです。読む気になりません。
どうにかリファクタリングできないでしょうか?
CSS でループ文使えれば・・・ 

ということで、Sass を使ってみたいと思います。
Sass とは?という方は、こちら がわかりやすいです。

エディターは、VSCode を使用しているため、Sass の導入は、こちら を参考に、簡単に始められます。 

Live Sass Compiler を追加して、ファイルの名前をscss に変更し、
先ほどのcss を変更していきます。

① 継承 

styles.scss
.circle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: green;
}

.menu-open-button {
  @extend .circle;
  ...
}

.circle1,
.circle2,
.circle3,
.circle4,
.circle5 {
  @extend .circle;
  ...
}

緑丸ボタンの設定を、.circle{} として、作り
@extend で、circle 1~5 と, menu-open-button へ継承してます。 

別の書き方として、@mixin@include を使った書き方もできます。

styles.scss
@mixin circle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: green;
}


.menu-open-button {
  @include circle;
  ...
}

.circle1,
.circle2,
.circle3,
.circle4,
.circle5 {
  @include circle;
  ...
}

こちらも同じ結果となります。
extend とかなり似てますが、何が違うのでしょうか?

@mixin, @include の場合、引数を使うことができ、

styles.scss
@mixin icon($padding) {
  font-size: 3em;
  color: #fff;
  padding: $padding;
}

というように、設定でき

styles.css
//before

.plus {
  font-size: 3em;
  color: #fff;
  padding: 27px 29px;
}

.mail {
  font-size: 3em;
  color: #fff;
  padding: 26px;
}

.question {
  font-size: 3em;
  color: #fff;
  padding: 26px;
}

このコードが、

styles.scss

//after

.plus {
  @include icon(27px 29px);
}

.mail,
.question {
  @include icon(26px);
}

こう書けます!!
このように、@mixin, @includeを使えば、引数を与えて使いまわすことができます!

もっと詳しく知りたい方は、

Web制作者のためのSassの教科書 改訂2版 Webデザインの現場で必須のCSSプリプロセッサ Web制作者のための教科書シリーズ

hajipon.com に大変わかりやすく書いてありましたので、ぜひご一読ください。


② ネスト

Sass では、CSSを入れ子で書いていくことができます。
この機能で、コードの記述量が大幅に減り、メンテナンス性が向上するでしょう。ただし、使いすぎるとネストが深くなり、可読性が落ちるので、気をつけましょう!

styles.css
//before


 body {
  margin: 0;
  padding: 0;
}

.container {
  position: relative;
  width: 100%;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.gooey {
  width: 100%;
  height: 100vh;
  margin: 0 auto;
  filter: url("#filter");
}

.plus {
  font-size: 3em;
  color: #fff;
  padding: 27px 29px;
}

.mail {
  font-size: 3em;
  color: #fff;
  padding: 26px;
}

.question {
  font-size: 3em;
  color: #fff;
  padding: 26px;
}

#start {
  display: none;
}

.menu-open-button {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: green;
  cursor: pointer;
  transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  transition-duration: 400ms;
  transform: scale(1, 1);
  z-index: 2;
}

.menu-open-button:hover {
  transform: scale(1.1, 1.1);
}

.circle1,
.circle2 {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: green;
  transition: transform ease-out 200ms;
  transform: translate3d(0, 0, 0);
}

#start:checked ~ .circle1 {
  transform: translate3d(0, -150px, 0);
  transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  transition-duration: 800ms;
}

#start:checked ~ .circle2 {
  transform: translate3d(0, -300px, 0);
  transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  transition-duration: 800ms;
}

#start:checked ~ div i {
  animation: blight 600ms ease-in forwards;
}

#start:checked + label div i {
  transform: rotateZ(-45deg);
  transition-timing-function: ease;
  transition-duration: 300ms;
}

@keyframes blight {
  0% {
    opacity: 0.6;
  }
  100% {
    opacity: 1;
  }
}
styles.scss
//after

body {
  margin: 0;
  padding: 0;
}

.container {
  position: relative;
  width: 100%;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.gooey {
  width: 100%;
  height: 100vh;
  margin: 0 auto;
  filter: url("#filter");
}

@mixin icon($padding) {
  font-size: 3em;
  color: #fff;
  padding: $padding;
}

.plus {
  @include icon(27px 29px);
}

.mail,
.question {
  @include icon(26px);
}

@mixin circle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: green;
}

.menu-open-button {
  @include circle;
  cursor: pointer;
  transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  transition-duration: 400ms;
  transform: scale(1, 1);
  z-index: 2;
  &:hover {
    transform: scale(1.1, 1.1);
  }
}

.circle1,
.circle2,
.circle3,
.circle4,
.circle5 {
  @include circle;
  transition: transform ease-out 200ms;
  transform: translate3d(0, 0, 0);
}

#start {
  display: none;
  &:checked {
    transition-timing-function: ease;
    transition-duration: 600ms;
    ~ div i {
      animation: blight 600ms ease-in forwards;
    }
    + label {
      div i {
        transform: rotateZ(-45deg);
        transition-timing-function: ease;
        transition-duration: 300ms;
      }
    }
    ~ .circle1 {
      transform: translate3d(200px, 20px, 0);
    }
    ~ .circle2 {
      transform: translate3d(120px, 130px, 0);
    }
    ~ .circle3 {
      transform: translate3d(0px, 200px, 0);
    }
    ~ .circle4 {
      transform: translate3d(-120px, 130px, 0);
    }
    ~ .circle5 {
      transform: translate3d(-200px, 20px, 0);
    }
  }
}

@keyframes blight {
  0% {
    opacity: 0.6;
  }
  100% {
    opacity: 1;
  }
}

&: を使うことで、入れ子の書き方ができ、記述量が少なくなりました。ただし、やはり使いすぎると読みにくくなるので、注意が必要ですね。

本日はここまでです。
明日から、Sass をいっぱい使っていこうと思います。
それではまた明日〜

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1