Comment puis-je créer une largeur de 100% TextArea sans débordement lorsque le remplissage est présent dans CSS?

426

J'ai l'extrait CSS et HTML suivant en cours de rendu.

textarea
{
  border:1px solid #999999;
  width:100%;
  margin:5px 0;
  padding:3px;
}
<div style="display: block;" id="rulesformitem" class="formitem">
  <label for="rules" id="ruleslabel">Rules:</label>
  <textarea cols="2" rows="10" id="rules"/>
</div>

Le problème est que la zone de texte finit par être 8px plus large (2px pour la bordure + 6px pour le remplissage) que le parent. Existe-t-il un moyen de continuer à utiliser la bordure et le remplissage, mais de limiter la taille totale de la textareaà la largeur du parent?

Eric Schoonover
la source
Btw il y a un bon article pour cela par Jeffrey Way sur tutsplus ici: net.tutsplus.com/tutorials/html-css-techniques/… Peut-être que cela aidera quelqu'un;)
Quelqu'un

Réponses:

664

Pourquoi ne pas oublier les hacks et le faire avec CSS?

Celui que j'utilise fréquemment:

.boxsizingBorder {
    -webkit-box-sizing: border-box;
       -moz-box-sizing: border-box;
            box-sizing: border-box;
}

Voir le support du navigateur ici .

Piet Bijl
la source
22
Je ne peux pas croire que ça a marché. Mais ça l'a fait. CSS n'est jamais aussi simple. :-)
Nate Bird
1
Cela doit être l'une des choses les plus cool que j'ai trouvées depuis un moment. Merci, y a-t-il une chance qu'il existe un moyen de le faire dans IE7 également?
Jeremy A. West
47
Notez que vous voudrez toujours utiliser la largeur: 100% en conjonction avec la zone de bordure.
Tyler
3
Les anciennes versions d'Internet Explorer n'utilisent-elles pas uniquement le comportement de la zone de bordure?
Peter Hedberg
3
quelqu'un peut-il expliquer cela, où va ce cours? une div entourant la zone de texte?
koolaang
81

La réponse à de nombreux problèmes de formatage CSS semble être "ajouter un autre <div>!"

Donc, dans cet esprit, avez-vous essayé d'ajouter une div wrapper à laquelle la bordure / le rembourrage sont appliqués, puis de mettre la zone de texte de 100% de largeur à l'intérieur de cela? Quelque chose comme (non testé):

textarea
{
  width:100%;
}
.textwrapper
{
  border:1px solid #999999;
  margin:5px 0;
  padding:3px;
}
<div style="display: block;" id="rulesformitem" class="formitem">
  <label for="rules" id="ruleslabel">Rules:</label>
  <div class="textwrapper"><textarea cols="2" rows="10" id="rules"/></div>
</div>

Dave Sherohman
la source
1
J'ai fini par m'éloigner de l'utilisation de% largeurs. Je crois cependant que votre approche fonctionnerait tout aussi bien. Merci!
Eric Schoonover
5
N'oubliez pas d'ajouter "." à la classe textwrapper.
Chris Porter
3
@Chris: Merci et corrigé. Je suis légèrement surpris qu'il ait fallu près d'un an et demi à quelqu'un pour attraper ça ...
Dave Sherohman
2
À quoi ressembleront les barres de défilement de la zone de texte dans ce cas?
Daniel LeCheminant du
1
En chrome, lorsque vous concentrez l'élément textarea, il est mis en surbrillance automatiquement et si vous créez un remplissage pour le wrapper div, ce remplissage sera visible et deux bordures seront visibles à cause de cela. Un en surbrillance et un autre en bordure .textwrapper: 1px solid # 999999;
Quelqu'un
22

considérons la sortie finale rendue à l'utilisateur de ce que nous voulons réaliser: une zone de texte rembourrée avec une bordure et un rembourrage, dont les caractéristiques sont qu'en cliquant, elles passent le focus à notre zone de texte, et l'avantage d'une largeur automatique de 100% typique des éléments de bloc.

