Entrée avec affichage: le bloc n'est pas un bloc, pourquoi pas?


153

Pourquoi display:block;width:auto;ma saisie de texte ne se comporte-t-elle pas comme un div et ne remplit-elle pas la largeur du conteneur?

J'avais l'impression qu'un div est simplement un élément de bloc avec une largeur automatique. Dans le code suivant, le div et l'entrée ne devraient-ils pas avoir des dimensions identiques?

Comment puis-je obtenir l'entrée pour remplir la largeur? Une largeur de 100% ne fonctionnera pas, car l'entrée a un remplissage et une bordure (ce qui entraîne une largeur finale de 1 pixel + 5 pixels + 100% + 5 pixels + 1 pixels). Les largeurs fixes ne sont pas une option, et je recherche quelque chose de plus flexible.

Je préférerais une réponse directe à une solution de contournement. Cela semble être une bizarrerie CSS et le comprendre peut être utile plus tard.

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

Je dois souligner que je peux déjà le faire avec des solutions de contournement. En dehors de ce vissage avec la sémantique de la page et les relations de sélecteur CSS, j'essaie de comprendre la nature du problème et s'il peut être surmonté en changeant la nature de l'INPUT lui-même.

Ok, c'est VRAIMENT étrange! J'ai trouvé que la solution consiste simplement à ajouter max-width:100%à une entrée avec width:100%;padding:5px;. Cependant, cela soulève encore plus de questions (que je poserai dans une question distincte), mais il semble que width utilise le modèle de boîte CSS normal et que max-width utilise le modèle de border-box d'Internet Explorer. Comme c'est étrange.

Ok, ce dernier semble être un bogue dans Firefox 3. Internet Explorer 8 et Safari 4 limitent la largeur maximale à 100% + padding + border, ce que la spécification dit de faire. Enfin, Internet Explorer a fait quelque chose de bien.

Oh mon dieu, c'est génial! En jouant avec cela, et avec beaucoup d'aide des vénérables gourous Dean Edwards et Erik Arvidsson , j'ai réussi à rassembler trois solutions distinctes pour créer un véritable cross-browser 100% largeur sur des éléments avec un rembourrage et des bordures arbitraires. Voir la réponse ci-dessous. Cette solution ne nécessite aucun balisage HTML supplémentaire, juste une classe (ou un sélecteur) et un comportement facultatif pour Internet Explorer hérité.



7
@SleepyCod ce n'est pas un doublon exact. Cette question traite du problème des inputéléments apparemment non conformes à la spécification CSS 2.1, tandis que la question à laquelle vous avez lié demande comment éviter le débordement des boîtes qui se produit parfaitement dans les limites de la spécification CSS 2.1. Les questions et leurs solutions se chevauchent, mais les appeler des doubles exacts est tout simplement faux.
amn

Réponses:


130

Découvrez ce que j'ai trouvé, une solution utilisant le box-sizing:border-boxstyle relativement inconnu de CSS 3. Cela permet une largeur «vraie» de 100% sur n'importe quel élément indépendamment du remplissage et / ou des bordures de ces éléments.

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

Cette solution prend en charge Internet Explorer 6 et Internet Explorer 7 via un comportement écrit par Erik Arvidsson avec quelques ajustements de Dean Edwards pour prendre en charge le pourcentage et d'autres largeurs non-pixels.

Exemple de travail
Behavior (boxsizing.htc)


Cela ressemble à une solution étonnante, mais ne fonctionne pas dans IE8 (les boîtes div & field ne sont pas assez larges). Savez-vous s'il y a eu une mise à jour sur cette méthode? Merci!
rocketmonkeys

2
Ce polyfill de Schepp met à jour le polyfill IE6 / 7 pour gérer plus de cas de bord et travailler avec IE8 sur github: github.com/Schepp/box-sizing-polyfill
nicjohnson

Merci! Je ne pouvais pas comprendre pourquoi <input type = text> et <input type = submit> étaient des largeurs différentes alors que je les avais définis tous les deux sur 300 px de large. Cela l'a résolu! Notez que deux ans plus tard, vous devez toujours utiliser le préfixe -moz- pour la dernière version de Firefox. caniuse.com/#feat=css3-boxsizing
Darren Cook

