.long) [8,8 784x2000]
diff --git a/Tests/LibWeb/Layout/input/viewport-overflow-propagation-1.html b/Tests/LibWeb/Layout/input/viewport-overflow-propagation-1.html
new file mode 100644
index 0000000000..1687d10874
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/viewport-overflow-propagation-1.html
@@ -0,0 +1,12 @@
+
diff --git a/Tests/LibWeb/Layout/input/viewport-overflow-propagation-2.html b/Tests/LibWeb/Layout/input/viewport-overflow-propagation-2.html
new file mode 100644
index 0000000000..431333e119
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/viewport-overflow-propagation-2.html
@@ -0,0 +1,10 @@
+
diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp
index 1a4df62a65..a6cef56816 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Document.cpp
@@ -917,6 +917,38 @@ void Document::invalidate_layout()
schedule_layout_update();
}
+static void propagate_overflow_to_viewport(Element& root_element, Layout::Viewport& viewport)
+{
+ // https://drafts.csswg.org/css-overflow-3/#overflow-propagation
+ // UAs must apply the overflow-* values set on the root element to the viewport
+ // when the root element’s display value is not none.
+ auto* overflow_origin_node = root_element.layout_node();
+ auto& viewport_computed_values = const_cast(static_cast(static_cast(viewport.computed_values())));
+
+ // However, when the root element is an [HTML] html element (including XML syntax for HTML)
+ // whose overflow value is visible (in both axes), and that element has as a child
+ // a body element whose display value is also not none,
+ // user agents must instead apply the overflow-* values of the first such child element to the viewport.
+ if (root_element.is_html_html_element()) {
+ auto* root_element_layout_node = root_element.layout_node();
+ auto& root_element_computed_values = const_cast(static_cast(static_cast(root_element_layout_node->computed_values())));
+ if (root_element_computed_values.overflow_x() == CSS::Overflow::Visible && root_element_computed_values.overflow_y() == CSS::Overflow::Visible) {
+ auto* body_element = root_element.first_child_of_type();
+ if (body_element && body_element->layout_node())
+ overflow_origin_node = body_element->layout_node();
+ }
+ }
+
+ // NOTE: This is where we assign the chosen overflow values to the viewport.
+ auto& overflow_origin_computed_values = const_cast(static_cast(static_cast(overflow_origin_node->computed_values())));
+ viewport_computed_values.set_overflow_x(overflow_origin_computed_values.overflow_x());
+ viewport_computed_values.set_overflow_y(overflow_origin_computed_values.overflow_y());
+
+ // The element from which the value is propagated must then have a used overflow value of visible.
+ overflow_origin_computed_values.set_overflow_x(CSS::Overflow::Visible);
+ overflow_origin_computed_values.set_overflow_y(CSS::Overflow::Visible);
+}
+
void Document::update_layout()
{
// NOTE: If our parent document needs a relayout, we must do that *first*.
@@ -943,6 +975,8 @@ void Document::update_layout()
m_layout_root = verify_cast(*tree_builder.build(*this));
}
+ propagate_overflow_to_viewport(*document_element(), *m_layout_root);
+
Layout::LayoutState layout_state;
{