La meilleure approche à mon avis est d'utiliser autant que possible des solutions de bas niveau, pour atteindre le maximum de support des navigateurs. Dans ce cas, le seul HTML pourrait fonctionner correctement, en évitant l'utilisation de Javascript (que nous aimons de toute façon).

La balise LABEL vient dans notre aide car a un tel comportement et est autorisée à contenir les éléments d'entrée auxquels elle doit s'adresser. Son style par défaut est celui des éléments en ligne, donc, donnant à l'étiquette un style d'affichage de bloc, nous pouvons nous prévaloir de la largeur automatique de 100%, y compris le rembourrage et les bordures, tandis que la zone de texte intérieure n'a pas de bordure, pas de rembourrage et une largeur de 100% .

En examinant les spécificités du W3C, nous pouvons remarquer d'autres avantages:

  • aucun attribut "for" n'est nécessaire: lorsqu'une balise LABEL contient l'entrée cible, elle concentre automatiquement l'entrée enfant lorsqu'elle est cliquée;
  • si une étiquette externe pour la zone de texte a déjà été conçue, aucun conflit ne se produit, car une entrée donnée peut avoir une ou plusieurs étiquettes.

Voir les spécificités du W3C pour des informations plus détaillées.

Exemple simple:

.container { 
  width: 400px; 
  border: 3px 
  solid #f7c; 
  }
.textareaContainer {
	display: block;
	border: 3px solid #38c;
	padding: 10px;
  }
textarea { 
  width: 100%; 
  margin: 0; 
  padding: 0; 
  border-width: 0; 
  }
<body>
<div class="container">
	I am the container
	<label class="textareaContainer">
		<textarea name="text">I am the padded textarea with a styled border...</textarea>
	</label>
</div>
</body>

Le remplissage et la bordure des éléments .textareaContainer sont ceux que nous voulons donner à la zone de texte. Essayez de les modifier pour les styliser comme vous le souhaitez. J'ai donné un remplissage et des bordures larges et visibles à l'élément .textareaContainer pour vous permettre de voir leur comportement lorsque vous cliquez dessus.

Emanuele Del Grande
la source
Je ne sais pas quels accrochages entre navigateurs se cachent ici, mais j'ai aimé l'approche. +1
HRJ
15

Si vous n'êtes pas trop gêné par la largeur du rembourrage, cette solution conservera également le rembourrage en pourcentages.

textarea
{
    border:1px solid #999999;
    width:98%;
    margin:5px 0;
    padding:1%;
}

Pas parfait, mais vous obtiendrez un rembourrage et la largeur s'additionne à 100%, donc tout va bien

qui
la source
12

Je suis tombé sur une autre solution ici qui est si simple: ajoutez padding-right au conteneur de la zone de texte. Cela conserve la marge, la bordure et le rembourrage de la zone de texte, ce qui évite le problème que Beck a signalé à propos de la mise en évidence de la mise au point que chrome et safari mettent autour de la zone de texte.

Le padding-right du conteneur doit être la somme de la marge, de la bordure et du padding effectifs des deux côtés de la zone de texte, plus tout padding que vous pourriez souhaiter pour le conteneur. Donc, pour le cas de la question d'origine:

textarea{
    border:1px solid #999999;
    width:100%;
    margin:5px 0;
    padding:3px;
}
.textareacontainer{
    padding-right: 8px; /* 1 + 3 + 3 + 1 */
}

<div class="textareacontainer">
    <textarea></textarea>
</div>
Brian
la source
1
+1 Cela fonctionnera dans plus de navigateurs que les instructions CSS3. La triste vérité est que le monde a encore besoin de divs wrapper.
BenSwayne
J'aime vraiment cette réponse. Il permet à la zone de texte de s'ajuster sans aucun pourcentage magique inférieur à 100%. Vous pouvez utiliser un rembourrage de tous les côtés dans l'encapsuleur pour forcer la zone de texte à se déplacer et à rester à l'intérieur du parent. La hauteur minimale et la hauteur doivent également être à 100% sur l'emballage. La zone de texte peut ensuite être réglée à 100% avec le même rembourrage pour que tout soit parfaitement ajusté.
justdan23
9

