¿Cómo puedo hacer un TextArea 100% de ancho sin desbordar cuando el relleno está presente en CSS?

426

Tengo el siguiente fragmento de CSS y HTML que se está representando.

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>

El problema es que el área de texto termina siendo 8px más ancho (2px para borde + 6px para relleno) que el padre. ¿Hay alguna manera de continuar usando el borde y el relleno pero restringiendo el tamaño total textareadel ancho de los padres?

Eric Schoonover
fuente
Por cierto, hay un buen artículo para esto de Jeffrey Way en tutsplus aquí: net.tutsplus.com/tutorials/html-css-techniques/… Quizás ayude a alguien;)
Alguien

Respuestas:

664

¿Por qué no olvidar los hacks y simplemente hacerlo con CSS?

Uno que uso con frecuencia:

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

Consulte el soporte del navegador aquí .

Piet Bijl
fuente
22
No puedo creer que esto haya funcionado. Pero lo hizo. CSS nunca es tan fácil. :-)
Nate Bird
1
Esta tiene que ser una de las mejores cosas que he encontrado en mucho tiempo. Gracias, ¿hay alguna posibilidad de que haya una manera de hacer esto también en IE7?
Jeremy A. West
47
Tenga en cuenta que aún querrá usar ancho: 100% junto con el cuadro de borde.
Tyler
3
¿Las versiones anteriores de Internet Explorer no utilizan únicamente el comportamiento de los cuadros de borde?
Peter Hedberg
3
alguien puede explicar esto por favor, ¿a dónde va esta clase? un div que rodea el área de texto?
koolaang
81

La respuesta a muchos problemas de formato CSS parece ser "agregar otro <div>!"

Entonces, en ese espíritu, ¿ha intentado agregar un div de envoltura al que se aplica el borde / relleno y luego poner el área de texto de 100% de ancho dentro de eso? Algo como (no probado):

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
fuente
1
Terminé alejándome de usar% anchuras. Sin embargo, creo que su enfoque funcionaría igual de bien. ¡Gracias!
Eric Schoonover el
55
No olvides agregar "." a la clase textwrapper.
Chris Porter
3
@ Chris: Gracias y arreglado. Estoy un poco sorprendido de que a alguien le haya tomado casi un año y medio
entender
2
¿Cómo se verán las barras de desplazamiento del área de texto en este caso?
Daniel LeCheminant
1
En Chrome, cuando enfoca el elemento textarea, se resalta automáticamente y si crea un relleno para el envoltorio div, este relleno será visible y dos bordes serán visibles debido a eso. Uno de iluminación y otro del borde .textwrapper: 1px sólido # 999999;
Alguien
22

Consideremos el resultado final presentado al usuario de lo que queremos lograr: un área de texto acolchada con un borde y un relleno, cuyas características son que al hacer clic pasan el foco a nuestra área de texto y la ventaja de un ancho automático del 100% típico de los elementos de bloque.

El mejor enfoque en mi opinión es utilizar soluciones de bajo nivel en la medida de lo posible, para alcanzar el máximo soporte de navegadores. En este caso, el único HTML podría funcionar bien, evitando el uso de Javascript (que de todos modos todos amamos).

La etiqueta LABEL viene en nuestra ayuda porque tiene ese comportamiento y puede contener los elementos de entrada a los que debe dirigirse. Su estilo predeterminado es el de los elementos en línea, por lo que, al darle a la etiqueta un estilo de visualización de bloque, podemos aprovechar el ancho automático del 100%, incluido el relleno y los bordes, mientras que el área de texto interna no tiene borde, relleno y un ancho del 100% .

Echando un vistazo a los detalles específicos del W3C, otras ventajas que podemos notar son:

  • no se necesita ningún atributo "for": cuando una etiqueta LABEL contiene la entrada de destino, automáticamente enfoca la entrada secundaria cuando se hace clic;
  • Si ya se ha diseñado una etiqueta externa para el área de texto, no se producen conflictos, ya que una entrada determinada puede tener una o más etiquetas.

Consulte los detalles del W3C para obtener información más detallada.

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

