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
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
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
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
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
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
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
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
.