Więcej opcji stylizacji <details>

Data publikacji: 6 listopada 2024 r.

W Chrome 131 masz więcej opcji stylizacji struktury elementów <details><summary>. Możesz teraz używać tych elementów podczas tworzenia widżetów z otwartymi informacjami lub widżetów w formie harmonijki.

W szczególności zmiany wprowadzone w Chrome 131 umożliwiają używanie właściwości display w tych elementach i dodawanie pseudoelementu ::details-content do stylizacji części, która się rozwija i zwija.

Obsługa przeglądarek

  • Chrome: 131.
  • Edge: 131.
  • Firefox: nieobsługiwane.
  • Safari: nieobsługiwane.

Ustawienie display w elemencie <details>

Dotychczas nie można było zmienić typu wyświetlania elementu <details>. To ograniczenie zostało złagodzone, dzięki czemu możesz na przykład używać układów siatki lub elastycznych w elemencie <details>.

W tym przykładzie wyłączny akordeon składa się z kilku elementów <details> umieszczonych obok siebie. Po rozwinięciu jednego z elementów <details> jego zawartość jest umieszczana obok elementu <summary>.

Prezentacja

Nagrywanie

Nagrywanie https://codepen.io/web-dot-dev/pen/VwoBQjY w Chrome 131

Aby to osiągnąć, użyj układu flex w elemencie <details>, stosując ten kod CSS:

details {
  display: flex;
  flex-direction: row;
}

Dozwolone są też inne wartości wyświetlania, np. grid.

Uwaga dotycząca używania display: inline

Wartość display, która może prowadzić do nieoczekiwanego wyniku, to inline. Nie dlatego, że nie działa, ale z powodu ograniczeń parsowania HTML.

Umieszczenie elementu <details> w akapitach powoduje, że parsujący HTML musi najpierw zamknąć otwarty akapit, zgodnie z definicją podaną w sekcji 13.2.6.4.7 standardu HTML:

tag startu, którego nazwa to: „address”, „article”, „aside”, „blockquote”, „center”, „details”, „dialog”, „dir”, „div”, „dl”, „fieldset”, „figcaption”, „figure”, „footer”, „header”, „hgroup”, „main”, „menu”, „nav”, „ol”, „p”, „search”, „section”, „summary”, „ul”;

Jeśli stos otwartych elementów zawiera element p w zakresie przycisku, zamknij element p. Wstaw element HTML dla tokena.

W efekcie <details> przepływa w kierunku bloku niezależnie od tego, czy ustawisz display: inline.

Na przykład ten znacznik

<p>Hello <details>…</details> world</p>

Po przeanalizowaniu wygląda tak:

<p>Hello </p><details>…</details> world<p></p>

Możesz to sprawdzić samodzielnie w tym filmie demonstracyjnym, sprawdzając zanalizowany znacznik za pomocą narzędzi deweloperskich w Chrome.

Pamiętaj, że dotyczy to tylko zagnieżdżania elementu <details> w elemencie <p>. Używanie display: inline na <details> w <div> działa prawidłowo.

Pseudo ::details-content

W przeglądarkach element <details> jest implementowany za pomocą Shadow DOM. Zawiera jeden element <slot> dla podsumowania (z domyślnym podsumowaniem podrzędnym) i element <slot> dla wszystkich pozostałych treści, czyli wszystkich elementów podrzędnych elementu <details> z wyjątkiem elementu <summary>.

<details>
  ↳ #shadow-root (user-agent)
      <slot id="details-summary">
        <summary>Details</summary>
        <!-- The summary goes here -->
      </slot>
      <slot id="details-content">
        <!-- All content goes here -->
      </slot>
</details>

Oprócz korzystania z większej liczby typów wyświetlania w przypadku <details> możesz teraz kierować reklamy na miejsce docelowe treści za pomocą pseudoelementu ::details-content. Możesz użyć tego pseudoklasy do nadania stylu kontenerowi, który otacza zawartość elementu <details>.

details::details-content {
  border: 5px dashed hotpink;
}

Aby zastosować styl tylko wtedy, gdy element <details> jest otwarty, przed nim umieść selektor [open].

[open]::details-content {
  border: 5px dashed hotpink;
}

Stylizację pseudoelementu ::details-content zalecamy stosować tylko wtedy, gdy element <details> jest w stanie [open].

Prezentacja

Nagrywanie

Nagrywanie https://codepen.io/web-dot-dev/pen/oNKMEYv w Chrome 131

W arkuszu stylów UA typ display elementu ::details-content ma wartość block, podczas gdy wcześniej była to wartość display: contents. W niektórych przypadkach ta zmiana może działać na Twoją niekorzyść, np. w przypadku ujawnionego materiału, który opiera się na height: 100%. Jeśli to stanowi dla Ciebie problem, możesz go rozwiązać, przywracając typ display do contents, tak jak w tym przykładzie: details[open]::details-content { display: contents; }.

Animowanie pseudo ::details-content

Możesz animować treść elementu <details>, gdy się rozszerza. W tym przykładzie szerokość zmienia się z 0px na 300px.

::details-content {
  transition: width 0.5s ease, content-visibility 0.5s ease allow-discrete;
  width: 0;
}