El relleno y el borde de los elementos .textareaContainer son los que queremos dar al área de texto. Intenta editarlos para darle el estilo que quieras. Le di un relleno y bordes grandes y visibles al elemento .textareaContainer para que pueda ver su comportamiento al hacer clic.

Emanuele Del Grande
fuente
No estoy seguro de qué trucos entre navegadores acechan aquí, pero me gustó el enfoque. +1
HRJ
15

Si no le preocupa demasiado el ancho del relleno, esta solución también mantendrá el relleno en porcentajes.

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

No es perfecto, pero obtendrá algo de relleno y el ancho se sumará al 100%, por lo que todo está bien

qui
fuente
12

Encontré otra solución aquí que es tan simple: agregar padding-right al contenedor del área de texto. Esto mantiene el margen, el borde y el relleno en el área de texto, lo que evita el problema que Beck señaló sobre el enfoque destacado que Chrome y Safari pusieron alrededor del área de texto.

El relleno derecho del contenedor debe ser la suma del margen efectivo, el borde y el relleno en ambos lados del área de texto, más cualquier relleno que pueda desear para el contenedor. Entonces, para el caso en la pregunta original:

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
fuente
1
+1 Esto funcionará en más navegadores que las declaraciones CSS3. La desafortunada verdad es que el mundo todavía necesita divisiones envolventes.
BenSwayne
Realmente me gusta esta respuesta. Hace que el área de texto se ajuste sin ningún número mágico de porcentaje inferior al 100%. Puede usar relleno en todos los lados del contenedor para forzar que el área de texto se mueva y permanezca dentro del elemento primario. La altura mínima y la altura también deben ser del 100% en la envoltura. El área de texto se puede configurar al 100% con el mismo relleno para que todo se ajuste perfectamente.
justdan23
9

Este código funciona para mí con IE8 y Firefox

<td>
    <textarea style="width:100%" rows=3 name="abc">Modify width:% accordingly</textarea>
</td>
Jeff Guest
fuente
Trabajó en Chrome también.
Sanjeev
5

Puede hacer uso de la propiedad de tamaño de caja, es compatible con todos los principales navegadores compatibles con el estándar e IE8 +. Sin embargo, aún necesitará una solución para IE7. Lee más aquí .

jzfgo
fuente
@DavidJohnstone: Y dado que ya no estás desarrollando sitios para IE7 o versiones anteriores, esta es LA solución :)
Jonatan Littke
2

No, no puedes hacer eso con CSS. Esa es la razón por la que Microsoft presentó inicialmente otro modelo de caja , y quizás más práctico . El modelo de caja que finalmente ganó, hace que sea poco práctico mezclar porcentajes y unidades.

No creo que esté bien que usted exprese el ancho de los bordes y el relleno también en porcentaje del padre.

buti-oxa
fuente
2

Estaba buscando una solución de diseño en línea en lugar de una solución CSS, y esto es lo mejor que puedo obtener para un área de texto receptiva:

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

Si rellenas y lo compensas así:

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

el lado derecho del área de texto se alinea perfectamente con el lado derecho del contenedor, y el texto dentro del área de texto se alinea perfectamente con el texto del cuerpo en el contenedor ... y el lado izquierdo del área de texto 'sobresale' un poco. A veces es más bonito.

Pico común
fuente
1

Para las personas que usan Bootstrap, textarea.form-control también puede generar problemas de tamaño de textarea. Chrome y Firefox parecen usar diferentes alturas con el siguiente CSS de Bootstrap:

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

A menudo soluciono ese problema con calc(). Simplemente le da al área de texto un ancho del 100% y una cierta cantidad de relleno, pero debe restar el relleno total izquierdo y derecho del ancho del 100% que le ha dado al área de texto:

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

O si quieres darle un borde al área de texto:

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

¿Qué hay de los márgenes negativos?

textarea {
    border:1px solid #999999;
    width:100%;
    margin:5px -4px; /* 4px = border+padding on one side */
    padding:3px;
}
meustrus
fuente
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>

antílope
fuente