How Do Browsers Deal with Non-Integer Values for Height and Width

How do browsers deal with non-integer values for height and width?

Assertion

Browsers are designed to deal with floating point numbers and values less than one pixel.


To see a simple example showing that browsers use floating point numbers in their calculations, create a 3% width item and look at its calculated properties in Chrome developer tools as it is resized.

You should see something like this:

Sample Image

"35.296875" can't be precisely rendered by a display that maps one pixel to one pixel in the physical display (CRT, traditional LCD). However, newer high density displays use a different ratio than 1-1 and this fractional value could conceptually be used to provide a greater degree of precision.

Even on low density displays, a fractional value could provide a hint for subpixel rendering, which uses the red, green and blue components of the pixel to make the edges of an object appear smoother than possible with whole pixel values.

But exactly what the browser will do with such numbers isn't very predictable. You can't (currently) ask a browser to make a box 31.5px wide and expect a consistent or even meaningful result. Some browsers will truncate fractional values; others round up/down.

Subpixel rendering is commonly used for text and works quite well in most/all browsers, but each browser implements this differently and there is very little a developer can do to impact how this works.

When

At what stage do non-integer values get rounded in the inheritance
chain?

Most/all calculations are performed as floating point numbers and any rounding may occur late in the process, or even outside of the browser's control. For example, a browser may delegate its anti-aliasing to an OS component (such as IE9 does to Windows Direct2D and DirectWrite).

CSS transitions may be tightly integrated with OS and/or hardware acceleration. This is another case in which I think it is highly likely the floating point values are preserved by the browser and passed to the underlying layer(s).

Rounding Behavior/Errors

When a container's children have non-integer dimensions, will there
ever be instances where the sum of the child lengths or heights not
equal the inner width / height of the parent element?

I've seen this in older browsers (IE7) as a result of percentage calculations, where 50% + 50% > 100%. Usually it is not a problem until you try to do something more complicated. Anecdotally, I have seen "off by one pixel" bugs when attempting to precisely align HTML elements as part of an animation.

Percentages vs. other Units

Do provided non-integer dimensions get handled differently to
non-integer results of percentage-based dimensions?

Do they round to the nearest integer, or truncate them?

It varies. This older answer states that they are truncated, but (in Chrome 24) I see rounding (note the example fiddle). Note my earlier comment about the differences between Chrome and Safari on the same machine.

What about non-whole values for padding and margins?

The same rules (or lack thereof) appear to apply.

Standards

I haven't found a standard definition for how floating point values should be handled in all cases. The closest relevant spec I can find talks about canvas pixels:

The handling of pixel rounding when the specified coordinates do not
exactly map to the device coordinate space is not defined by this
specification, except that the following must result in no visible
changes to the rendering: [...list of conditions...]

Again, this is from a section dealing specifically with canvas, but it does insinuate:

  • Browsers absolutely interact with fractional pixels.
  • Actual implementations will vary.
  • Some standardization does exist.
  • Mapping to the device's display may factor into the calculation.

DOM element width can be non-integer?

There's a difference between the CSS style rule (which getComputedStyle() or Renzo Kooi's getStyle() will give you) and the actual computed width in pixels as determined by the user agent.

This is partly due to the fact that partial pixel values are possible in CSS, but the user agent must choose how to render partial pixels (currently, I believe they all round up or down, but are very inconsistent, particularly when translating percents to pixels [see here]).

It is important for these differences to exist, particularly as user agents implement full page zooming.

For instance, I made a test case with this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Fractional pixels</title>
<style type="text/css" media="screen">
#fractional {
width: 17.5px;
height: 16.1333px;
background: red;
}
</style>
</head>
<body>
<div id="fractional"></div>
</body>
</html>

Zoomed in one step in Safari 4 Beta, the CSS width is reported as 17.5px and the height 16.1333px. But its offsetWidth is 21 device pixels, and its offsetHeight is 19 device pixels.

The moral of the story, in short, is that if you want to match an element's actual dimensions, it's best to use its CSS values as is, even if they are non-integer.

Browsers truncate border values to integers

The simple explanation is that the browser uses integers for border widths internally (or at least exposes them publicly as such).

An example of this is the source code of Chrome (Chromium) which in the file ComputedStyle.h defines all border-widths as integers (line 508):

source code snapshot

There is little we can do with that and as to why: there is very little information about border widths in the W3C specification for CSS Backgrounds and Borders. It only states line-width with no units, type or definition about how to treat this unit except it is absolute (non-negative):

Value: <line-width>

[...]

Computed value: absolute length; ‘0’ if the border style is ‘none’ or ‘hidden’

And:

