An element with both border-radius and backdrop-filter: blur(...) applies the blur outside its rounded border
shape when rendered with the AnyRender Skia backend. The filtered output appears in the rectangular corner areas
bounded by the element's border-box bounding rectangle.
The backdrop filter may sample pixels outside the element so that blur has enough input, but its final composited
output should remain clipped to the element's rounded border box.
Minimal reproduction
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Rounded backdrop-filter clip reproduction</title>
<style>
html, body { height: 100%; margin: 0; }
body { display: grid; place-items: center; background: #111827; }
.backdrop {
position: relative;
width: 360px;
height: 220px;
background: conic-gradient(
#ef476f 25%, #ffd166 0 50%, #118ab2 0 75%, #06d6a0 0
) 0 0 / 32px 32px;
}
.glass {
position: absolute;
inset: 40px 60px;
box-sizing: border-box;
background: rgb(16 26 42 / 45%);
border: 4px solid white;
border-radius: 52px 12px;
backdrop-filter: blur(12px);
}
</style>
</head>
<body>
<div class="backdrop"><div class="glass"></div></div>
</body>
</html>
Steps to reproduce
- Render the HTML above with Blitz using the AnyRender Skia backend.
- Inspect the checkerboard immediately outside the rounded corners of the white glass panel.
- Compare the result with a browser rendering of the same HTML.
Actual result
The checkerboard is blurred in the rectangular corner areas outside the panel's rounded border. The visible filter
output follows the axis-aligned border-box bounds instead of the rounded border shape.
Expected result
Only pixels inside the rounded white border are composited with the blurred backdrop. Pixels outside the rounded
corners remain sharp and unchanged. No overflow: hidden should be required on the filtered element or its parent.
Possible implementation location
Based on reading the current code, the likely location of the problem appears to be
BlitzDomPainter::render_element in packages/blitz-paint/src/render.rs. That function derives the effect-layer
clip with:
let mut effect_layer_clip = cx.frame.border_box_path().bounding_box();
One possible cause is that bounding_box() may discard the rounded geometry before the clip is passed through
PaintScene::push_layer. The Skia backend appears to clip the saved layer using the shape it receives, but the shape
may already be a plain rectangle at that point.
A potential fix may belong in packages/blitz-paint/src/render.rs, specifically
BlitzDomPainter::render_element. Backdrop sampling expansion and backdrop output clipping may need to remain
separate concepts: the exact rounded border path could be retained for backdrop-filter output while the blur operation
is still allowed to read the required pixels outside that path. If regular filter and backdrop-filter are
present together, separate nested effect layers may be required.
This explanation is a hypothesis from code inspection and has not yet been confirmed by implementing and validating a
fix.
An element with both
border-radiusandbackdrop-filter: blur(...)applies the blur outside its rounded bordershape when rendered with the AnyRender Skia backend. The filtered output appears in the rectangular corner areas
bounded by the element's border-box bounding rectangle.
The backdrop filter may sample pixels outside the element so that blur has enough input, but its final composited
output should remain clipped to the element's rounded border box.
Minimal reproduction
Steps to reproduce
Actual result
The checkerboard is blurred in the rectangular corner areas outside the panel's rounded border. The visible filter
output follows the axis-aligned border-box bounds instead of the rounded border shape.
Expected result
Only pixels inside the rounded white border are composited with the blurred backdrop. Pixels outside the rounded
corners remain sharp and unchanged. No
overflow: hiddenshould be required on the filtered element or its parent.Possible implementation location
Based on reading the current code, the likely location of the problem appears to be
BlitzDomPainter::render_elementinpackages/blitz-paint/src/render.rs. That function derives the effect-layerclip with:
One possible cause is that
bounding_box()may discard the rounded geometry before the clip is passed throughPaintScene::push_layer. The Skia backend appears to clip the saved layer using the shape it receives, but the shapemay already be a plain rectangle at that point.
A potential fix may belong in
packages/blitz-paint/src/render.rs, specificallyBlitzDomPainter::render_element. Backdrop sampling expansion and backdrop output clipping may need to remainseparate concepts: the exact rounded border path could be retained for backdrop-filter output while the blur operation
is still allowed to read the required pixels outside that path. If regular
filterandbackdrop-filterarepresent together, separate nested effect layers may be required.
This explanation is a hypothesis from code inspection and has not yet been confirmed by implementing and validating a
fix.