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

Fecha de publicación: 6 de noviembre de 2024

A partir de Chrome 131, tienes más opciones para aplicar diseño a 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 seudoelemento ::details-content para aplicar diseño a la parte que se expande y se contrae.

Navegadores compatibles

  • Chrome: 131.
  • Edge: 131.
  • 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 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, <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 lo siguiente 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 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 el espacio de contenido con el pseudoelemento ::details-content. Puedes usar este pseudoelemento 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 perjudicarte en algunos casos, como el contenido divulgado que depende de height: 100%. Si esto es un problema para ti, puedes solucionarlo restableciendo el tipo display a contents, de la siguiente manera: details[open]::details-content { display: contents; }.

Cómo animar el pseudoelemento ::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, 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 cerrado, como se define en la hoja de estilo del usuario-agente. Como esa propiedad es discretamente animatable, necesitas la palabra clave allow-discrete para que funcione.

Si se agrega a la demo 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 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 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 bien. 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 usar 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 que usan Gecko y Chromium (actual) y otro que usa WebKit (que se compartía con Chromium).

Una vez que la función sea interoperable, nuestro objetivo es brindarte un mejor control sobre cómo aplicar diseño al 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 compila 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 configura 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 un div de wrapper. El div de wrapper obtiene los estilos de diseño, como padding, y se anima el pseudo ::details-content.