Re: Border Gap Issue and Proposed Fix

874 views
Skip to first unread message

Traian Captan

unread,
Jun 24, 2022, 2:52:04 PM6/24/22
to Philip Rogers, David Baron, Xianzhu Wang, PaintTeamPublic
Hi Paind Dev Team,

(Resending since inline images got removed from my first email.)

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>

image.png

Zooming in to see the pixels looks like: https://screenshot.googleplex.com/7FnicoNST8XFQtF.png
image.png

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: https://screenshot.googleplex.com/7ny4SB5rgzXPgkJ.png
image.png
Notice there is no gap between the border and the background.

For completeness, Safari renders without a gap like: https://screenshot.googleplex.com/8hRFBSvbCFsXRua.png
image.png

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)
At paint time the border width gets floored to 10px inside DrawSolidBorderRect
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>


image.png

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:
https://chromium-review.googlesource.com/c/chromium/src/+/3717365/
(Please note the baselines have not been updated yet, since we wanted to confirm that this is the right approach first.)

After this patch Chrome renders without a gap.
The first image looks like: https://screenshot.googleplex.com/5VtArZNcYouRdpN.png
image.png
And the second nested one like: https://screenshot.googleplex.com/3dyF4fLXEdpy3Ho.png
image.png

The Firefox approach and difference with Chrome is discussed in the following blog post: Border rounding in CSS.

This issue and the proposed fix was discussed in: Issue 1201762: [Task] Investigate border snapping before layout, which is currently blocking 8 other issues (9 if we include the one I am currently investigating).

This issue was also discussed on:
https://github.com/w3c/csswg-drafts/issues/2114

Please let me know what your thoughts are on this issue and the proposed fix.

Regards,
Traian


On Fri, Jun 24, 2022 at 3:44 AM Traian Captan <tca...@google.com> wrote:
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:
image.png
Zooming in to see the pixels looks like:
image.png

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:
image.png
Notice there is no gap between the border and the background.

For completeness, Safari renders without a gap like:
image.png
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)
At paint time the border width gets floored to 10px inside DrawSolidBorderRect
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:
image.png

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:
https://chromium-review.googlesource.com/c/chromium/src/+/3717365/
(Please note the baselines have not been updated yet, since we wanted to confirm that this is the right approach first.)

The Firefox approach and difference with Chrome is discussed in the following blog post: Border rounding in CSS.

This issue and the proposed fix was discussed in: Issue 1201762: [Task] Investigate border snapping before layout, which is currently blocking 8 other issues (9 if we include the one I am currently investigating).

This issue was also discussed on:
https://github.com/w3c/csswg-drafts/issues/2114

Please let me know what your thoughts are on this issue and the proposed fix.

Regards,
Traian

Philip Rogers

unread,
Jun 27, 2022, 10:46:20 AM6/27/22
to Traian Captan, David Baron, Xianzhu Wang, PaintTeamPublic
Thanks so much for working on this! This is one of our largest classes of bugs (e.g., 21 stars in crbug.com/1201762, and an additional 32 on blockedon bugs, plus 11 on crbug.com/1120347, and probably more).

I think this approach is a good one since it basically just matches gecko and webkit, and maybe we can finally spec it too.

Xianzhu Wang

unread,
Jun 27, 2022, 12:02:56 PM6/27/22
to Philip Rogers, Traian Captan, David Baron, PaintTeamPublic
On Mon, Jun 27, 2022 at 7:46 AM Philip Rogers <p...@google.com> wrote:
Thanks so much for working on this! This is one of our largest classes of bugs (e.g., 21 stars in crbug.com/1201762, and an additional 32 on blockedon bugs, plus 11 on crbug.com/1120347, and probably more).

I think this approach is a good one since it basically just matches gecko and webkit, and maybe we can finally spec it too.

This also basically matches the old blink behavior before we supported sub-pixel borders.

Do we need an Intent to ship?

Benjamin Philipp

unread,
Aug 24, 2023, 12:19:58 PM8/24/23
to paint-dev, Xianzhu Wang, Traian Captan, David Baron, PaintTeamPublic, Philip Rogers
I'm noticing a gap now between the border of an element and its own background. This also seems to be a rounding issue.
It is exacerbated by the presence of a scroll bar
(This is on Windows 10)

Traian Captan

unread,
Aug 24, 2023, 11:24:43 PM8/24/23
to Benjamin Philipp, paint-dev, Xianzhu Wang, David Baron, Philip Rogers
Hi Benjamin,

Thanks for reaching out about this!
The original issue discussed in this thread was fixed, so this might be something new.
Please open a bug about it at:
and attach your html repro file to it so that we can further investigate.

Regards,
Traian

Traian Captan

unread,
Aug 25, 2023, 3:08:01 AM8/25/23
to Benjamin Philipp, paint-dev
Thank you!


On Thu, Aug 24, 2023 at 11:14 PM Benjamin Philipp <blacker...@gmail.com> wrote:
Thank you!
For posterity: The bug report is filed here: https://bugs.chromium.org/p/chromium/issues/detail?id=1475879

Benjamin Philipp

unread,
Aug 25, 2023, 3:10:11 PM8/25/23
to paint-dev, Traian Captan
Thank you!
For posterity: The bug report is filed here: https://bugs.chromium.org/p/chromium/issues/detail?id=1475879

On Friday, August 25, 2023 at 5:24:43 AM UTC+2 Traian Captan wrote:
Reply all
Reply to author
Forward
0 new messages