Help us understand the problem. What is going on with this article?

clip-path と CSS Masks でポップアップをアイリスワイプさせてみた

More than 1 year has passed since last update.

ポップアップの表示/非表示アニメーションはフェードやスライドで作るのが一般的ですが、 clip-path や CSS Masks を使えば同心円状のワイプ(アイリスワイプ)も作れそう…作れました。つまりこういうことです。
clip-path バージョン
コミカルでポップなテイストのデザインに合いそうですね。
動くデモはこちら。

説明

  • clip-path バージョン
    ポップアップを丸いパス( clip-path: circle(); )で切り抜き、パスのサイズをアニメーションさせています。

  • mask バージョン
    ポップアップに丸いマスク画像(実際は円形グラデーション)を適用し、マスクのサイズをアニメーションさせています。

後は面倒なのでコードを読んでください(ぶん投げ)。長いので clip-path バージョンのみ掲載します。
あ、 💬 の付いたコメントが今回の肝です。そこだけ読めば良いかと。
GitHub はこちら。

<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Iris Wipe Popup with clip-path</title>
<style>

  * {
    line-height: 1;
    margin: 0;
    padding: 0;
  }
  :root {
    font-size: 5vmin;
  }
    body {
      background-image: repeating-linear-gradient(-45deg, #0070e0, #0070e0 16px, #0080f0 16px, #0080f0 32px);
      color: #ffffff;
      font-family: "Arial Black", "Avenir-Black";
      -webkit-font-smoothing: antialiased;
      overflow-y: scroll;
      -webkit-tap-highlight-color: transparent;
    }
      article {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        height: 100%;
      }
        h1 {
          font-size: 2.0rem;
          line-height: 1.375;
          margin: 0 1.0rem 2.0rem;
          text-align: center;
        }
        button {
          background-color: rgba(0, 0, 0, 0.1);
          border: 4px solid #ffffff;
          color: #ffffff;
          cursor: pointer;
          font-family: "Arial Black", "Avenir-Black";
          font-size: 1.0rem;
          outline: none;
          padding: 0.5rem 2.0rem;
          text-transform: uppercase;
        }
        button:hover {
          background-color: rgba(255, 255, 255, 0.1);
        }
      .popup {
        background-image: repeating-linear-gradient(45deg, #e02000, #e02000 16px, #f03000 16px, #f03000 32px);

        /* 💬 クリッピングされているため、 box-shadow のようなボックス外部に適用されるスタイルは描画されない */
        /* box-shadow: 4px 4px 32px 16px rgba(0, 0, 0, 0.25); */

        display: none;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        margin: auto;
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        width: 90vmin;
        height: 90vmin;

        /* 💬 丸いクリップパスを適用する */
        /* 💬 プリフィクスは Safari 用 */
        -webkit-clip-path: circle(50%);
        clip-path: circle(50%);

        /* 💬 矩形バージョン
        -webkit-clip-path: inset(0 0 0 0);
        clip-path: inset(0 0 0 0);
        */

      }
      .popup.open {
        animation: popup-animation 750ms ease-in-out 0ms 1;
        display: flex;
      }
      .popup.close {
        animation: popup-animation 750ms ease-in-out 0ms 1 reverse;
        display: flex;
      }

      /* 💬 クリップパスのサイズをアニメーションさせる */
      /* 💬 `clip-path: circle();` は transition できない。バグ? */
      @keyframes popup-animation {
        0% {
          -webkit-clip-path: circle(0%);
          clip-path: circle(0%);

          /* 💬 矩形バージョン
          -webkit-clip-path: inset(50% 50% 50% 50%);
          clip-path: inset(50% 50% 50% 50%);
          */

        }
        100% {
          -webkit-clip-path: circle(50%);
          clip-path: circle(50%);

          /* 💬 矩形バージョン
          -webkit-clip-path: inset(0 0 0 0);
          clip-path: inset(0 0 0 0);
          */

        }
      }

</style>
<article>
  <h1>Iris Wipe Popup with clip-path</h1>
  <button onclick="openPopup()">Open popup!</button>
</article>
<aside class="popup">
  <h1>🎉 Popup! 🎉</h1>
  <button onclick="closePopup()">Close popup!</button>
</aside>
<script>
  const popup = document.querySelector('.popup')
  const openPopup = () => {
    popup.classList.add('open')
    popup.classList.remove('close')
  }
  const closePopup = () => {
    popup.classList.remove('open')
    popup.offsetWidth
    popup.classList.add('close')
    popup.addEventListener('webkitAnimationEnd', function () {
      popup.removeEventListener('webkitAnimationEnd', arguments.callee)
      popup.classList.remove('close')
    })
  }
</script>

なお、実際にプロダクトで使う際はバックドロップ( i.e. dialog::backdrop 疑似要素 )のスタイライズも必要になってくるでしょうから、ポップアップの DOM 構造は二重三重の入れ子にした方が無難です。

ポイント

  • clip-path: circle(); が CSS Transition に対応していない
    transition で clip-path: polygon() をモーフィングさせるデモはよく見かけるんですが、 clip-path: circle() はどうも未対応のようです。 もっとも、 CSS Animation で代用できるので問題はないと思います。

  • -webkit-mask-size が CSS Transition に対応していない
    もしかして上記共々バグなのかしら?しかしこれも animation で代用できるからセーフ、と思いきや…

  • -webkit-mask-size が Safari で CSS Animation に対応していない
    アウト。 mask の対応状況は割と複雑 なんですが、少なくともデモの mask バージョンは Chrome と Firefox でしか機能しませんでした。

  • Edge は全滅
    clip-path バージョンも mask バージョンもワイプされませんでした。 どうもこういうことらしいです。 もう知らない!プンプン!

おわりに

とりあえず、「 mask は避け、 clip-path を活用する、ただし機能しないことを念頭にアクセシビリティは担保する 」という結論に至りました。おしまい。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした