<fieldset> cambia el tamaño incorrecto; parece tener un `min-width: min-content` inamovible

221

Problema

Tengo un <select>donde uno de sus <option>valores de texto es muy largo. Quiero <select>que cambie el tamaño para que nunca sea más ancho que su padre, incluso si tiene que cortar el texto que se muestra.max-width: 100%Debería hacer eso.

Antes de cambiar el tamaño:

la página antes de cambiar el tamaño, mostrando toda la <code> select </code>

Lo que quiero después de cambiar el tamaño:

mi página deseada después de cambiar el tamaño, con el <code> select </code> recortando su contenido

Pero si carga este ejemplo de jsFiddle y cambia el tamaño del ancho del panel Resultado para que sea más pequeño que el del <select>, puede ver que la selección dentro del<fieldset> no logra reducir su ancho.

Lo que realmente estoy viendo después de cambiar el tamaño:

mi página actual después de cambiar el tamaño, con una barra de desplazamiento

Sin embargo, la página equivalente con una en <div>lugar de una<fieldset> escala correctamente. Puede ver eso y probar sus cambios más fácilmente si tiene un <fieldset>y uno al <div>lado del otro en una página . Y si elimina las <fieldset>etiquetas circundantes , el cambio de tamaño funciona. los<fieldset> etiqueta está causando que se rompa el cambio de tamaño horizontal.

Los <fieldset>actos son como si hubiera una regla CSS fieldset { min-width: min-content; }. ( min-contentsignifica, aproximadamente, el ancho más pequeño que no hace que un niño se desborde). Si reemplazo el <fieldset>con un <div>conmin-width: min-content , se ve exactamente igual. Sin embargo, no hay ninguna regla min-contenten mis estilos, en la hoja de estilos predeterminada del navegador o visible en el Inspector CSS de Firebug. Traté de anular todos los estilos visibles en el <fieldset>Inspector CSS de Firebug y en la hoja de estilo predeterminada de Firefox forms.css , pero eso no ayudó. Específicamente anulando min-widthywidth tampoco hizo nada.

Código

HTML del conjunto de campos:

<fieldset>
    <div class="wrapper">
        <select id="section" name="section">
            <option value="-1"></option>
            <option value="1501" selected="selected">Sphinx of black quartz, judge my vow. The quick brown fox jumps over the lazy dog.</option>
            <option value="1480">Subcontractor</option>
            <option value="3181">Valley</option>
            <option value="3180">Ventura</option>
            <option value="3220">Very Newest Section</option>
            <option value="1481">Visitor</option>
            <option value="3200">N/A</option>
        </select>
    </div>
</fieldset>

Mi CSS que debería funcionar pero no lo es:

fieldset {
    /* hide fieldset-specific visual features: */
    margin: 0;
    padding: 0;
    border: none;
}

select {
    max-width: 100%;
}

Restablecer las widthpropiedades a los valores predeterminados no hace nada:

fieldset {
    width: auto;
    min-width: 0;
    max-width: none;
}

Más CSS en el que intento y no soluciono el problema :

/* try lots of things to fix the width, with no success: */
fieldset {
    display: block;
    min-width: 0;
    max-width: 100%;
    width: 100%;
    text-overflow: clip;
}

div.wrapper {
    width: 100%;
}

select {
    overflow: hidden;
}

Más detalles

El problema también ocurre en este ejemplo de jsFiddle más completo y más complicado , que es más similar a la página web que estoy tratando de arreglar. Puede ver a partir de eso que <select>no es el problema: un bloque en línea divtampoco puede cambiar el tamaño. Aunque este ejemplo es más complicado, supongo que la solución para el caso simple anterior también solucionará este caso más complicado.

[Editar: consulte los detalles de soporte del navegador a continuación.]

Una cosa curiosa sobre este problema es que si configuradiv.wrapper { width: 50%; } , las <fieldset>paradas se redimensionan en el punto, entonces el tamaño completo <select>habría llegado al borde de la ventana gráfica. El cambio de tamaño ocurre como si lo <select>hubiera hecho width: 100%, aunque <select>parezca que sí width: 50%.

después de cambiar el tamaño con 50% de ancho envoltorio div

Si das el <select>sí mismowidth: 50% , ese comportamiento no ocurre; el ancho simplemente está configurado correctamente.

después de cambiar el tamaño con 50% de ancho seleccionado

No entiendo la razón de esa diferencia. Pero puede no ser relevante.

También encontré la pregunta muy similar El conjunto de campos HTML permite a los niños expandirse indefinidamente . El autor de la pregunta no pudo encontrar una solución y adivina que no hay solución aparte de eliminar la <fieldset>. Pero me pregunto, si realmente es imposible hacer la <fieldset>pantalla correctamente, ¿por qué es eso? ¿Qué en <fieldset>la especificación o CSS predeterminado (a partir de esta pregunta ) causa este comportamiento? Este comportamiento especial probablemente esté documentado en alguna parte, ya que varios navegadores funcionan así.

