Como criar uma largura de TextArea 100% sem estourar quando o preenchimento está presente no CSS?

426

Eu tenho o seguinte trecho de CSS e HTML sendo renderizado.

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>

O problema é que a área de texto acaba sendo 8px mais larga (2px para borda + 6px para preenchimento) do que o pai. Existe uma maneira de continuar a usar borda e preenchimento, mas restringir o tamanho total do textareapara a largura do pai?

Eric Schoonover
fonte
Btw há bom artigo para este por Jeffrey Way em tutsplus aqui: net.tutsplus.com/tutorials/html-css-techniques/... Talvez possa ajudar alguém;)
Alguém

Respostas:

664

Por que não esquecer os hacks e apenas fazê-lo com CSS?

Um que eu uso com frequência:

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

Veja o suporte do navegador aqui .

Piet Bijl
fonte
22
Não acredito que isso funcionou. Mas sim. CSS nunca é tão fácil. :-)
Nate Bird
1
Essa deve ser uma das coisas mais legais que já encontrei há algum tempo. Obrigado, alguma chance de haver uma maneira de fazer isso no IE7 também?
Jeremy A. West
47
Observe que você ainda deseja usar width: 100% em conjunto com a caixa de borda.
Tyler
3
As versões antigas do Internet Explorer não usam apenas o comportamento da caixa de borda?
Peter Hedberg
3
alguém pode explicar isso por favor, para onde vai essa aula? uma div em torno da área de texto?
precisa saber é o seguinte
81

A resposta para muitos problemas de formatação CSS parece ser "add another <div>!"

Então, nesse espírito, você tentou adicionar uma div de wrapper à qual a borda / preenchimento é aplicada e depois colocar a área de texto com 100% de largura dentro dela? Algo como (não testado):

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
fonte
1
Acabei me afastando do uso de% de largura. Eu acredito que sua abordagem funcionaria tão bem quanto isso. Obrigado!
11118 Eric Schoonover
5
Não esqueça de adicionar "." para a classe textwrapper.
Chris Porter
3
@ Chris: Obrigado e corrigido. Estou um pouco surpreso que demorou quase um ano e meio para alguém para pegar isso ...
Dave Sherohman
2
Como serão as barras de rolagem da área de texto neste caso?
precisa saber é o seguinte
1
No chrome, quando você focaliza o elemento da área de texto, ele fica realçado automaticamente e, se você criar preenchimento para o wrapper div, esse preenchimento ficará visível e duas bordas ficarão visíveis por causa disso. Um de destaque e outro da borda .textwrapper: 1px sólido # 999999;
Alguém
22

vamos considerar a saída final renderizada ao usuário do que queremos alcançar: uma área de texto preenchida com borda e preenchimento, cujas características são clicadas, elas passam o foco para nossa área de texto e a vantagem de uma largura automática de 100% típico de elementos de bloco.

A melhor abordagem, na minha opinião, é usar soluções de baixo nível, na medida do possível, para alcançar o suporte máximo aos navegadores. Nesse caso, o único HTML poderia funcionar bem, evitando o uso de Javascript (que de qualquer maneira todos gostamos).

A tag LABEL vem em nossa ajuda porque tem esse comportamento e pode conter os elementos de entrada aos quais deve ser endereçada. Seu estilo padrão é o dos elementos inline, portanto, dando ao rótulo um estilo de exibição de bloco, podemos aproveitar a largura automática de 100%, incluindo preenchimento e bordas, enquanto a área de texto interna não possui borda, preenchimento e largura de 100% .

Examinando as especificidades do W3C, outras vantagens que podemos notar são:

  • nenhum atributo "for" é necessário: quando uma tag LABEL contém a entrada de destino, ela focaliza automaticamente a entrada filho quando clicada;
  • se um rótulo externo para a área de texto já tiver sido projetado, nenhum conflito ocorrerá, pois uma determinada entrada pode ter um ou mais rótulos.

