Entrada con pantalla: el bloque no es un bloque, ¿por qué no?

153

¿Por qué display:block;width:auto;en mi entrada de texto no se comporta como un div y llena el ancho del contenedor?

Tenía la impresión de que un div es simplemente un elemento de bloque con ancho automático. En el siguiente código, ¿no deberían el div y la entrada tener dimensiones idénticas?

¿Cómo obtengo la entrada para llenar el ancho? El 100% de ancho no funcionará porque la entrada tiene relleno y un borde (lo que causa un ancho final de 1 píxel + 5 píxeles + 100% + 5 píxeles + 1 píxeles). Los anchos fijos no son una opción, y estoy buscando algo más flexible.

Prefiero una respuesta directa a una solución alternativa. Esto parece una peculiaridad de CSS y comprenderlo puede ser útil más adelante.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>width:auto</title>

        <style>
        div, input {
            border: 1px solid red;
            height: 5px;
            padding: 5px;
        }
        input, form {
            display: block;
            width: auto;
        }
        </style>
    </head>

    <body>
        <div></div>
        <form>
            <input type="text" name="foo" />
        </form>
    </body>
</html>

Debo señalar que ya puedo hacer esto con soluciones de envoltura. Además de este problema con la semántica de la página y las relaciones del selector CSS, estoy tratando de comprender la naturaleza del problema y si se puede superar cambiando la naturaleza de la ENTRADA.

Ok, esto es realmente extraño! He descubierto que la solución es simplemente agregar max-width:100%a una entrada con width:100%;padding:5px;. Sin embargo, esto plantea aún más preguntas (que haré en una pregunta separada), pero parece que el ancho usa el modelo de cuadro CSS normal y el ancho máximo usa el modelo de cuadro de borde de Internet Explorer. Que raro.

Ok, ese último parece ser un error en Firefox 3. Internet Explorer 8 y Safari 4 limitan el ancho máximo al 100% + relleno + borde, que es lo que dice hacer la especificación. Finalmente, Internet Explorer hizo algo bien.

¡Dios mío, esto es asombroso! En el proceso de jugar con esto, y con mucha ayuda de los venerables gurús Dean Edwards y Erik Arvidsson , logré juntar tres soluciones separadas para hacer un verdadero navegador cruzado de 100% de ancho en elementos con relleno y bordes arbitrarios. Ver la respuesta a continuación. Esta solución no requiere ningún marcado HTML adicional, solo una clase (o selector) y un comportamiento opcional para Internet Explorer heredado.

SpliFF
fuente
77
@SleepyCod que no es un duplicado exacto. Esta pregunta trata el problema de los inputelementos que aparentemente no cumplen con la especificación CSS 2.1, mientras que la pregunta a la que se vinculó pregunta cómo evitar el desbordamiento de cuadros que ocurre perfectamente dentro de los límites de la especificación CSS 2.1 por cierto. Tanto las preguntas como sus soluciones se superponen, pero llamarlas duplicados exactos es simplemente incorrecto.
amn

Respuestas:

130

Echa un vistazo a lo que se me ocurrió, una solución que utiliza el box-sizing:border-boxestilo relativamente desconocido de CSS 3. Esto permite un ancho "verdadero" del 100% en cualquier elemento, independientemente del relleno y / o bordes de esos elementos.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">

        <title>Cross-browser CSS box-sizing:border-box</title>

        <style type="text/css">
            form {display:block; margin:0; padding:0; width:50%; border:1px solid green; overflow:visible}
            div, input {display:block; border:1px solid red; padding:5px; width:100%; font:normal 12px Arial}

            /* The voodoo starts here */
            .bb {
                box-sizing: border-box; /* CSS 3 rec */
                -moz-box-sizing: border-box; /* Firefox 2 */
                -ms-box-sizing: border-box; /* Internet Explorer 8 */
                -webkit-box-sizing: border-box; /* Safari 3 */
                -khtml-box-sizing: border-box; /* Konqueror */
            }
        </style>

        <!-- The voodoo gets scary. Force Internet Explorer 6 and Internet Explorer 7 to support Internet Explorer 5's box model -->
        <!--[if lt IE 8]><style>.bb {behavior:url("boxsizing.htc");}</style><![endif]-->
    </head>

    <body>
        <form name="foo" action="#">
            <div class="bb">div</div>
            <input class="bb" size="20" name="bar" value="field">
        </form>
    </body>
</html>

Esta solución es compatible con Internet Explorer 6 e Internet Explorer 7 a través de un comportamiento escrito por Erik Arvidsson con algunos ajustes de Dean Edwards para admitir porcentajes y otros anchos sin píxeles.

Ejemplo de trabajo
Comportamiento (boxsizing.htc)

SpliFF
fuente
Esto parece una solución increíble, pero no funciona en IE8 (los cuadros div y field no son lo suficientemente anchos). ¿Sabes si ha habido alguna actualización en este método? ¡Gracias!
rocketmonkeys
2
Este polyfill de Schepp actualiza el polyfill IE6 / 7 para manejar más casos extremos y trabajar con IE8 en github: github.com/Schepp/box-sizing-polyfill
nicjohnson
¡Gracias! No pude entender por qué <input type = text> y <input type = submit> tenían anchos diferentes cuando los configuré para que ambos tuvieran 300px de ancho. Esto lo resolvió! Tenga en cuenta que dos años después aún necesita usar el prefijo -moz- para la última versión de Firefox. caniuse.com/#feat=css3-boxsizing
Darren Cook
44
Desafortunadamente, este enfoque no se puede usar para eliminar la división del contenedor si también necesita agregar márgenes (porque los márgenes no funcionan correctamente en ningún elemento si usa ancho: 100%)
SystemParadox
66
Sin embargo, eso no soluciona el problema. Sí, funciona si lo usa, width:100%pero no lo hace si lo usa width:auto, consulte aquí: jsfiddle.net/hGuzE
nimrod
8

