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


Popover

  • 最上位レイヤーに表示される要素のアニメーション
  • DOM階層や”z-index”の制約を受けない
  • close、::backdrop クリックで閉じる
  • @starting-style で動きを制御

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);
    }
  }
}
CSS

前の記事

コンテナクエリ(@container)