如何在其父级旋转后正确翻译部分 SVG 图形?
How to correctly translate part of SVG graphic after its parenthas been rotated?
我正在尝试在旋转整个图形后翻译部分 SVG 图形。它由两个先按比例缩小然后旋转的三角形支架组成。
完成后,我只希望右括号在 x 轴上向右移动,而左括号保持原位。
围绕元素中心缩放和旋转元素不是问题,但是当我想平移 x 轴上的右括号时,我遇到了意想不到的副作用。
这是一个说明问题的工作片段:
.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>
这是我迄今为止最接近的一次。请注意左括号在最后一个动画中看起来是如何平移的,即使我只在其上激活了旋转。我也不希望右括号在y轴上移动,只在x轴上移动。
我不太清楚为什么会发生这种情况,但我认为这与旋转有关,同时也修改了 SVG 的坐标系。我已经尝试将每个括号作为 SVG 嵌套在主 SVG 中,但要么我太笨不能正确地做到这一点,要么没有帮助。
我怎样才能做到这一点?在动画化 different/combined SVG 图形时处理修改 SVG 坐标系的变换的最佳方法是什么?
我会采取截然不同的方法。我会使用带有 stroke-linecap="round"
的笔触而不是填充路径
在下一个示例中,笔画是黑色的,但如果需要,您可以使用渐变色。
请注意,我已经更改了 viewBox 属性的前 2 个参数的值,因为我想使括号围绕 0,0 居中。这大大简化了代码。
观察:我保持了与您的代码中相同的 svg 大小和纵横比,但我会将其更改为更小的 canvas。为了理解我的意思,我在 svg canvas.
中添加了银色背景
svg{background:silver}
path{animation: a 1s forwards;}
g{animation: b 1s 1s forwards;}
@keyframes a{
100% {
transform: rotate(-45deg);
}
}
@keyframes b{
100% {
transform: translate(20px,0px);
}
}
<svg width="256" height="256" viewbox="-20 -20 100 100" fill="none" stroke="black" stroke-width="4" stroke-linecap="round">
<path d="M-7.5,-7.5h11" />
<path d="M-7.5,-7.5v11" />
<g>
<path d="M7.5,7.5h-11" />
<path d="M7.5,7.5v-11" />
</g>
</svg>
像这样的问题几乎总是由以下两种情况之一引起的:
- 不小心将现有转换替换为非等效转换,或者
- 变换原点意外改变
你的情况,我认为是后者。当您移动 .bracket-right
时,对应于 transform-origin: center
的点也会移动。那是因为 fill-box
越来越大了。这会影响转换组合产生的结果。
我会建议简化您的动画。您实际上只发生了两个转换:
- 两个支架的缩放和旋转
- 右括号的移动
我在下面所做的最重要的更改是 (a) 删除 transform-box: fill
和 (b) 使用绝对坐标作为 transform-origin
.
对于初始比例,我使用 transform-origin: 22.6px, 22.6px
。对应于括号的左上角。对于旋转,我使用 transform-origin: 32px, 32px
,它对应于两个括号的中心点。而且因为我使用的是绝对坐标,所以当右括号移动时变换不会受到影响。
至于右括号动画,我将其简化为简单的向下和向右平移。因为如果您考虑原始未旋转的图标,这就是它的真实情况。
.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>
我正在尝试在旋转整个图形后翻译部分 SVG 图形。它由两个先按比例缩小然后旋转的三角形支架组成。 完成后,我只希望右括号在 x 轴上向右移动,而左括号保持原位。
围绕元素中心缩放和旋转元素不是问题,但是当我想平移 x 轴上的右括号时,我遇到了意想不到的副作用。
这是一个说明问题的工作片段:
.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>
这是我迄今为止最接近的一次。请注意左括号在最后一个动画中看起来是如何平移的,即使我只在其上激活了旋转。我也不希望右括号在y轴上移动,只在x轴上移动。
我不太清楚为什么会发生这种情况,但我认为这与旋转有关,同时也修改了 SVG 的坐标系。我已经尝试将每个括号作为 SVG 嵌套在主 SVG 中,但要么我太笨不能正确地做到这一点,要么没有帮助。
我怎样才能做到这一点?在动画化 different/combined SVG 图形时处理修改 SVG 坐标系的变换的最佳方法是什么?
我会采取截然不同的方法。我会使用带有 stroke-linecap="round"
在下一个示例中,笔画是黑色的,但如果需要,您可以使用渐变色。
请注意,我已经更改了 viewBox 属性的前 2 个参数的值,因为我想使括号围绕 0,0 居中。这大大简化了代码。
观察:我保持了与您的代码中相同的 svg 大小和纵横比,但我会将其更改为更小的 canvas。为了理解我的意思,我在 svg canvas.
中添加了银色背景svg{background:silver}
path{animation: a 1s forwards;}
g{animation: b 1s 1s forwards;}
@keyframes a{
100% {
transform: rotate(-45deg);
}
}
@keyframes b{
100% {
transform: translate(20px,0px);
}
}
<svg width="256" height="256" viewbox="-20 -20 100 100" fill="none" stroke="black" stroke-width="4" stroke-linecap="round">
<path d="M-7.5,-7.5h11" />
<path d="M-7.5,-7.5v11" />
<g>
<path d="M7.5,7.5h-11" />
<path d="M7.5,7.5v-11" />
</g>
</svg>
像这样的问题几乎总是由以下两种情况之一引起的:
- 不小心将现有转换替换为非等效转换,或者
- 变换原点意外改变
你的情况,我认为是后者。当您移动 .bracket-right
时,对应于 transform-origin: center
的点也会移动。那是因为 fill-box
越来越大了。这会影响转换组合产生的结果。
我会建议简化您的动画。您实际上只发生了两个转换:
- 两个支架的缩放和旋转
- 右括号的移动
我在下面所做的最重要的更改是 (a) 删除 transform-box: fill
和 (b) 使用绝对坐标作为 transform-origin
.
对于初始比例,我使用 transform-origin: 22.6px, 22.6px
。对应于括号的左上角。对于旋转,我使用 transform-origin: 32px, 32px
,它对应于两个括号的中心点。而且因为我使用的是绝对坐标,所以当右括号移动时变换不会受到影响。
至于右括号动画,我将其简化为简单的向下和向右平移。因为如果您考虑原始未旋转的图标,这就是它的真实情况。
.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>