diff --git a/Tests/LibWeb/Text/expected/element-get-bounding-client-rect-css-transform.txt b/Tests/LibWeb/Text/expected/element-get-bounding-client-rect-css-transform.txt
new file mode 100644
index 0000000000..10297861d2
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/element-get-bounding-client-rect-css-transform.txt
@@ -0,0 +1 @@
+ {"x":68,"y":118,"width":100,"height":100,"top":118,"right":168,"bottom":218,"left":68}
diff --git a/Tests/LibWeb/Text/input/element-get-bounding-client-rect-css-transform.html b/Tests/LibWeb/Text/input/element-get-bounding-client-rect-css-transform.html
new file mode 100644
index 0000000000..0774a2ada9
--- /dev/null
+++ b/Tests/LibWeb/Text/input/element-get-bounding-client-rect-css-transform.html
@@ -0,0 +1,30 @@
+
+
+
+
+
diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp
index 76945fc283..5cde4c6fe2 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Element.cpp
@@ -900,7 +900,7 @@ JS::NonnullGCPtr Element::get_client_rects() const
// 3. Return a DOMRectList object containing DOMRect objects in content order, one for each box fragment,
// describing its border area (including those with a height or width of zero) with the following constraints:
- // FIXME: - Apply the transforms that apply to the element and its ancestors.
+ // - Apply the transforms that apply to the element and its ancestors.
// FIXME: - If the element on which the method was invoked has a computed value for the display property of table
// or inline-table include both the table box and the caption box, if any, but not the anonymous container box.
// FIXME: - Replace each anonymous block box with its child box(es) and repeat this until no anonymous block boxes
@@ -908,16 +908,27 @@ JS::NonnullGCPtr Element::get_client_rects() const
const_cast(document()).update_layout();
VERIFY(document().navigable());
auto viewport_offset = document().navigable()->viewport_scroll_offset();
+
+ Gfx::AffineTransform transform;
+ for (auto const* containing_block = this->layout_node(); containing_block; containing_block = containing_block->containing_block()) {
+ Gfx::AffineTransform containing_block_transform;
+ if (containing_block->paintable() && containing_block->paintable()->is_paintable_box()) {
+ auto const& containing_block_paintable_box = static_cast(*containing_block->paintable());
+ containing_block_transform = Gfx::extract_2d_affine_transform(containing_block_paintable_box.transform());
+ }
+ transform = transform.multiply(containing_block_transform);
+ }
+
auto const* paintable = this->paintable();
if (auto const* paintable_box = this->paintable_box()) {
auto absolute_rect = paintable_box->absolute_border_box_rect();
absolute_rect.translate_by(-viewport_offset.x(), -viewport_offset.y());
- rects.append(Geometry::DOMRect::create(realm(), absolute_rect.to_type()));
+ rects.append(Geometry::DOMRect::create(realm(), transform.map(absolute_rect.to_type())));
} else if (paintable && is(*paintable)) {
auto const& inline_paintable = static_cast(*paintable);
auto absolute_rect = inline_paintable.bounding_rect();
absolute_rect.translate_by(-viewport_offset.x(), -viewport_offset.y());
- rects.append(Geometry::DOMRect::create(realm(), absolute_rect.to_type()));
+ rects.append(Geometry::DOMRect::create(realm(), transform.map(absolute_rect.to_type())));
} else if (paintable) {
dbgln("FIXME: Failed to get client rects for element ({})", debug_description());
}