252

Something I've been wondering for a while whilst doing CSS design.

Are decimal places in CSS widths respected? Or are they rounded?

.percentage {
  width: 49.5%;
}

or

.pixel {
  width: 122.5px;
}
Alexander van Oostenrijk
  • 4,644
  • 3
  • 23
  • 37
Alastair Pitts
  • 19,423
  • 9
  • 68
  • 97
  • Are you interested in discovering if a pixel can have decimals? If yes, please clarify that in the question since I honestly do not understand if decimals pixels are a standard by W3C and it could be interesting to clarify in the provided answers – Valerio Bozz May 04 '23 at 21:09

6 Answers6

206

If it's a percentage width, then yes, it is respected:

#outer {
    width: 200px;
}

#first {
    width: 50%;
    height: 20px;
    background-color: red;
}

#second {
    width: 50.5%;
    height: 20px;
    background-color:green;
}

#third {
    width: 51%;
    height: 20px;
    background-color:blue;
}
<div id="outer">
    <div id="first">&nbsp;</div>
    <div id="second">&nbsp;</div>
    <div id="third">&nbsp;</div>
</div>

As Martin pointed out, things break down when you get to fractional pixels, but if your percentage values yield integer pixel value (e.g. 50.5% of 200px in the example) you'll get sensible, expected behaviour.

Edit: I've updated the example to show what happens to fractional pixels (in Chrome the values are truncated, so 50, 50.5 and 50.6 all show the same width.)

#percentage {
    width: 200px;
    color: white;
}

#percentage .first {
    width: 50%;
    height: 20px;
    background-color: red;
}

#percentage .second {
    width: 50.5%;
    height: 20px;
    background-color:green;
}

#percentage .third {
    width: 51%;
    height: 20px;
    background-color:blue;
}

#pixels {
    color: white;
}

#pixels .first {
    width: 50px;
    height: 20px;
    background-color: red;
}

#pixels .second {
    width: 50.5px;
    height: 20px;
    background-color:green;
}

#pixels .third {
    width: 50.6px;
    height: 20px;
    background-color:blue;
}

#pixels .fourth {
    width: 51px;
    height: 20px;
    background-color:red;
}
<div id="percentage">
    <div class="first">50%=100px</div>
    <div class="second">50.5%=101px</div>
    <div class="third">51%=102px</div>
</div>
<br />
<div id="pixels">
    <div class="first">50px</div>
    <div class="second">50.5px</div>
    <div class="third">50.6px</div>
    <div class="fourth">51px</div>
</div>
miken32
  • 42,008
  • 16
  • 111
  • 154
Skilldrick
  • 69,215
  • 34
  • 177
  • 229
  • 7
    You're right about percentage values not being rounded themselves, but pixel widths with decimal places and the final result of the percentage calculation will always be rounded to entire pixels :) – MartinodF Nov 29 '10 at 23:17
  • 2
    @MartinodF Thanks for the clarification. Yes, the pixels are rounded, but it's not defined whether they actually round to nearest, floor or ceiling (which is what I meant by "things break down"). – Skilldrick Nov 29 '10 at 23:20
  • Not necessarily; as far as I know, all browsers internally do subpixel positioning and rendering, with heuristics to pixel-align things that need to have sharp edges (like horizontal and vertical lines). – zwol Nov 29 '10 at 23:20
  • @MartinodF: I agree with your answer and your comment, but there is nothing in theory that would stop a layout engine to render at say 4x the screen resolution and then sample that via some nice method to fit into the 1x screen resolution. A not.so-great example of a similar concept is how super sampling AA works. – Andras Vass Nov 29 '10 at 23:23
  • @andras "in theory" is the key word ;) No current browser does AA, they all round positions and sizes before displaying the elements. I agree that it would be at least interesting to see some vendor implement it though! – MartinodF Nov 29 '10 at 23:28
  • @Skilldrick: If I zoom in on your example using the browser's zoom (or just Ctrl+Wheel on Win), I see that they are clearly different. It is just the default zoom level where they are the same. – Andras Vass Nov 29 '10 at 23:31
  • 1
    @Skilldrick I tried the fractional pixels in your demo on some browsers for the sake of curiosity: both IE9p7 and FF4b7 round to the nearest pixel, while Opera 11b, Chrome 9.0.587.0 and Safari 5.0.3 truncate the value. @andras Just to clarify: I'm not saying that the internal values are rounded, just the final render values are. If you zoom, or some elements inherit properties and so on, that decimal places will count. – MartinodF Nov 29 '10 at 23:35
  • @MartinodF, @Skilldrick: still, CSS itself does not have such a limitation (for either pixels, percents or ems), so any conforming browser should respect fractional values in any units. How they render it to a medium with finite resolution is an implementation detail. What if I always use my browser zoomed out 2x? :-) Should we avoid odd sizes and resort to even ones? :-) – Andras Vass Nov 29 '10 at 23:46
  • @andras I'm not saying that you should stick to use only integer values in any way. Your point is absolutely valid, but you should also keep in mind that the final result that 99.99% of your users (who have their browsers set to 100% zoom) will see, is going to be pixel-rounded :) – MartinodF Nov 29 '10 at 23:49
  • @MartinodF, @Skilldrick: I'm just telling that there are browsers right now that use hardware acceleration for rendering. The idea of rendering on a larger plane and then using the GPU to give smooth results on native screen resolution is not far fetched anymore. Couple that with an ability to use smooth zooming instead of zoom levels and the days of pixel hunting are counted... – Andras Vass Nov 29 '10 at 23:57
  • @Skilldrick: Great answer and a great little jsFiddle. Thanks! – Alastair Pitts Nov 30 '10 at 03:59
  • 11
    Modern update: my Chrome version 24 actually **rounds up** the fractional pixels. Viewing the jsFiddle, 50.5 and 50.6 both round up to 51px, being 1 pixel wider than the 50px div. – Michael Butler Jan 22 '13 at 20:37
  • 5
    What may be most important to note is how elements with fractional pixel dimensions stack next to each other. While they **do** round up visually by themselves, they also don't take up extra space when put next to other fractionally dimensioned elements: http://cssdesk.com/8R2rB – Sandy Gifford Apr 07 '14 at 16:56
  • 1
    @MichaelButler No, it rounds to the nearest. The jsFiddle should have had a 50.4 to be more meaningful because 50.5 would round up whether the rule was to round to the nearest or up. – Nick Rice Jul 05 '17 at 17:59