Objetivo de fondo y requisitos

La razón por la que intento hacer esto es como parte de la escritura de estilos móviles para una página existente con una gran forma. El formulario tiene varias secciones, y una parte está envuelta en una <fieldset>. En un teléfono inteligente (o si hace que la ventana de su navegador sea pequeña), la parte de la página con este <fieldset>es mucho más ancha que el resto del formulario. La mayor parte del formulario restringe su ancho muy bien, pero la sección con <fieldset>no lo hace, lo que obliga al usuario a alejarse o desplazarse hacia la derecha para ver toda esa sección.

Tengo cuidado de simplemente eliminarlo <fieldset>, ya que se genera en muchas páginas en una aplicación grande, y no estoy seguro de qué selectores en CSS o JavaScript podrían depender de él.

Puedo usar JavaScript si lo necesito, y una solución de JavaScript es mejor que nada. Pero si JavaScript es la única forma de hacer esto, me gustaría escuchar una explicación de por qué esto no es posible usando solo CSS y HTML.


Editar: soporte del navegador

En el sitio, necesito admitir Internet Explorer 8 y versiones posteriores (acabamos de dejar de admitir IE7), el último Firefox y el último Chrome. Esta página en particular también debería funcionar en teléfonos inteligentes iOS y Android. Un comportamiento ligeramente degradado pero aún utilizable es aceptable para Internet Explorer 8.

Volví a probar mi fieldsetejemplo roto en diferentes navegadores. En realidad, ya funciona en estos navegadores:

  • Internet Explorer 8, 9 y 10
  • Cromo
  • Chrome para Android

Se rompe en estos navegadores:

  • Firefox
  • Firefox para Android
  • Internet Explorer 7

Por lo tanto, el único navegador que me importa en el que se rompe el código actual es Firefox (tanto en computadoras de escritorio como en dispositivos móviles). Si el código se corrigiera para que funcionara en Firefox sin romperlo en ningún otro navegador, eso resolvería mi problema.

La plantilla HTML del sitio utiliza comentarios condicionales de Internet Explorer para agregar clases como .ie8y .oldieal <html>elemento. Puede usar esas clases en su CSS si necesita solucionar las diferencias de estilo en IE. Las clases agregadas son las mismas que en esta versión anterior de HTML5 Boilerplate .

Rory O'Kane
fuente
41
felicidades a esta excelente crítica
Alp
Su ejemplo simple: dar <fieldset>(o div.wrapper) cualquier ancho que necesite, y select { width:100% }. max-widthparece dar al elemento un porcentaje del ancho original de su padre , luego no se escala, mientras widthque se escala con su padre. Creo que hará lo que quieras (pero podría haber entendido mal). En su violín más complejo, intente asignar a los campos de la columna izquierda un% de ancho y un mínimo de píxeles de ancho. Luego dé los campos a la derecha 100 - (campos de la izquierda -% - ancho)% ancho.
Troyano
Solo tuve otro pensamiento: ¿qué pasa si configura el ancho mínimo del conjunto de campos en 0? Eso por sí solo probablemente no resolverá el problema, pero posiblemente valga la pena intentar resolverlo. Estoy trabajando por un camino diferente ahora, pero si no funciona, lo intentaré también
Trojan
¿Necesita la etiqueta y el campo para permanecer en la misma línea? Para ventanas pequeñas, se superponen. ¿Por qué no hacerlo algo receptivo y, si es necesario, pasar a una nueva línea?
Troyano

Respuestas:

346

Actualización (25 de septiembre de 2017)

El error de Firefox que se describe a continuación se corrigió a partir de Firefox 53 y el enlace a esta respuesta finalmente se eliminó de la documentación de Bootstrap .

Además, mis sinceras disculpas a los contribuyentes de Mozilla que tuvieron que bloquear la eliminación del soporte en -moz-documentparte debido a esta respuesta.

La solución

En WebKit y Firefox 53+, simplemente configura min-width: 0;en el conjunto de campos para anular el valor predeterminado de min-content

Aún así, Firefox es un poco ... extraño cuando se trata de conjuntos de campos. Para que esto funcione en versiones anteriores, debe cambiar la displaypropiedad del conjunto de campos a uno de los siguientes valores:

  • table-cell (recomendado)
  • table-column
  • table-column-group
  • table-footer-group
  • table-header-group
  • table-row
  • table-row-group

De estos, lo recomiendotable-cell . Tanto table-rowy table-row-groupque impiden el cambio de ancho, mientras que table-columny table-column-groupque impiden el cambio de altura.

