As casas decimais em uma largura CSS são respeitadas?

225

Algo que eu venho pensando há algum tempo enquanto fazia o design CSS.

As casas decimais nas larguras CSS são respeitadas? Ou eles são arredondados?

.percentage {
  width: 49.5%;
}

ou

.pixel {
  width: 122.5px;
}
Alastair Pitts
fonte

Respostas:

186

Se for uma largura percentual, sim, será respeitada . Como Martin apontou, as coisas se deterioram quando você obtém pixels fracionários, mas se seus valores de porcentagem produzirem um valor inteiro de pixels (por exemplo, 50,5% de 200px no exemplo), você terá um comportamento sensível e esperado.

Edit: Eu já atualizou o exemplo para mostrar o que acontece com pixels fracionários (em Chrome os valores são truncados, então 50, 50,5 e 50,6 todos mostram a mesma largura).

Skilldrick
fonte
7
Você está certo sobre valores percentuais não ser arredondado em si, mas larguras de pixel com casas decimais e o resultado final do cálculo percentual será sempre arredondado para pixels inteiras :)
MartinodF
2
@MartinodF Obrigado pelo esclarecimento. Sim, os pixels são arredondados, mas não está definido se eles realmente arredondam para o mais próximo, piso ou teto (que é o que eu quis dizer com "as coisas quebram").
Skilldrick
1
@ Skilldrick Tentei os pixels fracionários em sua demonstração em alguns navegadores por uma questão de curiosidade: o IE9p7 e o FF4b7 arredondam para o pixel mais próximo, enquanto o Opera 11b, o Chrome 9.0.587.0 e o Safari 5.0.3 truncam o valor. @andras Apenas para esclarecer: não estou dizendo que os valores internos são arredondados, apenas os valores finais de renderização. Se você aplicar zoom ou alguns elementos herdarem propriedades e assim por diante, essas casas decimais serão contadas.
MartinodF
10
Atualização moderna: minha versão 24 do Chrome, na verdade, arredonda os pixels fracionários. Ao visualizar o jsFiddle, 50,5 e 50,6 arredondam para 51px, sendo 1 pixel mais largo que o div de 50px.
Michael Butler
5
O que pode ser mais importante a observar é como os elementos com dimensões fracionárias de pixels se empilham um ao lado do outro. Enquanto eles fazem rodada visualmente por si mesmos, eles também não ocupam espaço extra quando colocado ao lado de outros elementos fractionally cotado: cssdesk.com/8R2rB
Sandy Gifford
53

Mesmo quando o número é arredondado quando a página é pintada, o valor total é preservado na memória e usado para o cálculo filho subsequente. Por exemplo, se sua caixa de 100,4999 px for 100 px, seu filho com uma largura de 50% será calculado como 0,5 * 100,4999 em vez de 0,5 * 100. E assim por diante para níveis mais profundos.

Criei sistemas de layout de grade profundamente aninhados, onde as larguras dos pais são ems e os filhos são porcentagens, e incluir até quatro pontos decimais a montante teve um impacto notável.

Edge case, claro, mas algo para se ter em mente.

natekoechley
fonte
2
A resposta aceita é mais completa que esta, mas a anedota desta me dá uma idéia melhor de como as implicações técnicas se farão sentir. Obrigado por publicá-lo.
Tom
23

Embora os pixels fracionários pareçam arredondar para elementos individuais (como o @SkillDrick demonstra muito bem) , é importante saber que os pixels fracionais são realmente respeitados no modelo de caixa real .

Isso pode ser visto melhor quando os elementos são empilhados um ao lado do outro (ou por cima deles); em outras palavras, se eu colocasse 400 divs de 0,5 pixel lado a lado, elas teriam a mesma largura que uma única div de 200 pixels. Se todos eles realmente arredondado para 1px (como olhar para elementos individuais implicaria) que seria de esperar a 200px div a ser metade do tempo.

Isso pode ser visto neste trecho de código executável:

body {
  color:            white;
  font-family:      sans-serif;
  font-weight:      bold;
  background-color: #334;
}

.div_house div {
  height:           10px;
  background-color: orange;
  display:          inline-block;
}

div#small_divs div {
  width:            0.5px;
}

div#large_div div {
  width:            200px;
}
<div class="div_house" id="small_divs">
  <p>0.5px div x 400</p>
  <div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
</div>
<br>
<div class="div_house" id="large_div">
  <p>200px div x 1</p>
  <div></div>
</div>

Sandy Gifford
fonte
11
Com relação à renderização: no seu exemplo, você tem dois divs competindo por cada pixel. Nesses casos, seu navegador escolherá um deles para renderizar todo o pixel - para evitar desfocagem e outros artefatos estranhos. Se você definir metade dos pixels como azuis, usando :nth-child(even)ou :nth-child(odd), notará que tudo é laranja ou tudo é azul - não uma mistura de azul e laranja (que seria um tom de roxo vago).
Daan Wilmer
16

A largura será arredondada para um número inteiro de pixels .

Não sei se todos os navegadores irão arredondá-lo da mesma maneira. Todos eles parecem ter uma estratégia diferente ao arredondar porcentagens de sub-pixel. Se você estiver interessado nos detalhes do arredondamento de sub-pixels em diferentes navegadores, há um excelente artigo sobre o ElastiCSS .

edit : Eu testei a demo do @ Skilldrick em alguns navegadores por uma questão de curiosidade. Ao usar valores de pixels fracionários (não porcentagens, eles funcionam como sugerido no artigo que eu linkei), o IE9p7 e o FF4b7 parecem arredondar para o pixel mais próximo, enquanto o Opera 11b, o Chrome 9.0.587.0 e o Safari 5.0.3 truncam as casas decimais. Não que eu esperasse que eles tivessem algo em comum, afinal ...

MartinodF
fonte
7

Eles parecem arredondar os valores para o número inteiro mais próximo; mas estou vendo inconsistência no chrome, safari e firefox.

Por exemplo, se 33,3% se converter em 420,945px

chrome e firexfox mostram-no como 421px. enquanto o safari mostra como 420px.

Parece que o chrome e o firefox seguem a lógica do piso e do teto, enquanto o safari não. Esta página parece discutir o mesmo problema

http://ejohn.org/blog/sub-pixel-problems-in-css/

de novo
fonte
6

Os elementos precisam pintar para um número inteiro de pixels e, como as outras respostas abordadas, as porcentagens são realmente respeitadas.

Uma observação importante é que pixels , nesse caso, significam pixels css , não pixels da tela; portanto, um contêiner de 200px com um filho de 50,7499% será arredondado para 101px pixels css , que serão renderizados em 202px em uma tela retina e não em 400 *. 507499 ~ = 203px.

A densidade da tela é ignorada neste cálculo e não há como pintar * um elemento para tamanhos específicos de subpixel de retina. Você não pode ter fundos ou bordas de elementos renderizados com tamanho menor que 1 css pixel , mesmo que o tamanho real do elemento possa ser menor que 1 pixel css, como mostrou Sandy Gifford.

[*] Você pode usar algumas técnicas como 0,5 sombra de caixa de deslocamento, etc., mas as propriedades reais do modelo de caixa serão pintadas em um pixel CSS completo.

Olex Ponomarenko
fonte
Excelente observação
agosto