Ce code fonctionne pour moi avec IE8 et Firefox

<td>
    <textarea style="width:100%" rows=3 name="abc">Modify width:% accordingly</textarea>
</td>
Jeff Guest
la source
Fonctionne également dans Chrome.
Sanjeev
5

Vous pouvez utiliser la propriété box-sizing, elle est prise en charge par tous les principaux navigateurs conformes aux normes et IE8 +. Cependant, vous aurez toujours besoin d'une solution de contournement pour IE7. En savoir plus ici .

jzfgo
la source
@DavidJohnstone: Et comme vous ne développez plus de sites pour IE7 ou plus, c'est LA solution :)
Jonatan Littke
2

Non, vous ne pouvez pas faire ça avec CSS. C'est la raison pour laquelle Microsoft a initialement introduit un autre modèle de boîte , et peut-être plus pratique . Le modèle de boîte qui a finalement gagné, rend impossible la combinaison de pourcentages et d'unités.

Je ne pense pas que ce soit OK avec vous d'exprimer le rembourrage et les largeurs de bordure en pourcentage du parent aussi.

buti-oxa
la source
2

Je cherchais une solution de style en ligne au lieu d'une solution CSS, et c'est le mieux que je puisse faire pour une zone de texte réactive:

<div style="width: 100%; max-width: 500px;">
  <textarea style="width: 100%;"></textarea>
</div>
Jee Mok
la source
1

Si vous le rembourrez et le décalez comme ceci:

textarea
{
    border:1px solid #999999;
    width:100%;
    padding: 7px 0 7px 7px; 
    position:relative; left:-8px; /* 1px border, too */
}

le côté droit de la zone de texte s'aligne parfaitement avec le côté droit du conteneur, et le texte à l'intérieur de la zone de texte s'aligne parfaitement avec le corps du texte dans le conteneur ... et le côté gauche de la zone de texte `` ressort '' un peu. c'est parfois plus joli.

pic commun
la source
1

Pour les personnes qui utilisent Bootstrap, textarea.form-control peut également entraîner des problèmes de dimensionnement de la zone de texte. Chrome et Firefox semblent utiliser des hauteurs différentes avec le CSS Bootstrap suivant:

textarea.form-conrtol{
    height:auto;
}
Gwi7d31
la source
1

Je règle souvent ce problème avec calc(). Vous donnez simplement à la zone de texte une largeur de 100% et une certaine quantité de remplissage, mais vous devez soustraire le remplissage total gauche et droit de la largeur de 100% que vous avez donné à la zone de texte:

textarea {
    border: 0px;
    width: calc(100% -10px);
    padding: 5px; 
}

Ou si vous souhaitez donner une bordure à la zone de texte:

textarea {
    border: 1px;
    width: calc(100% -12px); /* plus the total left and right border */
    padding: 5px; 
}
Jeroen Bellemans
la source
0

Et les marges négatives?

textarea {
    border:1px solid #999999;
    width:100%;
    margin:5px -4px; /* 4px = border+padding on one side */
    padding:3px;
}
meustrus
la source
0

* {
    box-sizing: border-box;
}

.container {
    border-radius: 5px;
    background-color: #f2f2f2;
    padding: 20px;
}

/* Clear floats after the columns */
.row:after {
    content: "";
    display: table;
    clear: both;
}

input[type=text], select, textarea{
    width: 100%;
    padding: 12px;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
    resize: vertical;
}
<div class="container">
  <div class="row">
    <label for="name">Name</label>
    <input type="text" id="name" name="name" placeholder="Your name..">
  </div>
  <div class="row">
    <label for="country">Country</label>
    <select id="country" name="country">
      <option value="australia">UK</option>
      <option value="canada">USA</option>
      <option value="usa">RU</option>
    </select>
  </div>    
  <div class="row">
    <label for="subject">Subject</label>
    <textarea id="subject" name="subject" placeholder="Write something.." style="height:200px"></textarea>
  </div>
</div>

antelove
la source