mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 05:37:34 +00:00
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
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();
|
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()
|
void Document::update_layout()
|
||||||
{
|
{
|
||||||
// NOTE: If our parent document needs a relayout, we must do that *first*.
|
// 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));
|
m_layout_root = verify_cast<Layout::Viewport>(*tree_builder.build(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
propagate_overflow_to_viewport(*document_element(), *m_layout_root);
|
||||||
|
|
||||||
Layout::LayoutState layout_state;
|
Layout::LayoutState layout_state;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue