¿Por qué <fieldset> no puede ser contenedores flexibles?

201

Traté de diseñar un fieldsetelemento con display: flexydisplay: inline-flex .

Sin embargo, no funcionó: se flexcomportó como blocky se inline-flexcomportó como inline-block.

Esto sucede tanto en Firefox como en Chrome, pero extrañamente funciona en IE.

¿Es un error? No pude encontrar que fieldsetdebería tener un comportamiento especial, ni en HTML5 ni en las especificaciones de diseño de caja flexible de CSS .

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

Oriol
fuente
2
Sí, es un error. Solución simple: use otro elemento. code.google.com/p/chromium/issues/detail?id=262679
Adam
Problema
Oriol

Respuestas:

145

De acuerdo con el error 984869: display: flexno funciona para elementos de botón ,

<button>no es implementable (por los navegadores) en CSS puro, por lo que son un poco como una caja negra, desde la perspectiva de CSS. Esto significa que no necesariamente reaccionan de la misma manera que, por ejemplo, un lo <div>haría.

Esto no es específico de flexbox, por ejemplo, no representamos barras de desplazamiento si pones overflow:scrollun botón, y no lo hacemos como una tabla si lo pones display:table.

Retrocediendo aún más, esto no es específico para <button>. Considerar <fieldset> y <table> que también tienen un comportamiento de representación especial:

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

En estos casos, Chrome está de acuerdo con nosotros y no tiene en cuenta el flex modo de visualización. (como lo revela el hecho de que "abc" y "def" terminan apilados verticalmente). El hecho de que hacen lo que esperas<button style="display:flex"> probablemente se deba a un detalle de implementación.

En la implementación del botón de Gecko, codificamos <button>(y <fieldset> ,y <table>) como una clase de marco específica (y, por lo tanto, una forma específica de diseñar los elementos secundarios), independientemente de la displaypropiedad.

Si desea que los niños se organicen de manera confiable en un modo de diseño particular en una forma de navegador cruzado, su mejor opción es usar un wrapper-div dentro del botón, tal como lo necesitaría dentro de una <table> oa <fieldset>.

Por lo tanto, ese error se marcó como "resuelto no válido".

También hay un error 1047590: display: flex;no funciona<fieldset> , actualmente "sin confirmar".


Buenas noticias : Firefox 46+ implementa Flexbox para <fieldset>. Ver error 1230207 .

Oriol
fuente
Teniendo en cuenta que flexbox ha estado en el limbo durante 8 años, me parece "notablemente" un poco exagerado. En todo caso, me sorprende que lo hayan hecho funcionar en Firefox tan rápido. Tal vez te gustaría ayudar a poner las cosas en marcha en Google (heh, ¿ entiendes ?).
BoltClock
3
<button> is not implementable (by browsers) in pure CSS-- eso está mal. Un navegador es libre de implementar lo <button>que quiera, no está "obligado contractualmente" a representarlo utilizando bibliotecas de widgets del sistema o lo que sea, lo que afecta la capacidad de diseñarlos con CSS u otros comportamientos personalizados. Lo mismo ocurre con cualquier otro elemento, en realidad.
amn
44
@BoltClock No estoy seguro de lo que quieres decir con limbo. Todos los principales navegadores admiten la tercera y última revisión de la sintaxis desde 2015; La interoperabilidad es bastante buena, creo. ¡Incluso obtuvimos un amplio soporte para Grid ahora! 🎉
Šime Vidas
@ Šime Vidas: Ya veo, parece que ha sido CR por un año. Lo suficientemente justo. Pensé que nunca lo lograría.
BoltClock
9
2017 de hecho. ¿Dónde apunto mi ira? Años de espera para implementar de manera segura flexbox, innumerables artículos, tutes, prueba / errores, obtengo el 98% allí y ... conjuntos de campo. Es como hacer que un electricista cablee mi casa, solo para descubrir que un enchufe no está conectado a tierra. "No exageres" escucho a la gente pensar, exagero no. Literalmente tengo que responder por esto mañana. Flex fue la respuesta a varios errores de tabla heredados que necesitaba resolver. Flex es ahora la causa de un pequeño puñado de errores no heredados. ¿Dónde apunto mi ira?
danjah
20

Descubrí que esto podría ser un error en Chrome y Firefox donde legendy fieldsetson elementos reemplazados .

Errores reportados:

Bug Chrome (todavía abierto)
Bug Firefox (corregido desde v46)

Una posible solución alternativa:

Una posible solución sería usar <div role="group">HTML y aplicar CSS div[role='group']como selector.


ACTUALIZAR

En Chrome versión 83 button puede funcionar con display: inline-grid/grid/inline-flex/flex, puedes ver la demostración a continuación:

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
fuente
11

