Entrada com display: bloco não é um bloco, por que não?

153

Por que display:block;width:auto;minha entrada de texto não se comporta como uma div e preenche a largura do contêiner?

Fiquei com a impressão de que uma div é simplesmente um elemento de bloco com largura automática. No código a seguir, a div e a entrada não devem ter dimensões idênticas?

Como obtenho a entrada para preencher a largura? A largura de 100% não funcionará, porque a entrada possui preenchimento e borda (causando uma largura final de 1 pixel + 5 pixels + 100% + 5 pixels + 1 pixels). Larguras fixas não são uma opção, e estou procurando algo mais flexível.

Eu preferiria uma resposta direta a uma solução alternativa. Parece uma peculiaridade do CSS e entender que pode ser útil mais tarde.

<!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>

Devo salientar que já posso fazer isso com soluções alternativas do invólucro. Além disso, sem entender as relações semânticas da página e os seletores de CSS, estou tentando entender a natureza do problema e se ele pode ser superado alterando a natureza da própria entrada.

Ok, isso é realmente estranho! Eu descobri que a solução é simplesmente adicionar max-width:100%a uma entrada com width:100%;padding:5px;. No entanto, isso levanta ainda mais questões (que eu farei em uma pergunta separada), mas parece que width usa o modelo de caixa CSS normal e max-width usa o modelo de caixa de borda do Internet Explorer. Que estranho.

Ok, esse último parece ser um bug no Firefox 3. O Internet Explorer 8 e o Safari 4 limitam a largura máxima a 100% + preenchimento + borda, que é o que as especificações dizem fazer. Finalmente, o Internet Explorer acertou em algo.

Oh meu Deus, isso é incrível! No processo de brincar com isso, e com muita ajuda dos veneráveis ​​gurus Dean Edwards e Erik Arvidsson , consegui reunir três soluções separadas para criar uma largura de 100% entre navegadores em elementos com preenchimento e bordas arbitrários. Veja a resposta abaixo. Esta solução não requer nenhuma marcação HTML extra, apenas uma classe (ou seletor) e um comportamento opcional para o Internet Explorer herdado.

SpliFF
fonte
7
@SleepyCod que não é uma duplicata exata. Esta questão lida com o problema deinput elementos aparentemente não cumprindo a especificação CSS 2.1, enquanto a pergunta que você vinculou pergunta como evitar caixas transbordantes que ocorrem perfeitamente dentro dos limites da especificação CSS 2.1. As perguntas e suas soluções se sobrepõem, mas chamá-las de duplicatas exatas está simplesmente errada.
amn

Respostas:

130

Confira o que eu criei, uma solução usando o box-sizing:border-boxestilo relativamente desconhecido do CSS 3. Isso permite uma largura '100%' verdadeira em qualquer elemento, independentemente do preenchimento e / ou das bordas dos 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 solução suporta o Internet Explorer 6 e o ​​Internet Explorer 7 por meio de um comportamento escrito por Erik Arvidsson com alguns ajustes de Dean Edwards para suportar porcentagens e outras larguras que não sejam de pixels.

Exemplo de trabalho
prático de comportamento (boxsizing.htc)

SpliFF
fonte
Parece uma solução incrível, mas não funciona no IE8 (as caixas div e field não são largas o suficiente). Você sabe se houve alguma atualização sobre esse método? Obrigado!
Rocketmonkeys
2
Este polyfill por Schepp atualiza o polyfill IE6 / 7 para lidar com mais casos de ponta e trabalhar com IE8 mais no github: github.com/Schepp/box-sizing-polyfill
nicjohnson
Obrigado! Não consegui entender por que <input type = text> e <input type = submit> tinham larguras diferentes quando eu defini os dois com 300 px de largura. Isso resolveu! Observe que, dois anos depois, você ainda precisará usar o prefixo -moz- para a versão mais recente do Firefox. caniuse.com/#feat=css3-boxsizing
Darren Cook
4
Infelizmente, esta abordagem não pode ser usado para eliminar a div envoltório se você também precisa adicionar margens (porque as margens não funcionam direito em qualquer elemento se você usar width: 100%)
SystemParadox
6
Isso não resolve o problema. Sim ele funciona se você usar width:100%, mas isso não acontece se você usar width:auto, consulte aqui: jsfiddle.net/hGuzE
nimrod
8

