Merge pull request #3146 from lightpanda-io/style-width-children-aware

render: CSS width/height are now children-content aware
This commit is contained in:
Karl Seguin authored and GitHub committed 2026-08-07 07:15:23 +08:00
commit df084b2cab
3 files changed
+53 -11

No files matched your search

+32
View File
@@ -168,6 +168,38 @@
}
</script>
<script id="computedWidthMarqueeLoop">
{
// The getComputedStyle variant of the marquee idiom (inchurch.com.br's
// dynamic-marquee-widget via jQuery .width()): the computed value must
// carry the same content fallback as clientWidth or the loop never
// terminates.
const container = document.createElement('div');
const wrap = document.createElement('div');
const item = document.createElement('span');
wrap.appendChild(item);
container.appendChild(wrap);
document.body.appendChild(container);
const width = (el) => parseFloat(getComputedStyle(el).width);
const containerWidth = width(container);
let guard = 0;
while (width(wrap) < containerWidth * 2 && guard < 50) {
wrap.appendChild(item.cloneNode(true));
guard++;
}
testing.expectTrue(guard < 50);
// An explicit inline size still wins over the content sum.
const pinned = document.createElement('div');
pinned.style.width = '40px';
pinned.appendChild(document.createElement('span'));
pinned.appendChild(document.createElement('span'));
document.body.appendChild(pinned);
testing.expectEqual('40px', getComputedStyle(pinned).width);
}
</script>
<script id="scrollHeightFromContent">
{
// An empty element has no content to overflow its box.
+12 -4
View File
@@ -1364,7 +1364,11 @@ pub fn getElementDimensions(self: *Element, frame: *Frame) Dimensions {
// to contentWidth/contentHeight
pub fn getClientWidth(self: *Element, frame: *Frame) f64 {
var visibility_cache: VisibilityCache = .{};
if (!self.checkVisibilityCached(&visibility_cache, frame)) {
return self.getClientWidthWithCache(frame, &visibility_cache);
}
pub fn getClientWidthWithCache(self: *Element, frame: *Frame, visibility_cache: *VisibilityCache) f64 {
if (!self.checkVisibilityCached(visibility_cache, frame)) {
return 0.0;
}
@@ -1375,12 +1379,16 @@ pub fn getClientWidth(self: *Element, frame: *Frame) f64 {
return dims.width;
}
return @max(dims.width, self.contentWidth(frame, &visibility_cache));
return @max(dims.width, self.contentWidth(frame, visibility_cache));
}
pub fn getClientHeight(self: *Element, frame: *Frame) f64 {
var visibility_cache: VisibilityCache = .{};
if (!self.checkVisibilityCached(&visibility_cache, frame)) {
return self.getClientHeightWithCache(frame, &visibility_cache);
}
pub fn getClientHeightWithCache(self: *Element, frame: *Frame, visibility_cache: *VisibilityCache) f64 {
if (!self.checkVisibilityCached(visibility_cache, frame)) {
return 0.0;
}
@@ -1391,7 +1399,7 @@ pub fn getClientHeight(self: *Element, frame: *Frame) f64 {
return dims.height;
}
return @max(dims.height, self.contentHeight(frame, &visibility_cache));
return @max(dims.height, self.contentHeight(frame, visibility_cache));
}
pub fn getBoundingClientRect(self: *Element, frame: *Frame) !*DOMRect {
@@ -97,9 +97,11 @@ pub fn getPropertyValue(self: *const CSSStyleDeclaration, property_name: []const
}
// Computed width/height must agree with the synthetic layout
// metrics (offsetWidth/getBoundingClientRect). Returning ""
// makes measurement code see contradictory sizes — jQuery's
// "shrink text until it fits" loops then never terminate.
// metrics. Returning "" makes measurement code see
// contradictory sizes — jQuery's "shrink text until it fits"
// loops then never terminate. jQuery's .width() reads this
// value, so it must also carry clientWidth's content fallback
// or append-until-wide marquee loops never terminate.
if (wrapped.eql(comptime .wrap("width"))) {
return resolvedDimension(element, .width, frame);
}
@@ -115,13 +117,13 @@ pub fn getPropertyValue(self: *const CSSStyleDeclaration, property_name: []const
}
fn resolvedDimension(element: *Element, dimension: enum { width, height }, frame: *Frame) []const u8 {
if (!element.checkVisibilityCached(null, frame)) {
var visibility_cache: Element.VisibilityCache = .{};
if (!element.checkVisibilityCached(&visibility_cache, frame)) {
return "auto";
}
const dims = element.getElementDimensions(frame);
const value = switch (dimension) {
.width => dims.width,
.height => dims.height,
.width => element.getClientWidthWithCache(frame, &visibility_cache),
.height => element.getClientHeightWithCache(frame, &visibility_cache),
};
return std.fmt.allocPrint(frame.local_arena, "{d}px", .{value}) catch "auto";
}