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

Fecha de publicación: 6 de noviembre de 2024

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

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

Navegadores compatibles

  • Chrome: 131
  • Edge: No es compatible.
  • Firefox: No es compatible.
  • Safari: No se admite.

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 ahora se relajó, lo que te permite, por ejemplo, usar diseños de cuadrícula o flex 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 a <summary>.

Demostración

Grabación

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

Esto se logra con 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 display que puede tener un resultado inesperado es inline. No porque no funcione, sino por las limitaciones del analizador de HTML.

Cuando se coloca un elemento <details> dentro de un párrafo, se fuerza 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 de 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, <details> fluye en la dirección del bloque, independientemente de que hayas establecido display: inline.

Por ejemplo, el siguiente marcado

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

Se convierte en esto después del análisis:

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

Puedes comprobarlo por tu cuenta en esta demostración. Para ello, inspecciona el 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 pseudoelemento ::details-content

En los navegadores, el elemento <details> se implementa con Shadow DOM. Contiene un <slot> para el resumen (con un resumen secundario 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 el espacio de contenido con el pseudoelemento ::details-content. Puedes usar este pseudo para aplicar diseño al contenedor que une el contenido del elemento <details>.

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

Para aplicar solo el estilo establecido cuando el elemento <details> esté en el estado abierto, anteplágalo con el selector [open].

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

Se recomienda aplicar diseño solo al pseudo ::details-content cuando el elemento <details> esté 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. Este cambio podría afectarte en algunos casos, como el contenido divulgado que depende de height: 100%. Si esto es un problema para ti, puedes solucionarlo volviendo a establecer el tipo display en contents, de la siguiente manera: details[open]::details-content { display: contents; }.

Cómo animar el seudo ::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 realizar la transición de width, la propiedad content-visibility también debe hacerlo. Esto se debe a que su valor cambia entre el estado abierto y cerrado, como se define en la hoja de estilo del usuario-agente. Como esa propiedad es una propiedad que se puede animar de forma discreta, necesitas la palabra clave allow-discrete para que funcione.

Si se agregó a la demostración de acordeón exclusiva que se compartió anteriormente, el resultado será 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 pseudo ::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 la IU de Material. 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 navegadores que no admiten ::details-content, el componente sigue funcionando correctamente. Lo único que los visitantes no pueden ver es la animación.

Detección de atributos

Para detectar la compatibilidad con el pseudoelemento ::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 pseudoelemento ::details-content y la capacidad de cambiar el tipo de visualización no tienen un impacto en 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 hasta su contenido oculto en respuesta a la búsqueda en la página, ScrollToTextFragment y la navegación de fragmentos de elementos. Esto no cambia.

Sin embargo, antes de usar acordeones exclusivos, considera si son útiles o dañinos 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 estilo del marcador?

Actualmente, el diseño del marcador de lista no es interoperable, ya que hay dos enfoques diferentes: uno tomado por Gecko y Chromium (actual) y otro tomado por WebKit (que se compartió anteriormente con Chromium).

Una vez que la función sea interoperable, nuestro objetivo es ofrecerte un mejor control sobre cómo definir el estilo del marcador.

Más demostraciones

Para finalizar, 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 creó después del 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

Esta demostración incluye un widget de divulgación parcialmente abierto cuyo contenido ya es visible en la pantalla. Para lograrlo, 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 la aplicación de diseño, el contenido se une en una div de wrapper. La div de wrapper obtiene los diseños, como padding, y se anima el pseudo ::details-content.