Hi Paind Dev Team,
Following up from our discussion in the Paint Weekly Team Meeting,
I've been investigating
The described issue is a visible 1px gap between a parent element's border and a child's background.
A very simple html Proof Of Concept looks like:
<!DOCTYPE html>
<html>
<head>
<title>Border Background Gap</title>
<style>
body {
border: 10.75px solid #FF000080;
width: fit-content;
height: fit-content;
}
.child {
background: #0000FF80;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div class="child"></div>
</body>
</html>
In Chrome this renders like:
Zooming in to see the pixels looks like:
Notice the 1px gap between the border and the background.
The body size gets calculated as 121.5px X 121.5px.
In Firefox on the same device the body size gets calculated as 120px X 120px
and the rendered image looks like:
Notice there is no gap between the border and the background.
For completeness, Safari renders without a gap like:
This behaviour is a regression introduced in:
which changed Chrome to "Use floor instead of round for decimal border widths".
The intent of that change was to increase interop with Firefox and Safari which both floor borders.
The 1 pixel gap issue we are currently seeing is because the sub pixel borders get floored at paint time in Chrome.
From the example above, the body size gets calculated as 121.5px (left border of 10.75px + child size of 100px + right border of 10.75px).
The body position is (8, 8).
The child position gets calculated as (19, 19). (8 + 10.75 border = 18.75 and rounded to 19)
The body's border gets drawn from pixel 8 to pixel 17.
The child background draws from pixel 19.
This leaves pixel 18 as white which is why we see the gap.
As an initial solution to this I looked at adjusting the parent's rectangle when we round the border by
insetting it 1px,
however this didn't seem like the right approach as it didn't quite work when having several nested elements like:
<!DOCTYPE html>
<html>
<head>
<title>Border Background Gap Stack</title>
<style>
div {
width: fit-content;
height: fit-content;
}
.outer {
border: 13.75px solid #00000080;
}
.middle {
border: 13.75px solid #FF000080;
}
.inner {
border: 13.75px solid #00FF0080;
}
.center {
background: #0000FF80;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<div class="outer">
<div class="middle">
<div class="inner">
<div class="center"></div>
</div>
</div>
</div>
</body>
</html>
Rendering like:
To fix this Chrome could do the border width snapping before layout, similar to Firefox and Safari.
I created the following CL with this proposed change:
The Firefox approach and difference with Chrome is discussed in the following blog post:
Border rounding in CSS.
Please let me know what your thoughts are on this issue and the proposed fix.
Regards,
Traian