[open]::details-content {
  width: 300px;
}

Oprócz przejścia właściwości width musisz też przenieść właściwość content-visibility. Wynika to z tego, że jego wartość zmienia się w stanie nieotwartym i otwartym, zgodnie z definicją w arkuszu stylów User-Agent. Ta właściwość jest właściwością, którą można animować oddzielnie, dlatego do jej działania potrzebujesz kwotowania allow-discrete.

Dodano do wcześniej udostępnionego ekskluzywnego dema harmonijki:

Prezentacja

Nagrywanie

Nagrywanie https://codepen.io/web-dot-dev/pen/XWvBZNo w Chrome 131

Element height może też być animowany. Aby animować do height: auto, musisz użyć interpolate-size lub calc-size(). Aby dodatkowo zapobiec wyciekaniu treści z pseudonimu ::details-content, zastosuj overflow: clip.

::details-content {
    transition: height 0.5s ease, content-visibility 0.5s ease allow-discrete;
    height: 0;
    overflow: clip;
}

/* Browser supports interpolate-size */
@supports (interpolate-size: allow-keywords) {
    :root {
        interpolate-size: allow-keywords;
    }

    [open]::details-content {
        height: auto;
    }
}

/* Fallback for browsers with no interpolate-size support */
@supports not (interpolate-size: allow-keywords) {
    [open]::details-content {
        height: 150px;
        overflow-y: scroll; /* In case the contents should be taller than 150px */
    }
}

Ten kod możesz zobaczyć w działaniu w następującym pokazie, który jest inspirowany zakładką w Material UI. Zawartość każdego elementu <details> ładnie się animuje.

Prezentacja

Nagrywanie

Nagrywanie https://codepen.io/web-dot-dev/pen/ExqpQZM w Chrome 131

W przeglądarkach, które nie obsługują ::details-content, komponent nadal działa prawidłowo. Jedyną rzeczą, której użytkownicy nie widzą, jest animacja.

Wykrywanie cech

Aby umożliwić wykrywanie w CSS obsługi pseudoelementu ::details-content, użyj tego fragmentu kodu.

@supports selector(::details-content) {
  
}

Możesz też użyć tej funkcji do wykrywania, czy przeglądarka używana przez odwiedzającego obsługuje dodatkowe wartości wyświetlania.

Ułatwienia dostępu

Wprowadzenie pseudoelementu ::details-content i możliwość zmiany typu wyświetlania nie mają wpływu na dostępność elementu <details>.

Jak do tej pory, przynajmniej w przypadku przeglądarek opartych na Chromium i zgodnie ze standardem HTML, element <details> można wyszukiwać i automatycznie rozwija się, gdy przeglądarka próbuje przewinąć do ukrytej zawartości w odpowiedzi na znajdowanie na stronie, przewijanie do fragmentu tekstu i nawigację po fragmencie elementu. To się nie zmienia.

Zanim jednak użyjesz wyłącznych harmonijek, zastanów się, czy jest to pomocne, czy szkodliwe dla użytkowników. Chociaż użycie wyłącznego układu harmonijkowego zmniejsza ilość miejsca na treści, użytkownicy mogą musieć otworzyć wiele elementów, aby zapoznać się z wszystkimi informacjami. Może to być frustrujące dla użytkowników, którzy chcą przeglądać wiele elementów jednocześnie.

A jak stylizować znacznik?

Obecnie styl markera listy nie jest interoperacyjny, ponieważ istnieją dwa różne podejścia: jedno stosowane przez Gecko i (obecnie) Chromium oraz drugie przez WebKit (które było wcześniej używane również w Chromium).

Gdy funkcja będzie interoperacyjna, chcemy zapewnić Ci większą kontrolę nad stylami znaczników.

Więcej wersji demonstracyjnych

Na koniec kilka dodatkowych prezentacji. Wszystkie używają ::details-content.

UIKit Accordion

Prezentacja

Nagrywanie

Nagrywanie https://codepen.io/web-dot-dev/pen/rNXrJyQ w Chrome 131

To demo zostało stworzone na podstawie poziomych kart UIKit. Kod jest praktycznie taki sam jak w udostępnionym wcześniej interfejsie Material UI.

Częściowo otwarty widżet

Prezentacja

Nagrywanie

Nagrywanie https://codepen.io/web-dot-dev/pen/PoMBQmW w Chrome 131

W tym filmie widać częściowo otwarty widżet, którego zawartość jest już widoczna na ekranie. Aby to osiągnąć, wartość content-visibility jest zawsze ustawiana na visible. Element height jest animowany za pomocą elementu calc-size(), ponieważ jest to związane z wykonywaniem obliczeń.

::details-content {
  content-visibility: visible; /* Make it always visible */
    
  transition: height 0.5s ease;
  height: 150px;
  overflow: clip;
}

[open]::details-content {
  height: calc-size(auto, size + 0.5rem); /* calc-size because we need to add a length */
}

Ze względu na wygodę stylizacji zawartość jest ujęta w element DIV. Element DIV otrzymuje style układu, takie jak padding, a pseudoelement ::details-content jest animowany.