Destaque el error de Chrome para aumentar la prioridad del error

Este es un error en Chrome. Agregue una estrella a este problema para aumentar su prioridad a solucionar: https://bugs.chromium.org/p/chromium/issues/detail?id=375693

Mientras tanto, creé estos tres ejemplos de Code Pen para mostrar cómo solucionar el problema. Se crean utilizando CSS Grid para los ejemplos, pero se pueden usar las mismas técnicas para flexbox.

Usando aria-labelledby en lugar de leyenda

Esta es la forma más adecuada de lidiar con el problema. La desventaja es que tiene que lidiar con la generación de ID únicos aplicados a cada elemento de leyenda falso.

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" y aria-labelledby en lugar de fieldset y legend

Si necesita el contenedor flexible para poder estirarse a la altura de un elemento hermano y luego también pasar ese estiramiento a sus elementos secundarios, deberá usarlo en role="group"lugar 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>

Crear una leyenda duplicada falsa para propósitos de estilo

Esta es una forma mucho más hacky de hacerlo. Todavía es igual de accesible, pero no tiene que lidiar con ID cuando lo hace de esta manera. El principal inconveniente es que habrá contenido duplicado entre el elemento de leyenda real y el elemento de leyenda falso.

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>

La leyenda DEBE ser un descendiente directo

Cuando intente solucionarlo usted mismo por primera vez, probablemente intente hacerlo:

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

        ...

    </div>
</fieldset>

Descubrirá que funciona, y luego probablemente continuará sin pensarlo dos veces.

El problema es que poner un contenedor div entre el conjunto de campos y la leyenda rompe la relación entre los dos elementos. Esto rompe la semántica del conjunto de campos / leyenda.

Entonces, al hacer esto, has derrotado el propósito de usar el conjunto de campos / leyenda en primer lugar.

Además, no tiene mucho sentido usar un conjunto de campos si no le da una leyenda a ese conjunto de campos.

Daniel Tonon
fuente
9

En mi experiencia, he descubierto que ni <fieldset>, ni <button>, ni <textarea>pueden usar adecuadamentedisplay:flex o heredar propiedades.

Como otros ya han mencionado, se han reportado errores. Si desea utilizar flexbox para controlar el orden (p order:2. Ej. ), Deberá envolver el elemento en un div. Si desea que flexbox controle el diseño y las dimensiones reales, entonces puede considerar usar un div, en lugar del control de entrada (que apesta, lo sé).

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

Es posible que necesite usar role-group porque firefox, chrome y creo que Safari tienen un error con los conjuntos de campos aparentemente. Entonces el selector en el CSS simplemente sería

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

Editar: Aquí hay algunos problemas que otras personas también están experimentando.

Edición 375693

Edición 262679

SharpCode
fuente
Esto sigue siendo un problema en Chrome 60.
evolutionxbox
Todavía aquí en Chrome 66.
Brad
Chrome 72 registrando.
danemacmillan
Registro de Chrome 73
Michael Draper,
Registro de
3

puedes poner div adicional <fieldset>con los siguientes accesorios:

flex-inner-wrapper {
  display: inherit;
  flex-flow: inherit;
  justify-content: inherit;
  align-items: inherit;
}
Jemy
fuente
1
No entiendo los votos negativos. Esto es realmente correcto. Pero recuerde mantener el <legend>elemento (si se usa) en el nivel superior del <fieldset>elemento para mantener su uso según lo previsto ( Permitted content: An optional <legend> element, followed by flow content.- vea developer.mozilla.org/en-US/docs/Web/HTML/Element/… )
Froxx
2
No fui yo, pero me imagino que el voto negativo tiene algo que ver con no responder la pregunta. No se trataba de encontrar una solución, sino del comportamiento de fieldsetsí mismo.
Manngo
Sí, es posible que no responda directamente la pregunta (que era un poco filosófica), pero esta es una posible solución para este ridículo error.
Eric S. Bullington
Abajo votó porque alienta a romper la semántica del <legend>elemento. Esto anula el propósito de usar el conjunto de campos / leyenda en primer lugar. Vea mi respuesta aquí: stackoverflow.com/a/59425373/1611058
Daniel Tonon
3

Para responder a la pregunta original: sí, es un error, pero no estaba bien definido en el momento en que se hizo la pregunta.

Ahora la representación para el conjunto de campos está mejor definida: https://html.spec.whatwg.org/multipage/rendering.html#the-fieldset-and-legend-elements

En Firefox y Safari, flexboxde fieldsetahora trabaja. Todavía no en cromo. (Ver https://bugs.chromium.org/p/chromium/issues/detail?id=375693 )

Consulte también https://blog.whatwg.org/the-state-of-fieldset-interoperability para conocer las mejoras realizadas en la especificación en 2018.

zcorpan
fuente