A razão pela qual isso acontece é que o tamanho de uma entrada de texto é determinado por seu atributo de tamanho. adicione size = "50" dentro da tag <input>. Então mude para size = "100" - entende o que eu quero dizer?

Suspeito que exista uma solução melhor, mas a única que me vem à mente é algo que encontrei na pergunta "Recursos ocultos do HTML" no SO: use uma div editável por conteúdo, em vez de uma entrada. Passar a entrada do usuário para o formulário anexo (se é isso que você precisa) pode ser um pouco complicado.

Recursos ocultos do HTML

MatrixFrog
fonte
8
Estou curioso para saber como o pessoal do CSS justifica isso. Se a largura pode substituir o tamanho explicitamente de pixels / porcentagem, não vejo por que ele deve continuar a honrá-lo quando o elemento é um bloco.
SpliFF 23/06/09
1
No entanto, o mesmo acontece buttontambém, que não tem um sizeatributo?
Zanona
1
Uma pergunta que se concentra mais na parte "por que o padrão é assim" como esta resposta: stackoverflow.com/questions/4567988/… A principal afirmação é de que é porque inputé um elemento substituído.
Ciro Santilli publicou 27/10/14
7

Sua melhor aposta é agrupar a entrada em uma div com sua borda, margens, etc., e ter a entrada interna com largura de 100% e sem borda, sem margens, etc.

Por exemplo,

<!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
fonte
1
Sim, vai funcionar, mas isso é mais uma solução alternativa do que uma resposta. Estou tentando estabelecer por que a entrada parece ignorar o comportamento do bloco.
SpliFF 23/06/09
2
Jonathan, por favor, perdoe minha aparente grosseria aqui, mas eu vim aqui procurando a resposta correta (tm) e também li com prazer a parte em que o @SpliFF menciona especificamente que ele preferiria uma "resposta direta a uma solução alternativa, mas você ainda adiciona outra redundante (como, repetido muitas vezes tanto no SO e em outros lugares na Internet) resposta, aparentemente ignorando o contrato de questão Posso perguntar-lhe -. ? por isso . Agradecemos antecipadamente a sua -Curiously.
amn
1

Você poderia fingir, assim:

<!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
fonte
1
Eu fiz a abordagem falsa no passado, mas para ser honesto, estou ficando cansado disso. Acabo com todos os tipos de hacks retardados, como usar 99% de largura para obter entradas e selecionar para corresponder. Eu realmente quero uma maneira de tratar uma entrada como uma div e eu esperava que tivesse esquecido alguma coisa.
SpliFF 23/06/09
2
sua entrada também excederá o inputWrapper porque ainda possui largura: 100% com um preenchimento interno.
SpliFF 23/06/09
1

Tente o seguinte:

form { padding-right: 12px; overflow: visible; }
input { display: block; width: 100%; }
Mike
fonte
1
você deixou de fora o preenchimento e a borda de entrada. Eu estava prestes a dizer que você está errado até perceber o que está fazendo. Agora entendi o que o merkuro estava tentando fazer (o código dele ainda está errado, mas o conceito estava quase lá). O direito de preenchimento altera o significado de 100% por 12px (borda mais preenchimento de entrada). A desvantagem dessa abordagem é que todos os outros filhos da forma também são afetados pelo preenchimento e precisam compensar também.
SpliFF 23/06/09
1

Além disso, você pode fingir, assim:

<!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
fonte
1
mesmo probablem que acima, você tem um preenchimento interno com 100% de largura. Isso vai transbordar.
23310 SpliFF
você pode fazer isso com javascript
AlexC
1

Adicione isso ao seu estilo:

box-sizing: border-box;
John Porter
fonte