最小限のCSSフレームワーク pico css -コンポーネント-


前回の続きです。

blog1.mammb.com


アコーディオン

<details open>
  <summary>Accordion 1</summary>
  <p>
    Flamingos are known for their bright pink feathers and distinctive long necks.
    These birds are social creatures that live in large groups, and a group of flamingos is called a flamboyance.
    They can often be seen standing on one leg, which helps them conserve body heat.
  </p>
</details>
<hr />
<details>
  <summary>Accordion 2</summary>
  <p>
    Flamingos are known for their bright pink feathers and distinctive long necks.
    These birds are social creatures that live in large groups, and a group of flamingos is called a flamboyance.
    They can often be seen standing on one leg, which helps them conserve body heat.
  </p>
</details>

<details open>
  <summary role="button" class="outline">Primary outline</summary>
  <p>
    Flamingos are known for their bright pink feathers and distinctive long necks.
    These birds are social creatures that live in large groups, and a group of flamingos is called a flamboyance.
    They can often be seen standing on one leg, which helps them conserve body heat.
  </p>
</details>
<hr />
<details>
  <summary role="button" class="outline secondary">Secondary outline</summary>
  <p>...</p>
</details>


カード

<article>
  <header>Header</header>
    Flamingos are known for their bright pink feathers and distinctive long necks.
    These birds are social creatures that live in large groups, and a group of flamingos is called a flamboyance.
    They can often be seen standing on one leg, which helps them conserve body heat.
  <footer>Footer</footer>
</article>


ドロップダウン

<details class="dropdown">
  <summary>Dropdown</summary>
  <ul>
    <li><a href="#">Solid</a></li>
    <li><a href="#">Liquid</a></li>
    <li><a href="#">Gas</a></li>
    <li><a href="#">Plasma</a></li>
  </ul>
</details>

<select name="select" aria-label="Select" required>
  <option selected disabled value="">Select</option>
  <option>Solid</option>
  <option>Liquid</option>
  <option>Gas</option>
  <option>Plasma</option>
</select>

<details class="dropdown">
  <summary role="button" class="outline">
    Select phases of matter...
  </summary>
  <ul>
    <li>
      <label>
        <input type="checkbox" name="solid" />
        Solid
      </label>
    </li>
    <li>
      <label>
        <input type="checkbox" name="liquid" />
        Liquid
      </label>
    </li>
    <li>
      <label>
        <input type="checkbox" name="gas" />
        Gas
      </label>
    </li>
    <li>
      <label>
        <input type="checkbox" name="plasma" />
        Plasma
      </label>
    </li>
  </ul>
</details>


グループ

<div role="group">
  <button>Button</button>
  <button class="secondary">Button</button>
  <button class="contrast">Button</button>
</div>

<form role="search">
  <input name="search" type="search" placeholder="Search" />
  <input type="submit" value="Search" />
</form>


ローディング

<article aria-busy="true"></article>
<hr/>
<button aria-busy="true" class="outline">Please wait…</button>


モーダル

<dialog open>
  <article>
    <h2>Confirm Your Membership</h2>
    <p>
      Thank you for signing up for a membership!
      Please review the membership details below:
    </p>
    <footer>
      <button className="secondary">
        Cancel
      </button>
      <button>Confirm</button>
    </footer>
  </article>
</dialog>

// Config
const isOpenClass = "modal-is-open";
const openingClass = "modal-is-opening";
const closingClass = "modal-is-closing";
const scrollbarWidthCssVar = "--pico-scrollbar-width";
const animationDuration = 400; // ms
let visibleModal = null;

// Toggle modal
const toggleModal = (event) => {
  event.preventDefault();
  const modal = document.getElementById(event.currentTarget.dataset.target);
  if (!modal) return;
  modal && (modal.open ? closeModal(modal) : openModal(modal));
};

// Open modal
const openModal = (modal) => {
  const { documentElement: html } = document;
  const scrollbarWidth = getScrollbarWidth();
  if (scrollbarWidth) {
    html.style.setProperty(scrollbarWidthCssVar, `${scrollbarWidth}px`);
  }
  html.classList.add(isOpenClass, openingClass);
  setTimeout(() => {
    visibleModal = modal;
    html.classList.remove(openingClass);
  }, animationDuration);
  modal.showModal();
};

// Close modal
const closeModal = (modal) => {
  visibleModal = null;
  const { documentElement: html } = document;
  html.classList.add(closingClass);
  setTimeout(() => {
    html.classList.remove(closingClass, isOpenClass);
    html.style.removeProperty(scrollbarWidthCssVar);
    modal.close();
  }, animationDuration);
};

// Close with a click outside
document.addEventListener("click", (event) => {
  if (visibleModal === null) return;
  const modalContent = visibleModal.querySelector("article");
  const isClickInside = modalContent.contains(event.target);
  !isClickInside && closeModal(visibleModal);
});

// Close with Esc key
document.addEventListener("keydown", (event) => {
  if (event.key === "Escape" && visibleModal) {
    closeModal(visibleModal);
  }
});

// Get scrollbar width
const getScrollbarWidth = () => {
  const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
  return scrollbarWidth;
};

// Is scrollbar visible
const isScrollbarVisible = () => {
  return document.body.scrollHeight > screen.height;
};


ナビ

<nav>
  <ul>
    <li><strong>Acme Corp</strong></li>
  </ul>
  <ul>
    <li><a href="#">About</a></li>
    <li><a href="#">Services</a></li>
    <li><button class="secondary">Products</button></li>
  </ul>
</nav>


パンくずリスト

<nav
  aria-label="breadcrumb"
  style="--pico-nav-breadcrumb-divider: '✨';"
>
  <ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">Services</a></li>
    <li>Design</li>
  </ul>
</nav>


プログレスバー

<progress />

<progress value="76" max="100" />


ツールチップ

<button data-tooltip="Top">Top</button>
<button data-tooltip="Right" data-placement="right">Right</button>
<button data-tooltip="Bottom" data-placement="bottom">Bottom</button>
<button data-tooltip="Left" data-placement="left">Left</button>