O box model padrão do CSS é uma das coisas mais contra-intuitivas que existem. Mas você pode trocá-lo com o box-sizing do CSS3. E, melhor, funciona em todos os navegadores -- até no IE8!
Todo elemento no HTML é uma caixa. Controlamos seu tamanho com width, sua borda com border e ainda temos as margens externas e internas com margin e padding. Box model é como todas essas propriedades se relacionam pra determinar o tamanho final do elemento.
E o box model tradicional da especificação tem uma regra bastante confusa: diz que a propriedade width trata do tamanho do conteúdo do elemento, não considerando seu padding e border (e a mesma coisa com a altura).
Isso quer dizer que, se você quiser que um elemento ocupe metade da página mas com uma borda de 10px, não funciona fazer border: 10px solid #555; width:50%
. O tamanho final do elemento terá 20px mais metade do tamanho do pai.
border-width: 10px;
width: 50%;
width: 50%;
É assim que as coisas funcionam mas certamente não é assim que nós pensamos. Se você pensa no tamanho de uma caixa, você não pensa só no conteúdo dela. Uma caixa termina em sua borda e isso deveria ser considerado seu tamanho.
Um viva ao IE6!
O curioso é que os primeiros a perceberem que o box model do CSS era esquisito foi a Microsoft. Já no IE6 em quirks mode eles trocaram o box model pra que o width significasse o tamanho total até a borda. A ideia era boa mas o problema foi eles atropelarem a especificação da época, o que acabou criando boa parte dos problemas de incompatibilidade entre navegadores. O IE em standards mode usa o box model oficial e esse é o padrão a partir do IE8.
Mas como a ideia, no fim, era boa, isso acabou se transformando no box-sizing do CSS3, que nos permite trocar o box model que queremos usar.
Por padrão, todos os elementos têm o valor box-sizing: content-box
o que indica que o tamanho dele é definido pelo seu conteúdo apenas -- em outras palavras, é o tal box model padrão que vimos antes. Mas podemos trocar por box-sizing: border-box
que indica que o tamanho agora levará em conta até a borda -- ou seja, o width será a soma do conteúdo com a borda e o padding.
box-sizing: border-box;
border-width: 10px;
width: 50%;
box-sizing: border-box;
width: 50%;
Usando o novo box-sizing
O suporte nos navegadores é excelente, indo até o IE8 -- e há um polyfill pra IE6 e IE7 se você precisar. O Firefox ainda precisa do prefixo -moz- e versões mais antigas do Chrome, Safari e Android, do -webkit-.
Eu uso essa regra em todos os elementos de todas as minhas páginas -- inclusive aqui no blog. Então aplico o seletor universal:
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
Existe uma preocupação quanto à performance do seletor universal *
mas ela certamente não será um problema para algo tão simples e pontual como essa regra. O ruim é abusar e ter diversas regras com seletor universal e descendentes. E você nem devia estar se preocupando com performance de CSS se ainda não tem uma nota maior que 95 no PageSpeed; gzip, minificação, sprites, etc são bem mais importantes pra performance.
Outro ponto importante é que o seletor *
não pega pseudo-elementos. Na prática, acabo usando:
*, *:before, *:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
Atualização Ago/2013: acrescentei os pseudo-elementos na regra e removi informações sobre bug antigo do Firefox.