Consulte as especificações do W3C para obter informações mais detalhadas.

Exemplo simples:

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

O preenchimento e a borda dos elementos .textareaContainer são os que queremos fornecer à área de texto. Tente editá-los para estilizá-lo como quiser. Dei preenchimento e bordas grandes e visíveis ao elemento .textareaContainer para permitir que você veja o comportamento deles quando clicado.

Emanuele Del Grande
fonte
Não tenho certeza de quais truques entre navegadores se escondem aqui, mas gostei da abordagem. +1
HRJ 27/10/10
15

Se você não estiver muito preocupado com a largura do preenchimento, essa solução também manterá o preenchimento em porcentagem.

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

Não é perfeito, mas você terá um pouco de preenchimento e a largura é de até 100%, então está tudo bem

qui
fonte
12

Encontrei outra solução aqui que é tão simples: adicione padding-right ao contêiner da área de texto. Isso mantém a margem, a borda e o preenchimento na área de texto, o que evita o problema apontado por Beck sobre o foco destacado pelo chrome e safari ao redor da área de texto.

O preenchimento à direita do contêiner deve ser a soma da margem, borda e preenchimento efetivos nos dois lados da área de texto, além de qualquer preenchimento que você possa desejar para o contêiner. Então, para o caso na pergunta 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
fonte
1
+1 Isso funcionará em mais navegadores do que nas instruções CSS3. A infeliz verdade é que o mundo ainda precisa de divs de invólucro.
precisa saber é o seguinte
Eu realmente gosto desta resposta. Faz com que a área de texto se encaixe sem nenhum número percentual mágico menor que 100%. Você pode usar preenchimento de todos os lados no invólucro para forçar a área de texto a entrar e permanecer dentro do pai. A altura mínima e a altura também precisam estar 100% no invólucro. A área de texto pode ser configurada para 100% com o mesmo preenchimento para que tudo se encaixe perfeitamente.
justdan23
9

Este código funciona para mim com o IE8 e Firefox

<td>
    <textarea style="width:100%" rows=3 name="abc">Modify width:% accordingly</textarea>
</td>
Jeff Guest
fonte
Também funcionou no Chrome.
Sanjeev
5

Você pode usar a propriedade de dimensionamento de caixa, que é suportada por todos os principais navegadores compatíveis com o padrão e pelo IE8 +. Você ainda precisará de uma solução alternativa para o IE7. Leia mais aqui .

jzfgo
fonte
@DavidJohnstone: E desde que você não está desenvolvendo sites para IE7 ou mais mais, esta é a solução :)
Jonatan Littke
2

Não, você não pode fazer isso com CSS. Essa é a razão pela qual a Microsoft introduziu outro modelo de caixa , talvez mais prático . O modelo de caixa que acabou vencendo torna impraticável misturar porcentagens e unidades.

Não acho que você possa expressar larguras de preenchimento e borda em porcentagem dos pais também.

buti-oxa
fonte
2

Eu estava procurando por uma solução de estilo embutido em vez da solução CSS, e é o melhor que posso fazer para uma área de texto responsiva:

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

Se você preencher e compensar assim:

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

o lado direito da área de texto se alinha perfeitamente com o lado direito do contêiner, e o texto dentro da área de texto se alinha perfeitamente com o corpo do texto no contêiner ... e o lado esquerdo da área de texto 'sobressai' um pouco. às vezes é mais bonito.

commonpike
fonte
1

Para pessoas que usam o Bootstrap, o textarea.form-control também pode levar a problemas de dimensionamento da área de texto. Chrome e Firefox parecem usar alturas diferentes com o seguinte CSS de Bootstrap:

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

Costumo corrigir esse problema calc(). Você apenas atribui à área de texto uma largura de 100% e uma certa quantidade de preenchimento, mas é necessário subtrair o preenchimento total esquerdo e direito da largura de 100% que você atribuiu à área de texto:

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

Ou se você deseja atribuir uma borda à área de texto:

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

E as margens negativas?

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