ポップアップの表示/非表示アニメーションはフェードやスライドで作るのが一般的ですが、 clip-path や CSS Masks を使えば同心円状のワイプ(アイリスワイプ)も作れそう…作れました。つまりこういうことです。
コミカルでポップなテイストのデザインに合いそうですね。
動くデモはこちら。
説明
-
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 を活用する、ただし機能しないことを念頭にアクセシビリティは担保する 」という結論に至りました。おしまい。