Issue
I am trying to translate part of a SVG graphic after the entire graphic has already been rotated. It consists of two triangle-shaped brackets that are first scaled in, and then rotated. After that's done, I simply want the right bracket to shift right on the x-axis while the left bracket stays in place.
Scaling and rotating the elements around their center was not a problem, however when I want to translate the right bracket on the x-axis, I am getting unexpected side-effects.
Here is a working snippet that illustrates the problem:
.brackets {
animation: scaling 1s, rotating 2s 1s;
transform-box: fill-box;
}
.bracket-left {
animation: rotate-left 1s 3s forwards;
transform-box: fill-box;
}
.bracket-right {
animation: sliding 1s 3s forwards;
transform-box: fill-box;
}
@keyframes scaling {
0% {
transform: scale(0);
}
25% {
transform: scale(1);
}
100% {
transform: scale(1);
}
}
@keyframes rotating {
0% {
transform-origin: center;
transform: rotate(0deg);
}
100% {
transform-origin: center;
transform: rotate(-405deg);
}
}
@keyframes sliding {
100% {
transform: translate(40px, 0px) rotate(-45deg);
}
}
@keyframes rotate-left {
0% {
transform-origin: center;
transform: rotate(-45deg);
}
100% {
transform-origin: center;
transform: rotate(-45deg);
}
}
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>CSS SVG</title>
<link rel="stylesheet" href="test.css" />
</head>
<body>
<svg
width="256"
height="256"
viewbox="0 0 100 100"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<linearGradient
xlink:href="#a"
id="e"
gradientUnits="userSpaceOnUse"
x1="-3.999"
y1=".503"
x2="-.497"
y2="4.005"
/>
<linearGradient id="a">
<stop
style="stop-color: #17ce17; stop-opacity: 0.80000001"
offset="0"
/>
<stop
style="stop-color: #11b3d4; stop-opacity: 0.49803922"
offset=".5"
/>
<stop style="stop-color: #00f; stop-opacity: 0" offset=".5" />
</linearGradient>
<linearGradient
xlink:href="#b"
id="f"
gradientUnits="userSpaceOnUse"
x1="1.906"
y1="1.889"
x2="15.117"
y2="15.107"
/>
<linearGradient id="b">
<stop style="stop-color: #17ceb5; stop-opacity: 1" offset=".364" />
<stop style="stop-color: #05fa05; stop-opacity: 0" offset="1" />
</linearGradient>
<linearGradient
xlink:href="#a"
id="c"
gradientUnits="userSpaceOnUse"
x1="-3.999"
y1=".503"
x2="-.497"
y2="4.005"
/>
<linearGradient
xlink:href="#b"
id="d"
gradientUnits="userSpaceOnUse"
x1="1.906"
y1="1.889"
x2="15.117"
y2="15.107"
/>
</defs>
<g class="brackets" style="display: inline">
<g class="bracket-right" style="display: inline">
<path
style="
display: inline;
fill: url(#c);
fill-rule: evenodd;
stroke-width: 0.264583;
"
transform="rotate(90 0 41.401) scale(3.77953)"
d="M-3.5 0h3a.499.499 0 1 1 0 1h-3a.499.499 0 1 1 0-1Z"
/>
<path
style="
display: inline;
fill: url(#d);
fill-opacity: 1;
fill-rule: evenodd;
stroke-width: 0.999999;
"
d="M1.89 0C.845 0 .002.845 0 1.89v3.78a1.89 1.89 0 0 1 1.885-1.89h11.344a1.884 1.884 0 0 0 1.888-1.89C15.117.845 14.275 0 13.23 0Zm1.89 5.67a1.89 1.89 0 0 1-.009.17h.008z"
transform="rotate(179.997 20.7 20.7)"
/>
</g>
<g class="bracket-left" style="display: inline">
<path
style="
display: inline;
fill: url(#e);
fill-rule: evenodd;
stroke-width: 0.264583;
"
transform="rotate(-90 22.599 0) scale(3.77953)"
d="M-3.5 0h3a.499.499 0 1 1 0 1h-3a.499.499 0 1 1 0-1Z"
/>
<path
style="
display: inline;
fill: url(#f);
fill-opacity: 1;
fill-rule: evenodd;
stroke-width: 0.999999;
"
d="M1.89 0C.845 0 .002.845 0 1.89v3.78a1.89 1.89 0 0 1 1.885-1.89h11.344a1.884 1.884 0 0 0 1.888-1.89C15.117.845 14.275 0 13.23 0Zm1.89 5.67a1.89 1.89 0 0 1-.009.17h.008z"
transform="matrix(1 0 0 1 22.599 22.598)"
/>
</g>
</g>
</svg>
</body>
</html>
This is the closest I have gotten to so far. Note how the left bracket looks like it is translating during the very last animation, even though I only have a rotate active on it. I also don't want the right bracket to move on the y-axis, just the x-axis.
I am not quite sure why exactly this happens, but I think it's related to the rotation also modifying the SVG's coordinate system. I already tried nesting each of the brackets as a SVG inside the main SVG, but either I was too dumb to do that correctly, or it didn't help.
How can I achieve this? What's the best way to handle transforms modifying the SVG's coordinate system when animating different/combined SVG-graphics?
Solution
Problems like this are almost always caused by one of two things:
- Accidentally replacing an existing transform with a non-equivalent one, or
- The transform origin changing unexpectedly
In your case, I believe it is the latter. When you move the .bracket-right
, the point corresponding to transform-origin: center
moves. That is because the fill-box
is getting bigger. And that affects what the combined set of transforms produces.
I would recommend simplifying your animations. You really only have two transforms happening:
- The scale and rotate of both brackets
- The movement of the right bracket
The most important change I have made below is to (a) remove transform-box: fill
and (b) use absolute coordinates for the transform-origin
.
For the initial scale, I use transform-origin: 22.6px, 22.6px
. Which corresponds to the top-left of the brackets. And for the rotation I use transform-origin: 32px, 32px
, which corresponds to the centre point of the two brackets. And because I am using absolute coordinates, the transforms aren't affected when the right bracket moves.
As for the right bracket animation, I simplified it to a simple translate down and to the right. Because that is what it really is if you think about the original un-rotated icon.
.brackets {
animation: anim-both 3s forwards;
}
.bracket-right {
animation: anim-right 1s 3s forwards;
}
@keyframes anim-both {
0% {
transform: rotate(0deg) scale(0);
transform-origin: 22.6px 22.6px;
}
33% {
transform: rotate(0deg) scale(1);
transform-origin: 22.6px 22.6px;
}
34% {
transform: rotate(0deg) scale(1);
transform-origin: 32px 32px;
}
100% {
transform: rotate(-405deg) scale(1);
transform-origin: 32px 32px;
}
}
@keyframes anim-right {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(40px, 40px);
}
}
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>CSS SVG</title>
<link rel="stylesheet" href="test.css" />
</head>
<body>
<svg
width="256"
height="256"
viewbox="0 0 100 100"
>
<defs>
<linearGradient
xlink:href="#a"
id="e"
gradientUnits="userSpaceOnUse"
x1="-3.999"
y1=".503"
x2="-.497"
y2="4.005"
/>
<linearGradient id="a">
<stop
style="stop-color: #17ce17; stop-opacity: 0.80000001"
offset="0"
/>
<stop
style="stop-color: #11b3d4; stop-opacity: 0.49803922"
offset=".5"
/>
<stop style="stop-color: #00f; stop-opacity: 0" offset=".5" />
</linearGradient>
<linearGradient
xlink:href="#b"
id="f"
gradientUnits="userSpaceOnUse"
x1="1.906"
y1="1.889"
x2="15.117"
y2="15.107"
/>
<linearGradient id="b">
<stop style="stop-color: #17ceb5; stop-opacity: 1" offset=".364" />
<stop style="stop-color: #05fa05; stop-opacity: 0" offset="1" />
</linearGradient>
<linearGradient
xlink:href="#a"
id="c"
gradientUnits="userSpaceOnUse"
x1="-3.999"
y1=".503"
x2="-.497"
y2="4.005"
/>
<linearGradient
xlink:href="#b"
id="d"
gradientUnits="userSpaceOnUse"
x1="1.906"
y1="1.889"
x2="15.117"
y2="15.107"
/>
</defs>
<g class="brackets">
<g class="bracket-right">
<path
style="
fill: url(#c);
fill-rule: evenodd;
stroke-width: 0.264583;
"
transform="rotate(90 0 41.401) scale(3.77953)"
d="M-3.5 0h3a.499.499 0 1 1 0 1h-3a.499.499 0 1 1 0-1Z"
/>
<path
style="
fill: url(#d);
fill-opacity: 1;
fill-rule: evenodd;
stroke-width: 0.999999;
"
d="M1.89 0C.845 0 .002.845 0 1.89v3.78a1.89 1.89 0 0 1 1.885-1.89h11.344a1.884 1.884 0 0 0 1.888-1.89C15.117.845 14.275 0 13.23 0Zm1.89 5.67a1.89 1.89 0 0 1-.009.17h.008z"
transform="rotate(179.997 20.7 20.7)"
/>
</g>
<g class="bracket-left">
<path
style="
fill: url(#e);
fill-rule: evenodd;
stroke-width: 0.264583;
"
transform="rotate(-90 22.599 0) scale(3.77953)"
d="M-3.5 0h3a.499.499 0 1 1 0 1h-3a.499.499 0 1 1 0-1Z"
/>
<path
style="
fill: url(#f);
fill-opacity: 1;
fill-rule: evenodd;
stroke-width: 0.999999;
"
d="M1.89 0C.845 0 .002.845 0 1.89v3.78a1.89 1.89 0 0 1 1.885-1.89h11.344a1.884 1.884 0 0 0 1.888-1.89C15.117.845 14.275 0 13.23 0Zm1.89 5.67a1.89 1.89 0 0 1-.009.17h.008z"
transform="matrix(1 0 0 1 22.599 22.598)"
/>
</g>
</g>
</svg>
</body>
</html>
Answered By - Paul LeBeau
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.