La razón por la que esto sucede es que el tamaño de una entrada de texto está determinado por su atributo de tamaño. agregue size = "50" dentro de la etiqueta <input>. Luego cámbielo a size = "100". ¿Ve a qué me refiero?

Sospecho que hay una mejor solución, pero la única que me viene a la mente es algo que encontré en la pregunta "Características ocultas de HTML" en SO: utilice un div editable por contenido, en lugar de una entrada. Pasar la entrada del usuario al formulario adjunto (si eso es lo que necesita) puede ser un poco complicado.

Características ocultas de HTML

MatrixFrog
fuente
8
Tengo curiosidad por saber cómo la gente de CSS justifica esto. Si el ancho puede anular el tamaño explícitamente con píxeles / porcentaje, no veo por qué debería seguir honrándolo cuando el elemento es un bloque.
SpliFF
1
Sin embargo, sucede buttonlo mismo que no tiene un sizeatributo?
zanona 12/12/2013
1
Una pregunta que se centra más en la parte "por qué el estándar es así" como esta respuesta: stackoverflow.com/questions/4567988/… La principal afirmación es que es porque inputes un elemento reemplazado.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
7

Su mejor opción es envolver la entrada en un div con su borde, márgenes, etc., y tener la entrada dentro con un ancho del 100% y sin borde, sin márgenes, etc.

Por ejemplo,

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>width:auto</title>

        <style>
            div {
                border: 1px solid red;
                padding: 5px;
            }
            input, form {
                display: block;
                width: 100%;
            }
        </style>
    </head>

    <body>
        <form>
            <div><input type="text" name="foo" /></div>
        </form>
    </body>
</html>
Jonathan Fingland
fuente
1
Sí, funcionará, pero eso es más una solución que una respuesta. Estoy tratando de establecer por qué la entrada parece ignorar el comportamiento del bloque.
SpliFF
2
Jonathan, por favor, perdona mi aparente rudeza aquí, pero vine aquí buscando la respuesta correcta (tm), y también con mucho gusto leí la parte donde @SpliFF menciona específicamente que preferiría una "respuesta directa a una solución alternativa, pero aún agregas otra redundante (como en, repetido muchas veces tanto en SO como en cualquier otro lugar de Internet), aparentemente ignorando el contrato de la pregunta. ¿Puedo preguntarle ? ¿Por qué? Gracias de antemano. -Curiosamente suyo.
amn
1

Podrías fingirlo así:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>width:auto</title>

        <style>
        div, #inputWrapper {
            border: 1px solid red;
        }
        #topDiv {
            padding: 5px;
            height: 5px;
        }
        form {
            display: block;
        }
        #inputWrapper {
            overflow: hidden;
            height: 15px;
        }
        input {
            display: block;
            width: 100%;
            border-style: none;
            padding-left: 5px;
            padding-right: 5px;
            height: 15px;
        }
        </style>
    </head>

    <body>
        <div id="topDiv"></div>
        <form>
          <div id="inputWrapper">
            <input type="text" name="foo" />
          </div>
        </form>
    </body>
</html>
Jacob
fuente
1
He hecho el enfoque falso en el pasado, pero para ser honesto, me estoy cansando de eso. Termino con todo tipo de hacks retardados, como el uso del 99% de ancho para obtener entradas y selecciones para que coincidan. Realmente quiero una forma de tratar una entrada como un div y esperaba haber pasado por alto algo.
SpliFF
2
también su entrada desbordará inputWrapper porque todavía tiene ancho: 100% con un relleno interno.
SpliFF
1

Prueba esto:

form { padding-right: 12px; overflow: visible; }
input { display: block; width: 100%; }
Miguel
fuente
1
omitió el relleno y el borde de entrada. Estaba a punto de decir que estás equivocado hasta que me di cuenta de lo que estás haciendo. Ahora entiendo lo que Merkuro estaba tratando de hacer (su código todavía está mal, pero el concepto estaba casi allí). El margen derecho cambia el significado de 100% por 12 píxeles (borde más margen de entrada). Sin embargo, el inconveniente de este enfoque es que todos los demás hijos de la forma también se ven afectados por el relleno y también necesitan compensar.
SpliFF
1

También podrías fingirlo así:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>width:auto</title>

        <style>

            .container {
                width:90%;
            }

            .container div{
                border: 1px solid red;
                padding: 5px;
                font-size:12px;
                width:100%;
            }

            input{
                  width:100%;
                border: 1px solid red;
                font-size:12px;
                padding: 5px;
            }

            form {

                margin:0px;
                padding:0px;
            }

        </style>
    </head>

    <body>
        <div class="container">
            <div>
                asdasd
            </div>
            <form action="">
                <input type="text" name="foo" />
            </form>
        </div>
    </body>
</html>
AlexC
fuente
1
Probablemente igual que el anterior, tiene un relleno interno con un ancho del 100%. Eso se desbordará.
SpliFF
puedes hacer esto con javascript
AlexC
1

Agregue esto a su estilo:

box-sizing: border-box;
John Porter
fuente