60

Even when the number is rounded when the page is painted, the full value is preserved in memory and used for subsequent child calculation. For example, if your box of 100.4999px paints to 100px, it's child with a width of 50% will be calculated as .5*100.4999 instead of .5*100. And so on to deeper levels.

I've created deeply nested grid layout systems where parents widths are ems, and children are percents, and including up to four decimal points upstream had a noticeable impact.

Edge case, sure, but something to keep in mind.

natekoechley
  • 711
  • 4
  • 4
  • 3
    The accepted answer is more complete than this one, but the anecdote in this one gives me a better feel for how the technical implications will make themselves felt. Thanks for posting it. – Tom Aug 31 '17 at 17:58
29

Although fractional pixels may appear to round up on individual elements (as @SkillDrick demonstrates very well) it's important to know that the fractional pixels are actually respected in the actual box model.

This can best be seen when elements are stacked next to (or on top of) each other; in other words, if I were to place 400 0.5 pixel divs side by side, they would have the same width as a single 200 pixel div. If they all actually rounded up to 1px (as looking at individual elements would imply) we'd expect the 200px div to be half as long.

This can be seen in this runnable code snippet:

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
  • 7,219
  • 3
  • 35
  • 65
  • 12
    With regards to rendering: in you example, you have two divs competing for each pixel. In these cases, your browser will pick one of them to render the whole pixel — to avoid blurring and other weird artefacts. If you set half the pixels to be blue, using `:nth-child(even)` or `:nth-child(odd)`, you notice that either the whole thing is orange or the whole thing is blue — not a mixture of blue and orange (which would be some vague purple hue). – Daan Wilmer Oct 08 '15 at 11:52
  • I actually did what @DaanWilmer suggested above, and got this interesting result [imgur](https://i.imgur.com/eloegkm.png), which was after adding this CSS: `div#small_divs div:nth-child(2n-1) {background-color: yellow}` – manroe Jun 04 '21 at 02:10
18

The width will be rounded to an integer number of pixels.

I don't know if every browser will round it the same way though. They all seem to have a different strategy when rounding sub-pixel percentages. If you're interested in the details of sub-pixel rounding in different browsers, there's an excellent article on ElastiCSS.

edit: I tested @Skilldrick's demo in some browsers for the sake of curiosity. When using fractional pixel values (not percentages, they work as suggested in the article I linked) IE9p7 and FF4b7 seem to round to the nearest pixel, while Opera 11b, Chrome 9.0.587.0 and Safari 5.0.3 truncate the decimal places. Not that I hoped that they had something in common after all...

Саша Черных
  • 2,561
  • 4
  • 25
  • 71
MartinodF
  • 8,157
  • 2
  • 32
  • 28
11

They seem to round up the values to the closest integer; but Iam seeing inconsistency in chrome,safari and firefox.

For e.g if 33.3% converts to 420.945px

chrome and firexfox show it as 421px. while safari shows its as 420px.

This seems like chrome and firefox follow the floor and ceil logic while safari doesn't. This page seems to discuss the same problem

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

agaase
  • 1,562
  • 1
  • 15
  • 24
9

Elements have to paint to an integer number of pixels, and as the other answers covered, percentages are indeed respected.

An important note is that pixels in this case means css pixels, not screen pixels, so a 200px container with a 50.7499% child will be rounded to 101px css pixels, which then get rendered onto 202px on a retina screen, and not 400 * .507499 ~= 203px.

Screen density is ignored in this calculation, and there is no way to paint* an element to specific retina subpixel sizes. You can't have elements' backgrounds or borders rendered at less than 1 css pixel size, even though the actual element's size could be less than 1 css pixel as Sandy Gifford showed.

[*] You can use some techniques like 0.5 offset box-shadow, etc, but the actual box model properties will paint to a full CSS pixel.

Olex Ponomarenko
  • 905
  • 7
  • 10