Publicado em 6 de novembro de 2024
A partir do Chrome 131, você tem mais opções para estilizar a estrutura dos elementos <details>
e <summary>
. Agora é possível usar esses elementos ao criar widgets de abertura ou acordeão.
Em particular, as mudanças introduzidas no Chrome 131 permitem o uso da propriedade display
nesses elementos e adicionam um pseudoelemento ::details-content
para estilizar a parte que se expande e se contrai.
Compatibilidade com navegadores
Definir display
no elemento <details>
Historicamente, não era possível mudar o tipo de exibição do elemento <details>
. Essa restrição foi flexibilizada, permitindo, por exemplo, o uso de layouts de grade ou flexível no elemento <details>
.
No exemplo abaixo, o acordeão exclusivo consiste em vários elementos <details>
colocados lado a lado. Ao expandir um dos elementos <details>
, o conteúdo dele é colocado ao lado do <summary>
.
Demonstração
Gravando
Para isso, use um layout flexível no elemento <details>
com o seguinte CSS:
details {
display: flex;
flex-direction: row;
}
Outros valores de exibição também são permitidos, como grid
.
Observação sobre o uso de display: inline
Um valor display
que pode ter um resultado inesperado é inline
. Não porque não funciona, mas devido às limitações do analisador de HTML.
Ao colocar um elemento <details>
dentro de um parágrafo, o analisador de HTML é forçado a fechar primeiro o parágrafo aberto, conforme definido na seção 13.2.6.4.7 do padrão HTML:
Uma tag de início cujo nome é um destes: "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"
Se a pilha de elementos abertos tiver um elemento p no escopo do botão, feche um elemento p. Insira um elemento HTML para o token.
Como resultado, o <details>
flui na direção do bloco, independentemente de você ter definido display: inline
.
Por exemplo, o seguinte markup
<p>Hello <details>…</details> world</p>
Vai ficar assim após a análise:
<p>Hello </p><details>…</details> world<p></p>
Confira esta demonstração e inspecione a marcação analisada usando o Chrome DevTools.
Isso se aplica apenas ao aninhamento de <details>
dentro de um <p>
. O uso de display: inline
em um <details>
dentro de um <div>
funciona bem.
O pseudo ::details-content
Nos navegadores, o elemento <details>
é implementado usando o Shadow DOM. Ele contém um <slot>
para o resumo (com um filho de resumo padrão) e um <slot>
para todo o conteúdo restante, ou seja, todos os filhos do elemento <details>
, exceto o <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>
Além de usar mais tipos de exibição no <details>
, o slot de conteúdo agora pode ser segmentado usando o pseudoelemento ::details-content
. Você pode usar esse pseudo para estilizar o contêiner que envolve o conteúdo do elemento <details>
.
details::details-content {
border: 5px dashed hotpink;
}
Para aplicar o estilo definido apenas quando o elemento <details>
estiver no estado aberto, adicione o seletor [open]
no início.
[open]::details-content {
border: 5px dashed hotpink;
}
É recomendável aplicar o estilo apenas ao pseudoelemento ::details-content
quando o elemento <details>
estiver no estado [open]
.
Demonstração
Gravando
O tipo display
de ::details-content
é definido como block
na folha de estilos do UA. Antes, ele era display: contents
. Essa mudança pode ser prejudicial em alguns casos, como conteúdo divulgado que depende de height: 100%
. Se isso for um problema para você, será possível contorná-lo definindo o tipo de display
novamente como contents
, desta forma: details[open]::details-content { display: contents; }
.
Como animar o pseudo ::details-content
É possível animar o conteúdo do elemento <details>
à medida que ele se expande. No exemplo abaixo, a animação de largura vai 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;
}
Além da transição de width
, a propriedade content-visibility
também precisa ser transferida. Isso ocorre porque o valor muda entre o estado fechado e aberto, conforme definido na folha de estilo do User-Agent. Como essa propriedade é animada de forma discreta, você precisa da palavra-chave allow-discrete
para que ela funcione.
Adicionada à demonstração de acordeão exclusiva compartilhada anteriormente, o resultado fica assim:
Demonstração
Gravando
A height
também pode ser animada. Para animar para height: auto
, use interpolate-size
ou calc-size()
. Além disso, para evitar que o conteúdo saia do pseudo ::details-content
, aplique overflow: clip
a ele.
::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 */
}
}
Confira o código em ação na demonstração a seguir, inspirada no acordeão do Material UI. O conteúdo de cada elemento <details>
é animado de maneira agradável.
Demonstração
Gravando
Em navegadores sem suporte para ::details-content
, o componente ainda funciona bem. A única coisa que os visitantes não conseguem ver é a animação.
Detecção de recursos
Para detectar o suporte ao pseudoelemento ::details-content
no CSS, use o snippet a seguir.
@supports selector(::details-content) {
…
}
Você também pode usar essa detecção como uma verificação para descobrir se o navegador que o visitante está usando oferece suporte aos valores de exibição extras ou não.
Considerações sobre acessibilidade
A introdução do pseudoelemento ::details-content
e a capacidade de mudar o tipo de exibição não afetam a acessibilidade do elemento <details>
.
Como antes, pelo menos em navegadores baseados no Chromium e de acordo com o padrão HTML, o elemento <details>
é pesquisável e se expande automaticamente quando o navegador tenta rolar para o conteúdo oculto em resposta à navegação com função de localizar na página, ScrollToTextFragment e de fragmentos de elementos. Isso não muda.
No entanto, antes de usar acordeões exclusivos, avalie se eles são úteis ou prejudiciais para os usuários. Embora o uso de um acordeão exclusivo reduza a quantidade de espaço visual ocupado pelo conteúdo, os usuários podem ter que abrir muitos itens para consumir todas as informações. Isso pode frustrar os usuários que querem conferir vários itens ao mesmo tempo.
E se você quiser estilizar o marcador?
Atualmente, o estilo do marcador de lista não é interoperável, porque há duas abordagens diferentes: uma usada pelo Gecko e pelo Chromium (atual) e outra pelo WebKit (que era compartilhada com o Chromium).
Quando o recurso estiver interoperável, nosso objetivo é oferecer a você um controle melhor sobre como estilizar o marcador.
Mais demonstrações
Para encerrar, confira mais algumas demonstrações. Todos usam ::details-content
.
Acordeão UIKit
Demonstração
Gravando
Esta demonstração é criada após o acordeão do UIKit. O código é praticamente o mesmo do acordeão da IU do Material Design que foi compartilhado antes.
Widget de divulgação parcialmente aberto
Demonstração
Gravando
Esta demonstração apresenta um widget de aviso parcialmente aberto, cujo conteúdo já está visível na tela. Para fazer isso, o content-visibility
é sempre definido como visible
. O height
é animado usando calc-size()
porque há um cálculo envolvido.
::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 o estilo, o conteúdo é envolvido em uma div de wrapper. A div de wrapper recebe os estilos de layout, como padding
aplicado, e o pseudo ::details-content
é animado.