LibWeb: Propagate overflow modes from <html> or <body> to viewport
This patch implements "Overflow Viewport Propagation" from CSS-OVERFLOW. It fixes an issue where many websites were not scrollable because they had `overflow: scroll` on the body element and we didn't propagate it.
This commit is contained in:
parent
09eed8eea2
commit
4011a107a4
Notes:
sideshowbarker
2024-07-17 02:08:15 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/4011a107a4 Pull-request: https://github.com/SerenityOS/serenity/pull/20343
5 changed files with 76 additions and 0 deletions
|
@ -0,0 +1,10 @@
|
|||
Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 800x2016 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 784x2000 children: not-inline
|
||||
BlockContainer <div> at (8,8) content-size 100x2000 children: inline
|
||||
TextNode <#text>
|
||||
|
||||
PaintableWithLines (Viewport<#document>) [0,0 800x600] overflow: [0,0 800x2016]
|
||||
PaintableWithLines (BlockContainer<HTML>) [0,0 800x2016]
|
||||
PaintableWithLines (BlockContainer<BODY>) [8,8 784x2000]
|
||||
PaintableWithLines (BlockContainer<DIV>) [8,8 100x2000]
|
|
@ -0,0 +1,10 @@
|
|||
Viewport <#document> at (0,0) content-size 800x600 [BFC] children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 800x616 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 784x600 children: not-inline
|
||||
BlockContainer <div.long> at (8,8) content-size 784x2000 children: inline
|
||||
TextNode <#text>
|
||||
|
||||
PaintableWithLines (Viewport<#document>) [0,0 800x600] overflow: [0,0 800x2008]
|
||||
PaintableWithLines (BlockContainer<HTML>) [0,0 800x616] overflow: [0,0 800x2008]
|
||||
PaintableWithLines (BlockContainer<BODY>) [8,8 784x600] overflow: [8,8 784x2000]
|
||||
PaintableWithLines (BlockContainer<DIV>.long) [8,8 784x2000]
|
|
@ -0,0 +1,12 @@
|
|||
<!doctype html><style>
|
||||
html {
|
||||
overflow: visible;
|
||||
}
|
||||
body {
|
||||
overflow: scroll;
|
||||
}
|
||||
div {
|
||||
width: 100px;
|
||||
height: 2000px;
|
||||
}
|
||||
</style><body><div>
|
|
@ -0,0 +1,10 @@
|
|||
<!doctype html><style>
|
||||
body {
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
}
|
||||
.long {
|
||||
height: 2000px;
|
||||
background: orange;
|
||||
}
|
||||
</style><body><div class="long">
|
|
@ -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<CSS::MutableComputedValues&>(static_cast<CSS::MutableComputedValues const&>(static_cast<CSS::ComputedValues const&>(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<CSS::MutableComputedValues&>(static_cast<CSS::MutableComputedValues const&>(static_cast<CSS::ComputedValues const&>(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<HTML::HTMLBodyElement>();
|
||||
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<CSS::MutableComputedValues&>(static_cast<CSS::MutableComputedValues const&>(static_cast<CSS::ComputedValues const&>(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<Layout::Viewport>(*tree_builder.build(*this));
|
||||
}
|
||||
|
||||
propagate_overflow_to_viewport(*document_element(), *m_layout_root);
|
||||
|
||||
Layout::LayoutState layout_state;
|
||||
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue