Por que <fieldset> não pode ser contêineres flexíveis?

201

Eu tentei estilizar um fieldsetelemento com display: flexe display: inline-flex.

No entanto, não funcionou: flexcomportou - se como block, e inline-flexcomportou-se como inline-block.

Isso acontece no Firefox e no Chrome, mas estranhamente funciona no IE.

Isso é um bug? Não achei que fieldsetdevesse ter nenhum comportamento especial, nem no HTML5 nem nas especificações do CSS Flexible Box Layout .

fieldset, div {
    display: flex;
    border: 1px solid;
}
<fieldset>
    <p>foo</p>
    <p>bar</p>
</fieldset>
<div>
    <p>foo</p>
    <p>bar</p>
</div>

Oriol
fonte
2
Sim, é um bug. Correção simples: use outro elemento. code.google.com/p/chromium/issues/detail?id=262679
Adam

Respostas:

145

De acordo com o Bug 984869 - display: flexnão funciona para elementos de botão ,

<button>não é implementável (por navegadores) em CSS puro; portanto, eles são um pouco de caixa preta, da perspectiva do CSS. Isso significa que eles não necessariamente reagem da mesma maneira que, por exemplo, um <div>faria.

Isso não é específico do flexbox - por exemplo, não renderizamos barras de rolagem se você overflow:scrollapertar um botão, e não renderizamos como uma tabela se você apertar um botão display:table.

Recuando ainda mais, isso não é específico <button>. Considerar <fieldset> e <table> que também possuem comportamento especial de renderização:

data:text/html,<fieldset style="display:flex"><div>abc</div><div>def</div>

Nesses casos, o Chrome concorda conosco e desconsidera o flex modo de exibição. (como revelado pelo fato de que "abc" e "def" acabam sendo empilhados verticalmente). O fato de eles fazerem o que você espera <button style="display:flex">provavelmente deve-se apenas a um detalhe da implementação.

Na implementação dos botões do Gecko, codificamos <button>(e <fieldset>,e <table>) como tendo uma classe de quadro específica (e, portanto, uma maneira específica de dispor os elementos filhos), independentemente da displaypropriedade.

Se você deseja que os filhos sejam organizados de maneira confiável em um modo de layout específico, em modo de navegador cruzado, sua melhor aposta é usar uma div de wrapper dentro do botão, exatamente como você precisaria dentro de um <table>oua <fieldset>.

Portanto, esse bug foi marcado como "resolvido inválido".

Há também o Bug 1047590 - display: flex;não funciona<fieldset> , atualmente "não confirmado".


Boas notícias : o Firefox 46+ implementa o Flexbox for <fieldset>. Veja o erro 1230207 .

Oriol
fonte
Considerando que o flexbox está no limbo há 8 anos, acho "extraordinariamente" um exagero. Estou surpreso que eles tenham funcionado no Firefox tão rapidamente. Talvez você queira ajudar a acelerar as coisas no Google (heh, entendeu ?).
BoltClock
3
<button> is not implementable (by browsers) in pure CSS- isso está errado. Um navegador é livre para implementar o modo <button>que quiser, não é "contratualmente obrigado" a renderizá-lo usando bibliotecas de widgets do sistema ou qualquer outra coisa, o que prejudica a capacidade de estilizá-las com CSS ou outros comportamentos personalizados. O mesmo vale para qualquer outro elemento, realmente.
amn
4
@BoltClock Não sei o que você quer dizer com limbo. Todos os principais navegadores suportam a terceira e última revisão da sintaxe desde 2015; interoperabilidade é muito boa, eu acho. Temos até amplo suporte para o Grid agora! 🎉
Šime Vidas
@ Šime Vidas: Entendo, parece que faz CR há um ano. Justo. Eu pensei que nunca iria conseguir.
BoltClock
9
2017 de fato. Onde aponto minha raiva? Anos de espera para implementar com segurança o flexbox, inúmeros artigos, tutes, tentativas / erros, recebo 98% lá e ... conjuntos de campos. É como contratar um eletricista para ligar minha casa, apenas para descobrir que uma tomada não está aterrada. "Não exagere" Eu ouço as pessoas pensarem, exagero, não. Eu literalmente tenho que responder por isso amanhã. O Flex foi a resposta para vários erros de tabela herdados que eu precisava resolver. Agora, o Flex é a causa de um punhado menor de bugs não herdados. Onde aponto minha raiva?
danjah
20