Esto (algo razonablemente) romperá la representación en IE. Como solo Gecko necesita esto, puede usar justificadamente @-moz-document—una de las extensiones CSS propietarias de Mozilla— para ocultarlo de otros navegadores:

@-moz-document url-prefix() {
    fieldset {
        display: table-cell;
    }
}

(Aquí hay una demostración de jsFiddle ).


Eso arregla las cosas, pero si eres como yo, tu reacción fue algo así como ...

Qué.

No es una razón, pero no es bastante.

La presentación predeterminada del elemento del conjunto de campos es absurda y esencialmente imposible de especificar en CSS. Piénselo: el borde del conjunto de campos desaparece donde se superpone un elemento de leyenda, ¡pero el fondo permanece visible! No hay forma de reproducir esto con ninguna otra combinación de elementos.

Para colmo, las implementaciones están llenas de concesiones al comportamiento heredado. Una de ellas es que el ancho mínimo de un conjunto de campos nunca es menor que el ancho intrínseco de su contenido. WebKit le ofrece una forma de anular este comportamiento al especificarlo en la hoja de estilo predeterminada, pero Gecko² va un paso más allá y lo aplica en el motor de renderizado .

Sin embargo, los elementos internos de la tabla constituyen un tipo de marco especial en Gecko. Las restricciones dimensionales para elementos con estos displayvalores establecidos se calculan en una ruta de código separada , eludiendo por completo el ancho mínimo impuesto impuesto en los conjuntos de campos.

Nuevamente, el error para esto se ha solucionado a partir de Firefox 53, por lo que no necesita este truco si solo se dirige a versiones más nuevas.

¿Está usando @-moz-documentseguro?

Para este problema, sí. @-moz-documentfunciona según lo previsto en todas las versiones de Firefox hasta 53, donde se soluciona este error.

Esto no es un accidente. Debido en parte a esta respuesta, el error para limitar @-moz-documenta las hojas de estilo de usuario / UA se hizo dependiente del error del conjunto de campos subyacente que se solucionó primero.

Más allá de esto, no lo use @-moz-documentpara apuntar a Firefox en su CSS , a pesar de otros recursos.³


¹ El valor puede estar prefijado. Según un lector, esto no tiene efecto en Android 4.1.2 Stock Browser y posiblemente en otras versiones antiguas; No he tenido tiempo de verificar esto.

² Todos los enlaces a la fuente Gecko en esta respuesta se refieren al conjunto de cambios 5065fdc12408 , comprometido el 29 de julio de 2013; Es posible que desee comparar notas con la revisión más reciente de Mozilla Central .

³ Ver, por ejemplo, SO # 953491: Dirigido solo a Firefox con CSS y CSS Trucos: CSS hacks dirigidos a Firefox para artículos ampliamente referenciados en sitios de alto perfil.

Jordan Gray
fuente
55
Me acabo de dar cuenta de que la solución se rompió en IE, solo para venir aquí y descubrir que ya has editado la solución. ¡Gracias! La solución de hackeo Gecko funciona bien para mí en cada navegador.
Rory O'Kane
Me estaba sacando el pelo por este problema, pero su solución es perfecta, excepto que solo parece funcionar en Firefox. ¿Alguna sugerencia para otros navegadores, especialmente navegadores móviles? Mi mayor problema es cambiar el tamaño debido al cambio de orientación en los dispositivos móviles ...
Adriaan Nel
30
Esta es una respuesta absolutamente excelente: exhaustiva, investigada y concisa. Gracias.
iamkeir
16
¡Por supuesto que es una respuesta absolutamente excelente! La documentación oficial de Bootstrap apunta aquí
Ranhiru Jude Cooray
1
Bueno, nunca supe eso sobre los conjuntos de campo. He aprendido algo aquí hoy.
superluminary
11

Problema de Safari en iOS con respuesta seleccionada

La respuesta de Jordan Gray me pareció particularmente útil. Sin embargo, no pareció resolver este problema en Safari iOS para mí.

El problema para mí es simplemente que el conjunto de campos no puede tener un ancho automático si el elemento dentro tiene un ancho máximo como% ancho.

Arreglo para el problema

Simplemente configurar el conjunto de campos para que tenga un ancho del 100% de su contenedor parece solucionar este problema.

Ejemplo

fieldset {
    min-width: 0; 
    width: 100%; 
}

Consulte los siguientes ejemplos de trabajo: si elimina el% de ancho del conjunto de campos o lo reemplaza por automático, no continuará funcionando.

JSFiddle | Codepen

jabalíes
fuente
1
Esta es una gran adición al problema general, no pensé probarlo en iOS. :) Casi creo que esto podría valer la pena preguntarte y responderte como una nueva pregunta, también. Intentaré hacer algunas pruebas adicionales esta semana y vincular a esta respuesta si funciona.
Jordan Gray
3