4
Malheureusement, cette approche ne peut pas être utilisée pour éliminer le div wrapper si vous avez également besoin d'ajouter des marges (car les marges ne fonctionnent pas correctement sur aucun élément si vous utilisez width: 100%)
SystemParadox

6
Cela ne résout pas le problème. Oui cela fonctionne si vous utilisez width:100%mais ce n'est pas le cas si vous utilisez width:auto, voir ici: jsfiddle.net/hGuzE
nimrod

8

La raison pour laquelle cela se produit est que la taille d'une entrée de texte est déterminée par son attribut size. ajoutez size = "50" dans la balise <input>. Puis changez-le en size = "100" - voyez ce que je veux dire?

Je soupçonne qu'il existe une meilleure solution, mais la seule qui me vient à l'esprit est quelque chose que j'ai trouvé sur la question "Fonctionnalités cachées du HTML" sur SO: Utilisez un div modifiable par le contenu, au lieu d'une entrée. Passer l'entrée utilisateur au formulaire englobant (si c'est ce dont vous avez besoin) peut être un peu délicat.

Fonctionnalités cachées du HTML


8
Je suis curieux de savoir comment les gens du CSS justifient cela. Si la largeur peut remplacer la taille explicitement avec des pixels / pourcentage, je ne vois pas pourquoi elle devrait continuer à l'honorer lorsque l'élément est un bloc.
SpliFF

1
Cependant, il en va buttonde même pour qui n'a pas d' sizeattribut?
zanona

1
Une question qui se concentre davantage sur la partie "pourquoi la norme est-elle comme celle-ci" comme cette réponse: stackoverflow.com/questions/4567988/... La principale affirmation est que c'est parce que inputc'est un élément remplacé.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

7

Votre meilleur pari est d'envelopper l'entrée dans un div avec votre bordure, vos marges, etc., et d'avoir l'entrée à l'intérieur avec une largeur de 100% et sans bordure, sans marges, etc.

Par exemple,

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

1
Oui, cela fonctionnera, mais c'est plus une solution de contournement qu'une réponse. J'essaye d'établir pourquoi l'entrée semble ignorer le comportement de bloc.
SpliFF

2
Jonathan, veuillez pardonner mon apparente impolitesse ici, mais je suis venu ici à la recherche de la bonne réponse (tm), et j'ai également lu avec plaisir la partie où @SpliFF mentionne spécifiquement qu'il préférerait une «réponse directe à une solution de contournement, mais vous ajoutez encore une autre redondante (comme dans, répété à plusieurs reprises à SO et ailleurs sur Internet), ignorant apparemment le contrat de la question. Puis-je vous demander - pourquoi? Merci d'avance. - Curieusement le vôtre.
amn

1

Vous pouvez le simuler, comme ceci:

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

1
J'ai fait la fausse approche dans le passé, mais pour être honnête, j'en ai marre. Je me retrouve avec toutes sortes de hacks retardés comme utiliser une largeur de 99% pour obtenir des entrées et des sélections pour correspondre. Je veux vraiment un moyen de traiter une entrée comme une div et j'espérais que j'avais juste oublié quelque chose.
SpliFF

2
votre entrée débordera également de inputWrapper car elle a toujours une largeur: 100% avec un remplissage interne.
SpliFF

1

Essaye ça:

form { padding-right: 12px; overflow: visible; }
input { display: block; width: 100%; }

1
vous avez omis le remplissage et la bordure d'entrée. J'étais sur le point de dire que tu as tort jusqu'à ce que je réalise ce que tu fais. Maintenant, je comprends ce que Merkuro essayait de faire (son code est toujours faux, mais le concept était presque là). Le padding-right change la signification de 100% par 12px (bordure plus remplissage de l'entrée). L'inconvénient de cette approche est que tous les autres enfants de la forme sont également affectés par le remplissage et doivent également compenser.
SpliFF

1

Vous pouvez également le simuler, comme ceci:

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

1
même probablem que ci-dessus, vous avez un rembourrage interne sur une largeur de 100%. Cela débordera.
SpliFF

vous pouvez le faire avec javascript
AlexC

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.