Eu descobrir isso pode ser um bug no Chrome e Firefox, onde legende fieldsetsão elementos substituído .

Erros relatados:

Bug Chrome (ainda aberto)
Bug Firefox (corrigido desde a v46)

Uma possível solução alternativa:

Uma possível solução alternativa seria usar <div role="group">em HTML e aplicar em CSS div[role='group']como seletor.


ATUALIZAR

No Chrome, a versão 83 button pode funcionar com o display: inline-grid/grid/inline-flex/flex, você pode ver a demonstração abaixo:

button {
  display: inline-flex;
  height: 2rem;
  align-items: flex-end;
  width: 4rem;
  -webkit-appearance: none;
  justify-content: flex-end;
}
<!-- 

The align-items keyword should fail in Chrome 81 or earlier, but work in Chrome 83 or later. To see the error, the button needs styles that make it more of an extrinsic container. In other words, it needs a height or width set. 
 
-->
<button>Hi</button>
<input type="button" value="Hi">

dippas
fonte
11

Marque o bug do Chrome com estrela para aumentar a prioridade do bug

Este é um erro no Chrome. Adicione uma estrela a esse problema para aumentar sua prioridade a ser corrigida: https://bugs.chromium.org/p/chromium/issues/detail?id=375693

Nesse meio tempo, criei esses três exemplos de Code Pen para mostrar como solucionar o problema. Eles são criados usando CSS Grid para os exemplos, mas as mesmas técnicas podem ser usadas para o flexbox.

Usando ária-labelledby em vez de legenda

Essa é a maneira mais adequada de lidar com o problema. A desvantagem é que você precisa lidar com a geração de IDs exclusivos aplicados a todos os elementos de legenda falsos.

https://codepen.io/daniel-tonon/pen/vaaGzZ

<style>
.flex-container {
    display: flex;
}
</style>

<fieldset aria-labelledby="fake-legend">
    <div class="flex-container">
        <div class="flex-child" id="fake-legend">
            I am as good accessibilty wise as a real legend
        </div>

        ...

    </div>
</fieldset>

Usando role = "group" e ária-labelledby em vez de fieldset e legend

Se você precisar que o contêiner flexível possa se esticar até a altura de um elemento irmão e também passá-lo para seus filhos, será necessário usar em role="group"vez de<fieldset>

https://codepen.io/daniel-tonon/pen/BayRjGz

<style>
.flex-container {
    display: flex;
}
</style>

<div role="group" class="flex-container" aria-labelledby="fake-legend">
    <div class="flex-child" id="fake-legend">
        I am as good accessibilty wise as a real legend
    </div>

    ...

</div>

Criando uma legenda duplicada falsa para fins de estilo

Esta é uma maneira muito mais hacky de fazer isso. Ainda é tão acessível, mas você não precisa lidar com IDs ao fazê-lo dessa maneira. A principal desvantagem é que haverá conteúdo duplicado entre o elemento de legenda real e o elemento de legenda falsa.

https://codepen.io/daniel-tonon/pen/zLLqjY

