I have an animated SVG in which the origin is the center. There is 256x256 path that is centered around the origin. This path has a fill which is a pattern that is a gradient rect also of 256x256. The path is animated to expand to the full width and height of the viewbox. Ideally, I would like the path's fill to stay centered around the origin, however, it stays in the top left of path, therefore moving with the animation.
I've tried animating the fill (x
, y
and transform
properties) to fake the fill staying centered however this has cros-browser issues. I tried animating all the properties in both CSS and plain SVG and each way tends to work on one browser not the other. For example, the animateTransform
spline easings don't work on Chrome, but they do on FireFox. Alternatively, the CSS cubic-bezier animation easings do work on Chrome but don't on FireFox.
Here is the current SVG:
<svg
width="1024"
height="1024"
viewBox="-512 -512 1024 1024"
fill="none"
overflow="hidden"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMinYMin meet"
>
<style>
#cube {
transform-box: fill-box;
transform: translate(-50%, -50%);
z-index: 1;
}
#origin,
#origin_label {
fill: red;
stroke: darkred;
stroke-width: 0;
font-family: sans-serif;
font-size: 30px;
}
</style>
<circle id="origin" cx="0" cy="0" r="10" />
<text id="origin_label" x="15" y="30">(0, 0)</text>
<use href="#cube" stroke-width="2">
<animate
attributeName="stroke"
dur="6s"
repeatCount="indefinite"
values="#FF9AA2;#FFB7B2;#FFDAC1;#E2F0CB;#B5EAD7;#C7CEEA;#FF9AA2"
/>
</use>
<defs>
<!-- EVERYTHING TOGETHER -->
<g id="cube">
<use
href="#cube_outline"
stroke-linejoin="round"
stroke-width="16"
fill="url(#sky_bg)"
/>
</g>
<!-- GRADIENT FILL -->
<pattern
id="sky_bg"
x="0%"
y="0%"
width="100%"
height="100%"
patternUnits="userSpaceOnUse"
patternContentUnits="userSpaceOnUse"
>
<rect
width="256"
height="256"
x="0"
y="0"
fill="url(#sky)"
id="starpat"
></rect>
</pattern>
<!-- THICK OUTER LINE-->
<g id="cube_outline">
<path>
<animate
attributeName="d"
dur="3s"
calcMode="spline"
keyTimes="0;0.5;1"
repeatCount="1"
fill="freeze"
keySplines="0.4 0 0.2 1;0.4 0 0.2 1"
values="M 0 64 L 118 0 L 236 64 L 236 192 L 118 256 L 0 192 Z;
M 0 0 L 236 0 L 236 0 L 236 256 L 0 256 L 0 256 Z;
M 0 0 L 1010 0 L 1010 0 L 1010 1010 L 0 1010 L 0 1010 Z"
/>
</path>
</g>
<linearGradient id="sky" gradientTransform="rotate(90)">
<stop offset="0.5" stop-color="#141417" />
<stop offset="1" stop-color="#40354a" />
</linearGradient>
</defs>
</svg>
I am limited to only CSS, HTML and SVG as any javascript will be sanitised away. Is it possible to keep the fill centered? Or is there another approach I should take?
Since you are grouping svg shapes together the width and height of <g> tag changes when the cube_outline starts to expand. In order to avoid that i just used a second <use> tag and removed the to avoid grouping and changed the rect to a path to mimic the same animation that outline does before its expansion. Hope this solves your problem.
<svg
width="1024"
height="1024"
viewBox="-512 -512 1024 1024"
fill="none"
overflow="hidden"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMinYMin meet"
>
<style>
#cube_outline,#starpat {
transform-box: fill-box;
transform: translate(-50%, -50%);
z-index: 1;
}
#origin,
#origin_label {
fill: red;
stroke: darkred;
stroke-width: 0;
font-family: sans-serif;
font-size: 30px;
}
</style>
<circle id="origin" cx="0" cy="0" r="10" />
<text id="origin_label" x="15" y="30">(0, 0)</text>
<use
href="#cube_outline"
stroke-linejoin="round"
stroke-width="16"
/>
<use
href="#starpat"
/>
<defs>
<!-- EVERYTHING TOGETHER -->
<!-- GRADIENT FILL -->
<path
width="256"
height="256"
x="0"
y="0"
fill="url(#sky)"
id="starpat"
>
<animate
attributeName="d"
dur="1.5s"
calcMode="spline"
keyTimes="0;1"
repeatCount="1"
fill="freeze"
keySplines="0.4 0 0.2 1"
values="M 0 64 L 113 0 L 226 64 L 226 187 L 113 246 L 0 182 Z;
M 0 0 L 226 0 L 226 0 L 226 246 L 0 246 L 0 246 Z;"
/>
</path>
<!-- THICK OUTER LINE-->
<g id="cube_outline">
<path>
<animate
attributeName="d"
dur="3s"
calcMode="spline"
keyTimes="0;0.5;1"
repeatCount="1"
fill="freeze"
keySplines="0.4 0 0.2 1;0.4 0 0.2 1"
values="M 0 64 L 118 0 L 236 64 L 236 192 L 118 256 L 0 192 Z;
M 0 0 L 236 0 L 236 0 L 236 256 L 0 256 L 0 256 Z;
M 0 0 L 1010 0 L 1010 0 L 1010 1010 L 0 1010 L 0 1010 Z"
/>
<animate
attributeName="stroke"
dur="6s"
repeatCount="indefinite"
values="#FF9AA2;#FFB7B2;#FFDAC1;#E2F0CB;#B5EAD7;#C7CEEA;#FF9AA2"
/>
</path>
</g>
<linearGradient id="sky" gradientTransform="rotate(90)">
<stop offset="0.5" stop-color="#141417" />
<stop offset="1" stop-color="#40354a" />
</linearGradient>
</defs>
</svg>