The lengths corresponding to ‘thin’, ‘medium’ and ‘thick’ are not
specified, but the values are constant throughout a document and thin
≤ medium ≤ thick. A UA could, e.g., make the thickness depend on the
‘medium’ font size: one choice might be 1, 3 & 5px when the ‘medium’
font size is 17px or less. Negative values are not allowed.

The same information is found in the box model document with no new details.

As all values eventually end up as pixel values (as our screens are pixel-devices) the number coming through em, vw, % etc. seems to end up as an integer when it comes to border widths without considering sub-pixeling.

Not even transforms (scale) seem to affect this in the browsers which use integers for border widths.

In the end, it seems to be up to the browser vendor how to treat these values (it could simply be aesthetic reasons for doing so, performance, .. we can only guess..).

What is the reason for the discrepancy between the height and width values I set and the ones returned?

The reason about that discrepancy is that browsers differ on zooming functions. So as tyler durden said here:

"The reason why some browsers don't zoom properly has nothing to do with sub-pixel support, it is because they are not remembering the exact position and rounding correctly. In other words, they are prematurely rounding the position and that causes the image to be mis-aligned."

In fact, for the example you are referring too, on my browsers, safari as always zooms only text!

IE, Chrome, Opera and Firefox are resizing by calculating not only the text, but also, all the elements you are using on your page (border, width,padding etc). In addition, Border AFFECTS the outside edge of your element so lets see if its rounded properly:

<!DOCTYPE html><html>    <head>        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>            <script>        $(window).ready(function () {            $("button").click(function () {                var txt = "";                txt += "Width of div1: " + $(window).width() + "</br>";                txt += "Width of div1: " + $("#div1").width() + "</br>";                txt += "Inner left border width of div1: " + $("#div1").css("border-left-width") + "</br>";
txt += "Height of div1: " + $("#div1").height(); $("#div1").html(txt); fixSubpixelLayout($('#all-cats'), $('#all-cats .cat')); }); });
</script> <style> #div1 { height: 100px; width: 300px; padding: 10px; margin: 3px; border: 1px solid blue; background-color: lightblue; } </style> </head> <body>
<div id="div1"></div> <br>
<button>Display dimensions of div</button>
<p>width() - returns the width of an element.</p> <p>height() - returns the height of an element.</p>
</body></html>

How should User Agents deal with non-integer values for tabindex and z-index?

As noted in David's answer, the current HTML/CSS specifications clearly require an integral value for these properties. Decimal values are not meant to be supported.

should the two values above be treated as the same or different?

In terms of should, I would have thought they would be treated as different values, and basically parsed as floating-point numbers. However a quick jsFiddle test shows otherwise, in Chrome at least.

<input type="text" placeholder="start here" tabindex="1" />
<input type="text" placeholder="tab 3" tabindex="1.3" />
<input type="text" placeholder="tab 2" tabindex="1.2" />
<input type="text" placeholder="tab 1" tabindex="1.1" />
<hr />
<input type="text" placeholder="start here" tabindex="10" />
<input type="text" placeholder="tab 3" tabindex="13" />
<input type="text" placeholder="tab 2" tabindex="12" />
<input type="text" placeholder="tab 1" tabindex="11" />

http://jsfiddle.net/NWKt4/2/

Why would you use those values in favour of tabindex="11",
tabindex="12", etc.?

Based upon the results above, I'd suggest that you wouldn't/shouldn't use decimal values in favor of integral ones, since they don't appear to work as one might expect.

My question is should user agents honour the decimal point and the
digits after it or just use the integer part?

That seems somewhat subjective. So my subjective answer is that yes, of course they should.

In practice, however, it does not appear that mainstream browsers (Firefox does the same thing as Chrome, as does IE) honor the fractional component of the tabindex value. And the HTML/CSS spec says that this should be an integral value.

Edit: and the same applies to z-index as well: http://jsfiddle.net/NWKt4/3/

Are decimal pixels in css supported in multiple browsers?

Using decimal pixels is incorrect. Pixel should be a single dot on the screen. Therefore, size can only be complete with no floating numbers.
The decimal value will be used only when you will increase the zoom level and will be increased proportionaly to it.

Example: http://jsfiddle.net/x2bdrdy6/
in the example above you can see that the 50.5px is rounded upp and equals to the 51px.

#body1{
height: 50px;
width:100px;
background: red;
}

#body2{
height: 50px;
width:100.5px;
background: green;
}

#body3{
height: 50px;
width:101px;
background: blue;
}

offsetWidth not same in different Browsers

The width of the inner element is a non integer. FF and Chrome are rounding the number differently. You can get the exact width by using inner.getBoundingClientRect().width (which is 101.5)

This is because the parent element is 203px. Not 202 or 204.

Strange edges in the input fields and heights with non-integer value

Add outline: none; to the input element;

Codepen: https://codepen.io/manaskhandelwal1/pen/WNGgQwP



Related Topics



Leave a reply



Submit