Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider that images scale to specified dimensions, rather than overflowing. #1485

Merged
merged 5 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/strong-islands-relax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@siteimprove/alfa-style": patch
---

**Fixed:** `<img>` elements are now considered as respecting their specified dimensions

`<img>` elements whose `width` or `height` is specified are now considered to respect it when computing their concrete dimensions (i.e., they rescale rather than overflow, independantly from the `overflow` property).

This is especially meaningful for tracking pixels with specified dimensions of 0 that are now correcly considered as invisible.
25 changes: 24 additions & 1 deletion packages/alfa-style/src/node/predicate/is-clipped.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ function isClippedBySize(
const y = style.computed("overflow-y").value.value;
const width = style.computed("width").value;
const height = style.computed("height").value;
const overflows = test(canOverflow(device), element);

// Does the element always show a scrollbar, no matter whether there is
// enough room in it to show the content?
Expand All @@ -115,7 +116,7 @@ function isClippedBySize(
["height", y, height],
] as const) {
// Is the element reduced to nothingness in this axis?
if (overflow === "visible") {
if (overflow === "visible" && overflows) {
// The content overflows in this axis, go to next axis.
continue;
}
Expand Down Expand Up @@ -296,3 +297,25 @@ function isClipping(elementBox: Rectangle, device: Device): Predicate<Element> {
)(ancestor);
};
}

/**
* Check if an element scales to its specified dimensions
*
* @remarks
* Replaced elements are not rendered by CSS directly. Instead, they have
* natural dimension (e.g., an image size) and specified ones (e.g., the width
* CSS property). Negotiation between the two computes a concrete size with which
* the element is effectively render. In practice, the concrete size is often
* the specified one, and while the rendering may result in smaller or larger
* object, it is also often fitting quite well.
* {@link https://drafts.csswg.org/css-images/#sizing}
*
* @privateRemarks
* For now, we mostly use this to discard the check on overflow for <img>.
* <img> seem to be always rendered at their specified size, if any. This is
* especially important here for tracking pixels whose specified size is 0
* and we need to treat them as invisible.
*/
function canOverflow(device: Device): Predicate<Element> {
return not(Element.hasName("img"));
}
14 changes: 14 additions & 0 deletions packages/alfa-style/test/node/predicate/is-visible.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,17 @@ test(`isVisible() returns true for text with the same color as their background

t.equal(isVisible(text), true);
});

test(`isVisible() consider that images' concrete dimensions are the specified ones`, (t) => {
const img = (
<img src="foo.jpg" style={{ width: "0px", overflow: "visible" }} />
);
const div = (
<div style={{ width: "0px", overflow: "visible" }}>Hello World</div>
);

h.document([img, div]);

t.equal(isVisible(img), false);
t.equal(isVisible(div), true);
});