Más opciones para aplicar diseño <details>

Publicado: 6 de noviembre de 2024

A partir de Chrome 131, tienes más opciones para diseñar la estructura de los elementos <details> y <summary>. Ahora puedes usar estos elementos cuando compiles widgets de divulgación o acordeón.

En particular, los cambios introducidos en Chrome 131 permiten usar la propiedad display en estos elementos y agregan un seudoelemento ::details-content para aplicar diseño a la parte que se expande y se contrae.

Browser Support

  • Chrome: 131.
  • Edge: 131.
  • Firefox: 143.
  • Safari: 18.4.

Source

Cómo configurar display en el elemento <details>

Históricamente, no era posible cambiar el tipo de visualización del elemento <details>. Esta restricción se relajó, lo que te permite, por ejemplo, usar diseños de cuadrícula o flexibles en el elemento <details>.

En el siguiente ejemplo, el acordeón exclusivo consta de varios elementos <details> colocados uno al lado del otro. Cuando se expande uno de los elementos <details>, su contenido se coloca junto al <summary>.

Demostración

Grabación

Grabación de https://codepen.io/web-dot-dev/pen/VwoBQjY en Chrome 131

Esto se logra usando un diseño flexible en el elemento <details>, con el siguiente CSS:

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

También se permiten otros valores de visualización, como grid.

Nota sobre el uso de display: inline

Un valor de display que puede tener un resultado inesperado es inline. No es porque no funcione, sino por las limitaciones del analizador de HTML.

Cuando se coloca un elemento <details> dentro de un párrafo, se obliga al analizador de HTML a cerrar primero el párrafo abierto, como se define en la sección 13.2.6.4.7 del estándar HTML:

Una etiqueta de inicio cuyo nombre es uno de los siguientes: "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"

Si la pila de elementos abiertos tiene un elemento p en el alcance del botón, cierra un elemento p. Inserta un elemento HTML para el token.

Como resultado, el flujo de <details> se produce en la dirección del bloque, independientemente de que hayas establecido display: inline.

Por ejemplo, el siguiente lenguaje de marcado

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

Después del análisis, se convierte en lo siguiente:

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

Puedes comprobarlo por tu cuenta en esta demostración inspeccionando el lenguaje de marcado analizado con las Herramientas para desarrolladores de Chrome.

Ten en cuenta que esto solo se aplica a la anidación de <details> dentro de un <p>. El uso de display: inline en un <details> dentro de un <div> funciona bien.

El seudo ::details-content

En los navegadores, el elemento <details> se implementa con Shadow DOM. Contiene un <slot> para el resumen (con un elemento secundario de resumen predeterminado) y un <slot> para todo el contenido restante, es decir, todos los elementos secundarios del elemento <details>, excepto el elemento <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>

Además de usar más tipos de visualización en <details>, ahora se puede segmentar la ranura de contenido con el seudoelemento ::details-content. Puedes usar este seudoelemento para aplicar un diseño al contenedor que envuelve el contenido del elemento <details>.

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

Para aplicar el estilo establecido solo cuando el elemento <details> está en estado abierto, antepón el selector [open].

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

Se recomienda aplicar el diseño solo al seudoelemento ::details-content cuando el elemento <details> se encuentre en el estado [open].

Demostración

Grabación

Grabación de https://codepen.io/web-dot-dev/pen/oNKMEYv en Chrome 131

El tipo display de ::details-content se establece en block en la hoja de estilo de UA, mientras que antes era display: contents. En algunos casos, este cambio podría perjudicarte, por ejemplo, cuando el contenido divulgado depende de height: 100%. Si esto es un problema para ti, puedes solucionarlo configurando el tipo display como contents, de la siguiente manera: details[open]::details-content { display: contents; }.

Cómo animar el seudoelemento ::details-content

Puedes animar el contenido del elemento <details> a medida que se expande. En el siguiente ejemplo, el ancho se anima de 0px a 300px.

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

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

Además de la transición de width, también se debe realizar la transición de la propiedad content-visibility. Esto se debe a que su valor cambia entre el estado abierto y el cerrado, como se define en la hoja de estilo User-Agent. Como esa propiedad es discretamente animable, necesitas la palabra clave allow-discrete para que funcione.

Si se agrega a la demostración exclusiva del acordeón que se compartió antes, el resultado es el siguiente:

Demostración

Grabación

Grabación de https://codepen.io/web-dot-dev/pen/XWvBZNo en Chrome 131

El height también se puede animar. Para animar a height: auto, debes usar interpolate-size o calc-size(). Además, para evitar que el contenido se salga del seudoelemento ::details-content, aplícale 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 */
    }
}

Puedes ver el código en acción en la siguiente demostración, inspirada en el acordeón de Material UI. El contenido de cada elemento <details> se anima de forma agradable.

Demostración

Grabación

Grabación de https://codepen.io/web-dot-dev/pen/ExqpQZM en Chrome 131

En los navegadores que no admiten ::details-content, el componente sigue funcionando correctamente. Lo único que no ven los visitantes es la animación.

Detección de características

Para detectar la compatibilidad con el seudoelemento ::details-content en CSS, usa el siguiente fragmento.

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

También puedes usar esta detección como una verificación reveladora para determinar si el navegador que usa tu visitante admite los valores de visualización adicionales o no.

Consideraciones de accesibilidad

La introducción del seudoelemento ::details-content y la capacidad de cambiar el tipo de visualización no afectan la accesibilidad del elemento <details>.

Al igual que antes, al menos en los navegadores basados en Chromium y según el estándar HTML, el elemento <details> se puede buscar y se expande automáticamente cuando el navegador intenta desplazarse a su contenido oculto en respuesta a la función de búsqueda en la página, ScrollToTextFragment y la navegación por fragmentos de elementos. Esto no cambia.

Sin embargo, antes de usar acordeones exclusivos, considera si son útiles o perjudiciales para los usuarios. Si bien el uso de un acordeón exclusivo reduce la cantidad de espacio visual que ocupa el contenido, es posible que los usuarios deban abrir muchos elementos para consumir toda la información. Esto puede frustrar a los usuarios que desean ver varios elementos al mismo tiempo.

¿Qué sucede con el diseño del marcador?

Actualmente, el diseño del marcador de lista no es interoperable, ya que hay dos enfoques diferentes: uno adoptado por Gecko y Chromium (actual), y otro adoptado por WebKit (que antes se compartía con Chromium).

Una vez que la función sea interoperable, nuestro objetivo es brindarte un mejor control sobre cómo aplicar estilo al marcador.

Más demostraciones

Para terminar, aquí tienes algunas demostraciones más que puedes consultar. Todos usan ::details-content.

Acordeón de UIKit

Demostración

Grabación

Grabación de https://codepen.io/web-dot-dev/pen/rNXrJyQ en Chrome 131

Esta demostración se basa en el acordeón de UIKit. El código es prácticamente el mismo que el acordeón de Material UI que se compartió antes.

Widget de divulgación parcialmente abierto

Demostración

Grabación

Grabación de https://codepen.io/web-dot-dev/pen/PoMBQmW en Chrome 131

En esta demostración, se muestra un widget de divulgación parcialmente abierto cuyo contenido ya está visible en la pantalla. Para lograrlo, el content-visibility siempre se establece en visible. El height se anima con calc-size() porque hay un cálculo involucrado.

::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 */
}

Para facilitar el diseño, el contenido se incluye en un div de wrapper. El div de wrapper obtiene los diseños de diseño, como padding, aplicados y el seudo ::details-content se anima.