ポップアップとアコーディオンUI

Popover
- 最上位レイヤーに表示される要素のアニメーション
- DOM階層や”z-index”の制約を受けない
- close、::backdrop クリックで閉じる
- @starting-style で動きを制御
popover属性を使ったモーダル Escキー、領域外クリックで閉じる
popover属性を使ったモーダル closeボタン、Escキー、領域外クリックで閉じる
HTML
<div class="popover_wrap">
<button popovertarget="Modal">Open Popover</button>
<div id="Modal" popover>. // popover宣言
<p>popover属性を使ったモーダルEscキー、領域外クリックで閉じる</p>
// <button class="Close" popovertarget="Modal" popovertargetaction="hidden">close</button> // closeボタン追加時
</div>
</div>
CSS
.popover_wrap {
& button {
transition-duration: 0.5s;
background: rgb(119, 193, 201);
border-radius: 1rem;
&:hover,
&:focus {
filter: invert();
}
}
& [popover] {
background: rgba(0, 0, 0, 0.7);
color: #fff;
top: 2rem;
margin-inline: auto;
}
& ::backdrop {
background: rgba(0, 0, 0, 0.2);
transition: opacity 1s ease;
}
}
// 背景をスクロールさせない //
html:has([popover]:popover-open) {
overflow: hidden;
}
[popover]:popover-open {
translate: 0 0;
}
[popover] {
transition: translate 0.5s ease-out, display 0.5s ease-out allow-discrete, overlay 0.7s ease-out allow-discrete;
translate: -10vw 0;
}
// display: none スタートではないトランジション開始時を定義するアットルール //
@starting-style {
[popover]:popover-open {
translate: 10vw 0;
}
}
ダイアログ
- showModal()など、基本jsと併用。formの戻り値にも対応
- close、::backdrop クリックで閉じる
- @starting-style で動きを制御
HTML
<button id="openBtn">dialog open</button>
<dialog id="myDialog">
<div class="inner">
<p>ダイアログの中身</p>
<button id="closeBtn">close</button>
</div>
</dialog>
CSS
#openBtn {
transition-duration: 0.5s;
background: rgb(142, 179, 152);
&:hover {
filter: invert();
}
}
html:has(#myDialog[open]) {
overflow: hidden;
pointer-events: none;
}
#myDialog {
opacity: 0;
transform: translateY(1em);
transition: opacity 0.5s ease, transform 0.3s ease;
border: #999 solid 1px;
border-radius: 10px;
padding: 0;
filter: drop-shadow(0 0 7px #00000055);
pointer-events: none; // アニメーション中にクリックされないように //
&[open] {
opacity: 1;
@starting-style {
opacity: 0;
}
}
&::backdrop {
opacity: 0;
background: rgba(100, 0, 0, 0.4);
transition: opacity 1s;
}
&[open]::backdrop {
opacity: 1;
@starting-style {
opacity: 0;
}
}
&.show {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
& #closeBtn {
margin-block: 1em 0;
background: #333;
color: #fff;
outline: none;
letter-spacing: 0.1em;
display: block;
margin-left: auto;
&:hover {
filter: invert();
}
}
}
JS
const dialog = document.getElementById("myDialog");
const openBtn = document.getElementById("openBtn");
const closeBtn = document.getElementById("closeBtn");
openBtn.addEventListener("click", () => {
dialog.showModal();
requestAnimationFrame(() => {
dialog.classList.add("show");
});
});
closeBtn.addEventListener("click", () => {
closeDialog();
});
dialog.addEventListener("click", (e) => {
if (e.target === dialog) {
closeDialog();
}
});
function closeDialog() {
dialog.classList.remove("show");
dialog.addEventListener(
"transitionend",
() => {
dialog.close();
},
{ once: true }
);
}
detailsとsummaryタグで作るアコーディオンUI
detailsとsummaryタグで作るアコーディオンUI
- name属性でdetails要素制御
- 複数のdetails要素に同じ値を持つname属性を指定すると、該当箇所だけが開いて他は自動で閉じる
坊っちゃん
親譲りの無鉄砲で小供の時から損ばかりしている。小学校に居る時分学校の二階から飛び降りて、一週間ほど腰を抜かした事がある。
ポラーノの広場
あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。
徒然草
つれづれなるまゝに、日暮らし、硯にむかひて、心にうつりゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。
HTML
<div class="accordion">
<details name="title">
<summary>坊っちゃん</summary>
<p>親譲りの無鉄砲で小供の時から損ばかりしている。小学校に居る時分学校の二階から飛び降りて、一週間ほど腰を抜かした事がある。</p>
</details>
<details name="title">
<summary>ポラーノの広場</summary>
<p>あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。</p>
</details>
<details name="title">
<summary>徒然草</summary>
<p>つれづれなるまゝに、日暮らし、硯にむかひて、心にうつりゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。</p>
</details>
</div>
CSS
.accordion {
& summary {
display: grid;
grid-template-columns: 1fr auto;
cursor: pointer;
&::-webkit-details-marker {
display: none; /* safari */
}
&::after {
content: "";
display: inline-block;
background: #000;
height: 18px;
width: 12px;
clip-path: polygon(10% 0, 100% 50%, 10% 100%, 0 100%, 90% 50%, 0 0);
transform: rotate(90deg);
transition: 0.3s transform ease-out;
}
}
& details {
&[open] {
background: #f5f5f5;
color: #c00;
}
&[open] summary::after {
transform: rotate(-90deg);
}
}
}