CREATIVE X 第2弾
CREATIVE X 第2弾
2018.09.17
#163
それいけ!フロントエンド

SVGやclip-pathは必要なし!平行四辺形のクリッピングマスクをかけてアニメーションさせてみよう

はっちゃん

こんにちは、フロントエンドエンジニアのはっちゃんです。

マスクと言えばclip-pathが有名ですが、IEが全滅なんですよね。まだまだ案件で使うには敷居が高いプロパティな気がしています……。

さて今回はSVGとclip-pathなしで画像にマスクをかけて、さらに簡単なアニメーションを作ってみようと思います。

SVGとclip-pathを使ったマスクは以前まろさんが書いてますので、こちらをご覧ください。

考え方


レイヤーを2枚用意し、上のレイヤーをtransformで変形、overflowでマスクをかけます。

下のレイヤーは、上のレイヤーのtransfromに影響されるので、同じ角度だけ戻してあげます。

もうこれだけです! HTMLとCSSは下記になります。

HTML

<div class="object">
    <img src="https://82mou.github.io/image/hatsushi_mask.png" alt="">
</div>

CSS

.object {
  position: relative;
  width: 300px;
  height: 300px;
  margin: 30px auto 0;
  overflow: hidden;
  border-radius: 0;
  transform: skew(-20deg);
  img {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 500px;
    transform: translate(-50%, -50%) skew(20deg);
  }
}

DEMO

See the Pen transform skew mask by k_hatsushi (@hatsushi_kazuya) on CodePen.

ちゃんとマスクされていますね。また、平行四辺形はCSSで作ったものなので、容易にアニメーションさせることができます。

アニメーションさせてみる

CSSのtransitionプロパティを設定して動かしてみましょう。

状態変更用のclassをdata属性に持たせ、四角、丸、ひし形のボタンを作成し、押したら変形するようにします。

HTMLとCSSとJSは下記になります。

HTML

<div id="js-object" class="object">
    <img src="https://82mou.github.io/image/hatsushi_mask.png" alt="">
</div>

<ul class="nav">
  <li>
    <div class="square js-transform" data-object-class="is-square">
      <span class="text">square</span>
    </div>
  </li>
  <li>
    <div class="circle js-transform" data-object-class="is-circle">
      <span class="text">circle</span>
    </div>
  </li>
  <li>
    <div class="parallelogram js-transform" data-object-class="is-parallelogram">
      <span class="text">parallelogram</span>
    </div>
  </li>
</ul>

CSS

li {
  list-style: none;
}

.object {
  position: relative;
  width: 300px;
  height: 300px;
  margin: 30px auto 0;
  overflow: hidden;
  will-change: transform;
  transition: all 0.6s;
  &.is-square {
    width: 300px;
    height: 300px;
    border-radius: 0;
    transform: skew(0deg);
    img {
      transform: translate(-50%, -50%) skew(0deg);
    }
  }
  &.is-circle {
    width: 300px;
    height: 300px;
    border-radius: 50%;
    transform: skew(0deg);
    img {
      will-change: transform;
      transform: translate(-50%, -50%) skew(0deg);
    }
  }
  &.is-parallelogram {
    border-radius: 0;
    transform: skew(-20deg);
    img {
      transform: translate(-50%, -50%) skew(20deg);
    }
  }
  img {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 500px;
    transform: translate(-50%, -50%) skew(0deg);
    transition: all 0.6s;
  }
}
.nav {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 60px;
  li {
    padding: 0 30px;
    .square {
      position: relative;
      width: 100px;
      height: 100px;
      background-color: #8FD5DF;
    }
    .circle {
      position: relative;
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background-color: #F2CEE9;
    }
    .parallelogram {
      position: relative;
      width: 100px;
      height: 100px;
      margin: 0 20px;
      transform: skew(-30deg);
      background-color: #FBF9EC;
      .text {
        transform: translate(-50%, -50%) skew(30deg);
      }
    }
  }
}

.text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 12px;
}

JS

const $object = $('#js-object'),
      $transform = $('.js-transform');

$transform.on('click', (e) => {
  $object.removeClass((index, className) => {
   return (className.match(/\bis-\S+/g) || []).join(' ')
  });
  $object.addClass($(e.currentTarget).data('object-class'));
});

完成

See the Pen transform skew mask by k_hatsushi (@hatsushi_kazuya) on CodePen.

平行四辺形を経由する場合のみ若干画像がぶれますが、形状をアニメーションさせることができました。

まとめ

いかがでしたか?

背景色のアニメーションなどを加えるなど、工夫次第で印象に残るアニメーションを実現できそうですね! 何かの参考になれば幸いです、それではまた。