Context:
I’m trying to reveal an element on page scroll using the shape of a “blob” with a CSS
animation-timeline
animation, so at this moment, this code must be tested on a recent Edge
or Chrome
browser.
The element (a <div>
) has a clip-path: url(#blob)
where #blob
is the id of a <clipPath>
element contained in a SVG
: this element has clipPathUnits="objectBoundingBox"
and the coordinates of the <path>
create a shape of a blob.
The <clipPath>
is initially scaled to 0
and the animation linked to the animation-timeline makes it scale to 2.5
.
Problem:
The issue is in the transform-origin
of the <clipPath>
element.
On a retina display the origin of the scale transformation is wrong, while on non-retina display is correct1.
Here is the minimal code to reproduce the issue (but I also made a demo on Codepen)
body {
margin: 0;
view-timeline: --body;
min-block-size: 300vh;
}
div {
position: sticky;
top: 0;
display: grid;
place-content: center;
block-size: 100vh;
background: linear-gradient(#83a3ac, #df9784);
clip-path: url("#blob");
h1 {
font: 7rem "system-ui";
color: #fff;
}
}
svg {
block-size: 0;
inline-size: 0;
clipPath {
transform-origin: 50vw 50vh;
transform: scale(0);
animation: linear clippath 1 forwards;
animation-timeline: --body;
animation-range: exit-crossing 25vh exit-crossing 275vh;
}
}
@keyframes clippath { to { transform: scale(2.5) }}
<body>
<div>
<h1>Hello, World</h1>
</div>
<svg viewBox="0 0 1 1" xmlns="http://www.w3.org/2000/svg"
aria-hidden="true" focusable="false">
<clipPath id="blob" clipPathUnits="objectBoundingBox">
<path d="M0.8338,0.1121c0.0818,0.0416,0.1468,
0.1134,0.1623,0.1922c0.0158,0.0788-0.0178,
0.1642-0.0397,0.2459c-0.0216,0.0819-0.0316,
0.1598-0.0652,0.2489c-0.0338,0.089-0.0909,
0.1882-0.1696,0.1995c-0.0789,0.0115-0.1794
-0.065-0.2937-0.096c-0.1147-0.0312-0.2437
-0.0172-0.3109-0.065c-0.0674-0.0478-0.0726
-0.1574-0.0887-0.2649c-0.0158-0.1076-0.0412
-0.2135-0.0201-0.3188c0.0208-0.1054,0.0886
-0.2096,0.1875-0.2447c0.0986-0.0351,0.2551
-0.0011,0.3824,0.0221C0.6536,0.0593,0.7519,
0.0703,0.8338,0.1121z"/>
</clipPath>
</svg>
</body>
What I actually see?
(click to see the animated gif)
What I tried?
I found a workaround with a mediaquery
for retina displays
clipPath {
transform-origin: 50vw 50vh;
@media (-webkit-min-device-pixel-ratio: 2) {
transform-origin: 100vw 100vh;
}
...
}
but I’m not sure this could be a consistent approach. What am I doing wrong?
Footnotes/edits
1: tested with a Macbook Air 13″ (2024) and iMac 27″ (2017) and various non-retina displays
5