He luchado durante muchas horas con esto, y básicamente, el navegador está aplicando un estilo computarizado que debes anular en tu CSS. Olvidé la propiedad exacta que se establece en fieldsetelementos versus divs ( min-width¿ tal vez ?).

Mi mejor consejo sería cambiar su elemento a a div, copiar los estilos calculados de su inspector, luego volver a cambiar su elemento fieldsety comparar los estilos calculados para encontrar al culpable.

Espero que ayude.

Actualización: Agregar display: table-cellayuda en navegadores que no son de Chrome.

phdj
fuente
Comparé todas las propiedades CSS de fieldsety diven esta página en Firebug. No sirvió de nada. En Firebug, las únicas propiedades con diferentes valores eran widthy perspective-origin. El widthera numéricamente diferente, pero el fieldset's widthera auto, como el div' s. Y esto perspective-origines solo una función del width50% de forma predeterminada.
Rory O'Kane
Sin embargo, la comparación ayudó de alguna manera en Chrome Web Inspector. ¡Descubrí justo después de abrir mi ejemplo que está funcionando en Chrome! Agregué el min-width: 0;a mi ejemplo después de probar en Chrome, pero parece que eso resolvió el problema en Chrome. El inspector web me dice que Chrome tiene el estilo min-width: -webkit-min-content;, tal como lo planteé. Así que ahora solo necesito resolver el problema en Firefox y posiblemente en otros navegadores que aún no he probado.
Rory O'Kane
Me alegro de que haya ayudado un poco. Pude resolver mi problema en otros navegadores con "display: table-cell". No creo que no sea la mejor solución, pero espero que funcione para usted.
phdj
2

.fake-select { white-space:nowrap; }hizo que el conjunto de campos interpretara el .fake-selectelemento por su ancho original, en lugar de su ancho forzado (incluso cuando el desbordamiento está oculto).

Eliminar esa regla, y el cambio .fake-select'es max-width:100%de solo width:100%y se adapta a todo. La advertencia es que ve todo el contenido de la selección falsa, pero no creo que esto sea tan malo, y ahora se ajusta horizontalmente.

Actualización: con las reglas actuales en el siguiente violín (que contiene solo selecciones reales), los elementos secundarios del conjunto de campos están restringidos a los anchos correctos. Además de eliminar reglas .fake-selecty corregir comentarios (de // commenta /* comment */, he notado cambios en el CSS del violín.

Ahora entiendo mejor su problema, y ​​el violín refleja cierto progreso. Establezco reglas predeterminadas para todos <select>los .xxlargecorreos electrónicos , y reservo para aquellos que sabe que serán más anchos que 480px (y esto solo funciona porque conoce el ancho de #viewport, y puede agregar manualmente la clase a aquellos demasiado anchos. Solo requiere un poco de prueba )

Prueba

Troyano
fuente
Cualquier solución que use tiene que funcionar de manera real <select>. El sitio real solo tiene <select>s. El punto fake-selectera tener las reglas de diseño de a <select>sin ser realmente un <select>, solo para mostrar que este comportamiento no es un error del navegador que solo ocurre con los <select>elementos. Por lo tanto, cambiar los estilos de .fake-selectser menos como una <select>derrota el propósito.
Rory O'Kane
Reemplacé la .fake-selectcaja con un <select>(idéntico al que ya está presente) para demostrar. Todos los elementos están restringidos al ancho del elemento primario (excepto cuando hace clic en él y despliega las opciones, que se muestran en una sola línea, pero no creo que pueda controlarlo). También eliminé todas las reglas para .fake-select. ¿El violín actual hace lo que necesita?
Troyano
No es asi. width: 100%funciona con los menús largos en la página, pero no funciona bien con menús cortos. Expande los menús cortos al ancho completo de la página, pero quiero que los menús cortos mantengan su ancho corto. Los menús deben ser su ancho natural si hay espacio, pero 100% de ancho si son demasiado grandes para sus padres. Eso es lo que max-widthse supone que debe hacer, pero no lo hace en este caso.
Rory O'Kane
He hecho algunos cambios más, separando "todos <select>s" de "largos <select>s", y ahora solo estoy trabajando en el ancho de fondo.
Troyano
#viewporttampoco tiene un ancho fijo. Es por eso que puse el botón Cambiar tamaño de ventana gráfica en la página, para que pueda probar que todo funciona sin importar el ancho de la ventana gráfica. Así como .fake-selectes un sustituto de una <select>prueba real , #viewportes un sustituto de una ventana gráfica real. (Una "ventana gráfica" es básicamente una ventana del navegador). Lo incluí #viewporten la página para que pueda ver fácilmente los elementos que sobresalen de la ventana gráfica, en lugar de tener que desplazarse para verlos.
Rory O'Kane