<style>
.screen-reader-only {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.flex-container {
    display: flex;
}
</style>

<fieldset>
    <legend class="screen-reader-only">
        I am a real screen-reader accessible legend element
    </legend>

    <div class="flex-container">
        <div class="flex-child" aria-hidden="true">
            I am a fake legend purely for styling purposes
        </div>

        ...

    </div>
</fieldset>

A legenda DEVE ser um decendente direto

Quando você estiver tentando consertar isso sozinho, provavelmente tentará fazer o seguinte:

<!-- DO NOT DO THIS! -->
<fieldset>
    <div class="flex-container">
        <legend class="flex-child">
            Broken semantics legend text
        </legend>

        ...

    </div>
</fieldset>

Você descobrirá que funciona e provavelmente seguirá em frente sem pensar duas vezes.

O problema é que colocar um invólucro div entre o conjunto de campos e a legenda interrompe o relacionamento entre os dois elementos. Isso quebra a semântica do fieldset / legenda.

Então, ao fazer isso, você derrotou todo o propósito de usar fieldset / legend em primeiro lugar.

Além disso, não faz muito sentido usar um conjunto de campos se você não der uma legenda a esse conjunto de campos.

Daniel Tonon
fonte
9

Na minha experiência, descobri que nem <fieldset>, nem <button>, nem <textarea>podem usar display:flexou herdar adequadamente as propriedades.

Como outros já mencionaram, foram relatados bugs. Se você quiser usar o flexbox para controlar pedidos (por exemplo order:2), precisará envolver o elemento em uma div. Se você deseja que o flexbox controle o layout e as dimensões reais, considere usar uma div, em vez do controle de entrada (o que cheira mal, eu sei).

paceaux
fonte
3
<div role="group">
    <p>foo</p>
    <p>bar</p>
</div>
<div>
    <p>foo</p>
    <p>bar</p>
</div>

Talvez precise usar o grupo de funções, porque o Firefox, o Chrome e eu acho que o safari tem um bug com os conjuntos de campos, aparentemente. Então o seletor no CSS seria simplesmente

div[role='group'], div {
    display: flex;
    border: 1px solid;
}

Edit: Aqui estão alguns problemas que outras pessoas estão enfrentando também.

Edição 375693

Edição 262679

SharpCode
fonte
Este ainda é um problema no Chrome 60.
evolutionxbox
Ainda aqui no Chrome 66.
Brad
Check-
Chrome 73 verificando
Michael Draper
Check-
3

você pode colocar div adicional <fieldset>com os seguintes adereços:

flex-inner-wrapper {
  display: inherit;
  flex-flow: inherit;
  justify-content: inherit;
  align-items: inherit;
}
Jemy
fonte
1
Eu não entendo os votos negativos. Isso está realmente correto. Mas lembre-se de manter o <legend>elemento (se usado) no nível superior do <fieldset>elemento para manter seu uso como pretendido ( Permitted content: An optional <legend> element, followed by flow content.- consulte developer.mozilla.org/en-US/docs/Web/HTML/Element/… )
Froxx
2
Não fui eu, mas devo imaginar que o voto negativo tem algo a ver com não responder à pergunta. Não se tratava de encontrar uma solução alternativa, mas o comportamento de fieldsetsi mesmo.
Manngo 27/05/19
Sim, pode não responder diretamente à pergunta (que era um pouco filosófica), mas essa é uma possível correção para esse bug ridículo.
Eric S. Bullington 7/10/19
O voto inativo porque encoraja a quebra da semântica do <legend>elemento. Isso anula o propósito de usar fieldset / legenda em primeiro lugar. Veja minha resposta aqui: stackoverflow.com/a/59425373/1611058
Daniel Tonon
3

Para responder à pergunta original: sim, é um bug, mas não estava bem definido no momento em que a pergunta foi feita.

Agora, a renderização para o fieldset está melhor definida: https://html.spec.whatwg.org/multipage/rendering.html#the-fieldset-and-legend-elements

No Firefox e no Safari, flexboxno fieldsetagora funciona. Ainda não está no Chromium. (Consulte https://bugs.chromium.org/p/chromium/issues/detail?id=375693 )

Consulte também https://blog.whatwg.org/the-state-of-fieldset-interoperability para obter as melhorias feitas na especificação em 2018.

zcorpan
fonte