clip-path와 CSS Masks로 팝업을 아이리스 스 와이프 해 보았습니다.

팝업의 표시/숨기기 애니메이션은 페이드나 슬라이드로 만드는 것이 일반적입니다만, clip-path 나 CSS Masks 를 사용하면 동심원형의 와이프(아이리스 스와이프)도 만들 수 있을 것 같은… 만들 수 있었습니다. 즉 이런 것입니다.

코믹하고 팝적인 맛의 디자인에 맞을 것 같네요.
움직이는 데모는 이쪽.
  • clip-path 버전
  • mask 버전

  • 설명


  • 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 버전 모두 지우지 않았습니다. 아무래도 이런 것 같습니다. 더 이상 모른다! 푹푹!

  • 결론



    일단 "마스크는 피하고 clip-path를 활용한다. 그러나 작동하지 않는다는 것을 염두에 접근성은 담보한다"는 결론에 이르렀다. 끝.

    좋은 웹페이지 즐겨찾기