如何使用 CSS 为径向渐变设置动画?
How to animate a radial-gradient using CSS?
我正在尝试为 div 框创建径向渐变发光效果,但我不确定这样做的最佳方法是什么。我没有找到实现我想要实现的目标的资源;只是闪耀影响看起来像叠加层。
我找到的大多数示例看起来像这样 http://jsfiddle.net/nqQc7/512/。
下面显示了我要创建的内容。
#shine-div {
height: 30vh;
width: 60vw;
margin-right: auto;
margin-left: auto;
border-radius: 10px;
/*background: radial-gradient(ellipse farthest-corner at right top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%);*/
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
animation: colorChange 5s infinite;
}
@keyframes colorChange {
0% {
background: radial-gradient(ellipse farthest-corner at left top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%)
}
50% {
background: radial-gradient(ellipse farthest-corner at top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%)
}
100% {
background: radial-gradient(ellipse farthest-corner at right top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%)
}
}
<div id="shine-div">
Shine
</div>
这可以吗?我还想让白色在顶部闪耀,从左到右平滑地移动?我的尝试是否走在正确的轨道上?
您可以采用不同的渐变方式并为位置设置动画。诀窍是将渐变的大小加倍,并使颜色值停止其实际值的一半,这样您就可以保持相同的视觉渐变,然后可以从左到右对其进行动画处理。
由于最远角的计算,它看起来与您在动画中定义的渐变完全不一样。
#shine-div {
height: 30vh;
width: 60vw;
margin-right: auto;
margin-left: auto;
border-radius: 10px;
background: radial-gradient(farthest-corner at top, #FFFFFF 0%, #ffb3ff 4%, #ff33ff 12.25%, #800080 31.25%, #b300b3 50%) top right/200% 200%;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
animation: colorChange 5s infinite alternate;
}
@keyframes colorChange {
to {
background-position:top left;
}
}
<div id="shine-div">
Shine
</div>
为了更接近您的渐变,您还必须设置 background-size
的动画(计算详情见下文)
#shine-div {
height: 30vh;
width: 60vw;
margin-right: auto;
margin-left: auto;
border-radius: 10px;
background: radial-gradient(farthest-corner at top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 24.5%, #800080 62.5%, #b300b3 100%);
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
animation: colorChange 5s infinite alternate linear;
}
@keyframes colorChange {
from { /* radial-gradient(farthest-corner at top right, ..) */
background-position:left top;
background-size:200% 100%;
}
49.9% {
background-position:left top;
}
50% { /* radial-gradient(farthest-corner at top center, ..) */
background-size:100% 100%;
}
50.1% {
background-position:right top;
}
to { /* radial-gradient(farthest-corner at top left, ..) */
background-position:right top;
background-size:200% 100%;
}
}
<div id="shine-div">
Shine
</div>
你也可以做同样的动画考虑伪元素和变换以获得更好的性能:
#shine-div {
height: 30vh;
width: 60vw;
margin-right: auto;
margin-left: auto;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
overflow:hidden;
position:relative;
z-index:0;
}
#shine-div:before {
content:"";
position:absolute;
z-index:-1;
top:0;
left:0;
width:400%;
height:200%;
background: radial-gradient(farthest-corner at top, #FFFFFF 0%, #ffb3ff 4%, #ff33ff 12.25%, #800080 31.25%, #b300b3 50%);
animation: colorChange 5s infinite alternate linear;
}
@keyframes colorChange {
from {
transform:translateX(-50%);
}
50% {
transform:scaleX(0.75) translateX(-50%)
}
to {
transform:translateX(-25%);
}
}
<div id="shine-div">
Shine
</div>
更深入
为了使答案更通用,我将详细说明如何从两个不同的位置为任何类型的渐变设置动画。主要技巧是用不同的方式编写渐变,使其定义为常量(radial-gradient(<constant_definition>)
)并为 background-position
(在某些情况下为 background-size
)设置动画
假设我们的梯度为 background:radial-gradient(Rh Rv at X Y, color1 p1, color2 p2)
其中 Rh
和 Ry
分别是我们椭圆的水平半径和垂直半径(如果两者相等或只使用一个值然后是一个圆圈)。
首先,我们将渐变的大小加倍。这个技巧将使我们能够使用百分比值轻松调整渐变的位置(此处解释:Using percentage values with background-position on a linear-gradient)
如果半径是用像素值定义的,我们保留它,但如果它是用百分比值定义的,我们将它除以 2,因为它是相对于他增加的大小。如果两个半径都是百分比,我们可以将两者都除以 2,或者保留它们并将色标除以 2。
其次,我们移除at X Y
,这会使渐变居中,因此我们需要使用background-position
来校正位置。很明显,如果梯度为 0 0
,我们需要使用 background-position:100% 100%
绿色框是我们的背景,比元素(黑色框)大两倍,红色圆圈是我们的渐变。通过调整背景位置,我们在视觉上将渐变定位在 0 0
.
对于任何 X
、Y
值,逻辑上我们将有 background-position:calc(100% - X) calc(100% - Y)
如果X,Y是像素值我们也可以用background-position: right -X bottom -Y
(注意是-X
而不是- X
,我们用负值)
示例:
有像素值
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(20% 100px at 20px 30px,red 30%,blue 60%);"></div>
<div class="box" style="background:radial-gradient(10% 100px,red 30%,blue 60%) right -20px bottom -30px/200% 200%;"></div>
<br>
<div class="box" style="background:radial-gradient(40% 40% at 40px 50px,yellow 30%,blue);"></div>
<div class="box" style="background:radial-gradient(40% 40%,yellow 15%,blue 50%) right -40px bottom -50px/200% 200%;"></div>
<div class="box" style="background:radial-gradient(20% 20%,yellow 30%,blue) right -40px bottom -50px/200% 200%;"></div>
有百分比值
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(20% 100px at 50% 10%,red 30%,blue 60%);"></div>
<div class="box" style="background:radial-gradient(10% 100px,red 30%,blue 60%) calc(100% - 50%) calc(100% - 10%)/200% 200%;"></div>
<br>
<div class="box" style="background:radial-gradient(40% 40% at 30% 70%,yellow 30%,blue);"></div>
<div class="box" style="background:radial-gradient(40% 40%,yellow 15%,blue 50%) calc(100% - 30%) calc(100% - 70%)/200% 200%;"></div>
<div class="box" style="background:radial-gradient(20% 20%,yellow 30%,blue) calc(100% - 30%) calc(100% - 70%)/200% 200%;"></div>
所以如果我们想为来自以下位置的 gadient 设置动画:
radial-gradient(Rh Rv at X Y, color1 p1, color2 p2)
至
radial-gradient(Rh Rv at X1 Y2, color1 p1, color2 p2)
我们以不同的方式编写它并为 background-position
:
设置动画
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
.first {
background:radial-gradient(10% 100px,red 30%,blue 60%) calc(100% - 50%) calc(100% - 10%)/200% 200%;
animation:change1 2s linear infinite alternate;
}
.second {
background:radial-gradient(20% 20%,yellow 30%,blue)right -50px bottom 0/200% 200%;
animation:change2 2s linear infinite alternate;
}
@keyframes change1 {
to {
background-position:calc(100% + 10%) calc(100% - 80%);
}
}
@keyframes change2 {
to {
background-position:right -100px bottom -100px;
}
}
<div class="box first" ></div>
<div class="box second"></div>
现在让我们考虑更棘手的情况,例如我们最初的示例,使用 farthest-side
来定义大小。我们将执行相同的逻辑并转换
radial-gradient(farthest-side at X Y, color1 p1, color2 p2);
至
radial-gradient(farthest-side, color1 p1, color2 p2) Px Py/Sx Sy no-repeat;
我会解释一个轴(X
),同样适用于另一个轴
farthest-side
定义半径为渐变中心到渐变框最远边的距离(渐变框默认是元素本身,因为我们没有定义任何大小)。如果 X
是一个百分比值,那么半径是 X
和 100% - X
之间的最大值,并且在转换后的梯度中,半径将为 50%
因为我们位于中心。所以我们需要匹配第一个半径 50%*Sx
如果 X
是 50%
那么 Sx
应该是 100%
如果 X
是 0
或者 100%
那么Sx
应该是 200%
.
公式为Sx = max(X,100% - X)*2
在这种情况下,由于形状应该接触一侧的渐变性质,位置更容易
- 如果
[0 50%[
中的X
Px
应该是100%
(right
)
- 如果
X
是 50%
,Px
的任何值都可以使用,因为 Sx=100%
- 如果
]50% 100%]
中的X
Px
应该是0%
(left
)
相关问题:Using percentage values with background-position on a linear-gradient
示例:
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(farthest-side at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(farthest-side, red 20%, blue 100%, yellow 50%) 100% 0/calc(80%*2) calc(60%*2)"></div>
<br>
<div class="box" style='background:radial-gradient(farthest-side at 22% 100%,red 40%, blue 100%,yellow 100%)'></div>
<div class="box" style="background:radial-gradient(farthest-side,red 40%, blue 100%,yellow 100%) 100% 0/calc(78%*2) calc(100%*2)"></div>
对于farthest-corner
我们做的完全一样:
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(farthest-corner at 20% 60%, red 20%, blue 50%, yellow 60%)" ></div>
<div class="box" style="background:radial-gradient(farthest-corner, red 20%, blue 50%, yellow 60%) 100% 0%/calc(80%*2) calc(60%*2)"></div>
<br>
<div class="box" style="background:radial-gradient(farthest-corner at 40% 100%, red 20%, blue 50%, yellow 60%)" ></div>
<div class="box" style="background:radial-gradient(farthest-corner, red 20%, blue 50%, yellow 60%) 100% 0%/calc(60%*2) calc(100%*2)"></div>
我们也可以将 farthest-side
(或 farthest-corner
)转换为 Rh Rv
并进行前面的计算,但它对动画没有用,因为我们将有两个渐变不同的半径,而我们需要相同的梯度。
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(farthest-side at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(80% 60% at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(80% 60%, red 10%, blue 50%, yellow 50%) 80% 40%/200% 200%"></div>
如果X
是一个像素值我们有两种情况:
- 元素有一个固定的宽度:在这种情况下,我们可以简单地将
X
的像素值转换为宽度的百分比,我们做与上面相同的逻辑。
- 元素的宽度可变:在这种情况下,转换渐变会很棘手(可能不可能),因为形状会根据宽度改变。当
width-X > X
时,我们将有一个 可变的 半径,当 width-X < X
时,我们将有一个 固定的 半径。我认为我们不能使用 background-size
和 background-position
来表达这一点。示例:
body {
margin:0;
height:100vh;
background:radial-gradient(farthest-side at 400px 200px,blue 40%,yellow 50%);
}
对于 closest-side
考虑 Sx=min(X,100% - X)*2
会执行相同的逻辑,但是我们应该添加 no-repeat
和 background-color
等于渐变中的最后一个颜色,因为大小小于 100%
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(closest-side at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(closest-side, red 20%, blue 100%, yellow 100%) 0 100%/calc(20%*2) calc(40%*2)"></div>
<div class="box" style="background:radial-gradient(closest-side, red 20%, blue 100%, yellow 100%) 0 100%/calc(20%*2) calc(40%*2) no-repeat,yellow"></div>
<br>
<div class="box" style='background:radial-gradient(closest-side at 22% 10%,red 40%, blue 100%,yellow 100%)'></div>
<div class="box" style="background:radial-gradient(closest-side,red 40%, blue 100%,yellow 100%) 0 0/calc(22%*2) calc(10%*2)"></div>
<div class="box" style="background:radial-gradient(closest-side,red 40%, blue 100%,yellow 100%) 0 0/calc(22%*2) calc(10%*2) no-repeat,yellow"></div>
我们可以对 closest-corner
做同样的事情,但是由于渐变会溢出渐变框,我们会遇到一些问题。
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(closest-corner at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(closest-corner, red 20%, blue 100%, yellow 100%) 0 100%/calc(20%*2) calc(40%*2)"></div>
<div class="box" style="background:radial-gradient(closest-corner, red 20%, blue 100%, yellow 100%) 0 100%/calc(20%*2) calc(40%*2) no-repeat,yellow"></div>
为了纠正这个问题,我们可以将色标除以 2,以确保我们将整个渐变保留在里面。然后我们把size变大一倍,我们把position改正
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(closest-corner at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(closest-corner, red 10%, blue 50%, yellow 50%) -100% 33%/calc(20%*4) calc(40%*4)"></div>
<div class="box" style="background:radial-gradient(closest-corner, red 10%, blue 50%, yellow 50%) -100% 33%/calc(20%*4) calc(40%*4) no-repeat,yellow"></div>
<br>
<div class="box" style='background:radial-gradient(closest-corner at 22% 10%,red 40%, blue 100%,yellow 100%)'></div>
<div class="box" style="background:radial-gradient(closest-corner,red 20%, blue 50%,yellow 50%) -100% 0%/calc(22%*4) calc(10%*4)"></div>
<div class="box" style="background:radial-gradient(closest-corner,red 20%, blue 50%,yellow 50%) -164% -18%/calc(22%*4) calc(10%*4) no-repeat,yellow"></div>
即使没有动画,也更支持不带 at X Y
的渐变语法。 Safari 等浏览器不支持 at
()
SVG 解决方案
作者没有要求使用 SVG
解决他的问题。但是,以多种方式解决一个问题可能会有用。
渐变属性值取自@Temani Afif 响应。
本题SVG径向渐变公式:
<radialGradient id="radGrad" fx="0%" fy="5%" r="200%">
<stop offset="0%" stop-color ="#FFFFFF" />
<stop offset="4%" stop-color ="#ffb3ff" />
<stop offset="12.25%" stop-color ="#ff33ff" />
<stop offset="31.25%" stop-color ="#800080" />
<stop offset="50%" stop-color ="#b300b3" />
</radialGradient>
要为渐变设置动画,您可以使用公式中包含的任何属性。
下面的示例将使用属性 fx
和 fy
- 水平渐变运动动画
点击矩形后开始动画
svg {
width:50%;
height:50%;
}
.txt {
font-family:sans-serif;
font-size:28px;
font-weight:bold;
text-anchor:middle;
fill:#FFDD00;
}
<div id="shine-div">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 100">
<defs>
<radialGradient id="radGrad" fx="0%" fy="0%" r="200%">
<stop offset="0%" stop-color ="#FFFFFF" />
<stop offset="4%" stop-color ="#ffb3ff" />
<stop offset="12.25%" stop-color ="#ff33ff" />
<stop offset="31.25%" stop-color ="#800080" />
<stop offset="50%" stop-color ="#b300b3" />
</radialGradient>
</defs>
<g id="gr1" >
<rect id="rect1" fill="url(#radGrad)" x="5%" y="5%" width="95%" height="95%" rx="10%"/>
<text class="txt" x="50%" y="60%"> Sun shine </text>
</g>
<animate xlink:href="#radGrad"
attributeName="fx"
dur="3s"begin="gr1.click"
values="0%;100%;0%"
repeatCount="1"
restart="whenNotActive" />
</svg>
</div>
- 垂直渐变运动的动画。
svg {
width:50%;
height:50%;
}
.txt {
font-family:sans-serif;
font-size:28px;
font-weight:bold;
text-anchor:middle;
fill:#FFDD00;
}
<div id="shine-div">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 100">
<defs>
<radialGradient id="radGrad" fx="48%" fy="0%" r="200%">
<stop offset="0%" stop-color ="#FFFFFF" />
<stop offset="4%" stop-color ="#ffb3ff" />
<stop offset="12.25%" stop-color ="#ff33ff" />
<stop offset="31.25%" stop-color ="#800080" />
<stop offset="50%" stop-color ="#b300b3" />
</radialGradient>
</defs>
<g id="gr1" >
<rect id="rect1" fill="url(#radGrad)" x="5%" y="5%" width="95%" height="95%" rx="10%"/>
<text class="txt" x="50%" y="60%"> Sun shine </text>
</g>
<animate xlink:href="#radGrad"
attributeName="fy"
dur="2s"begin="gr1.click"
values="0%;50%;50%;100%;50%;50%;0%"
keyTimes="0;0.1;0.5;0.6;0.7;0.9;1"
repeatCount="1"
restart="whenNotActive" />
</svg>
</div>
- 沿对角线移动渐变
两个属性同时动画:fx
和fy
svg {
width:50%;
height:50%;
}
.txt {
font-family:sans-serif;
font-size:28px;
font-weight:bold;
text-anchor:middle;
fill:#FFDD00;
}
<div id="shine-div">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 100">
<defs>
<radialGradient id="radGrad" fx="0%" fy="0%" r="200%">
<stop offset="0%" stop-color ="#FFFFFF" />
<stop offset="4%" stop-color ="#ffb3ff" />
<stop offset="12.25%" stop-color ="#ff33ff" />
<stop offset="31.25%" stop-color ="#800080" />
<stop offset="50%" stop-color ="#b300b3" />
</radialGradient>
</defs>
<g id="gr1" >
<rect id="rect1" fill="url(#radGrad)" x="5%" y="5%" width="95%" height="95%" rx="10%"/>
<text class="txt" x="50%" y="60%"> Sun shine </text>
</g>
<animate xlink:href="#radGrad"
attributeName="fy"
dur="2s"begin="gr1.click"
values="0%;50%;50%;100%;0%"
keyTimes="0;0.1;0.5;0.9;1"
repeatCount="1"
restart="whenNotActive" />
<animate xlink:href="#radGrad"
attributeName="fx"
dur="2s"begin="gr1.click"
values="0%;50%;50%;100%;0%"
keyTimes="0;0.1;0.5;0.9;1"
repeatCount="1"
restart="whenNotActive" />
</svg>
</div>
使用 CSS 变量和新的 @property
we can easily animate radial-gradient
(or any kind of gradient). The support 目前仅涵盖 Chrome 和 Edge。
@property --x {
syntax: '<percentage>';
inherits: false;
initial-value: 0%;
}
#shine-div {
height: 30vh;
width: 60vw;
margin: auto;
border-radius: 10px;
background: radial-gradient(ellipse farthest-corner at var(--x) 0%, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%);
animation: colorChange 5s infinite alternate;
}
@keyframes colorChange {
0% {
--x:0%;
}
50% {
--x:50%;
}
100% {
--x:100%;
}
}
<div id="shine-div"></div>
我们所要做的就是使用变量 --x
定义位置,该变量将使用百分比值,然后我们为该变量设置动画。就这么简单!
我正在尝试为 div 框创建径向渐变发光效果,但我不确定这样做的最佳方法是什么。我没有找到实现我想要实现的目标的资源;只是闪耀影响看起来像叠加层。
我找到的大多数示例看起来像这样 http://jsfiddle.net/nqQc7/512/。
下面显示了我要创建的内容。
#shine-div {
height: 30vh;
width: 60vw;
margin-right: auto;
margin-left: auto;
border-radius: 10px;
/*background: radial-gradient(ellipse farthest-corner at right top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%);*/
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
animation: colorChange 5s infinite;
}
@keyframes colorChange {
0% {
background: radial-gradient(ellipse farthest-corner at left top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%)
}
50% {
background: radial-gradient(ellipse farthest-corner at top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%)
}
100% {
background: radial-gradient(ellipse farthest-corner at right top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%)
}
}
<div id="shine-div">
Shine
</div>
这可以吗?我还想让白色在顶部闪耀,从左到右平滑地移动?我的尝试是否走在正确的轨道上?
您可以采用不同的渐变方式并为位置设置动画。诀窍是将渐变的大小加倍,并使颜色值停止其实际值的一半,这样您就可以保持相同的视觉渐变,然后可以从左到右对其进行动画处理。
由于最远角的计算,它看起来与您在动画中定义的渐变完全不一样。
#shine-div {
height: 30vh;
width: 60vw;
margin-right: auto;
margin-left: auto;
border-radius: 10px;
background: radial-gradient(farthest-corner at top, #FFFFFF 0%, #ffb3ff 4%, #ff33ff 12.25%, #800080 31.25%, #b300b3 50%) top right/200% 200%;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
animation: colorChange 5s infinite alternate;
}
@keyframes colorChange {
to {
background-position:top left;
}
}
<div id="shine-div">
Shine
</div>
为了更接近您的渐变,您还必须设置 background-size
的动画(计算详情见下文)
#shine-div {
height: 30vh;
width: 60vw;
margin-right: auto;
margin-left: auto;
border-radius: 10px;
background: radial-gradient(farthest-corner at top, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 24.5%, #800080 62.5%, #b300b3 100%);
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
animation: colorChange 5s infinite alternate linear;
}
@keyframes colorChange {
from { /* radial-gradient(farthest-corner at top right, ..) */
background-position:left top;
background-size:200% 100%;
}
49.9% {
background-position:left top;
}
50% { /* radial-gradient(farthest-corner at top center, ..) */
background-size:100% 100%;
}
50.1% {
background-position:right top;
}
to { /* radial-gradient(farthest-corner at top left, ..) */
background-position:right top;
background-size:200% 100%;
}
}
<div id="shine-div">
Shine
</div>
你也可以做同样的动画考虑伪元素和变换以获得更好的性能:
#shine-div {
height: 30vh;
width: 60vw;
margin-right: auto;
margin-left: auto;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
overflow:hidden;
position:relative;
z-index:0;
}
#shine-div:before {
content:"";
position:absolute;
z-index:-1;
top:0;
left:0;
width:400%;
height:200%;
background: radial-gradient(farthest-corner at top, #FFFFFF 0%, #ffb3ff 4%, #ff33ff 12.25%, #800080 31.25%, #b300b3 50%);
animation: colorChange 5s infinite alternate linear;
}
@keyframes colorChange {
from {
transform:translateX(-50%);
}
50% {
transform:scaleX(0.75) translateX(-50%)
}
to {
transform:translateX(-25%);
}
}
<div id="shine-div">
Shine
</div>
更深入
为了使答案更通用,我将详细说明如何从两个不同的位置为任何类型的渐变设置动画。主要技巧是用不同的方式编写渐变,使其定义为常量(radial-gradient(<constant_definition>)
)并为 background-position
(在某些情况下为 background-size
)设置动画
假设我们的梯度为 background:radial-gradient(Rh Rv at X Y, color1 p1, color2 p2)
其中 Rh
和 Ry
分别是我们椭圆的水平半径和垂直半径(如果两者相等或只使用一个值然后是一个圆圈)。
首先,我们将渐变的大小加倍。这个技巧将使我们能够使用百分比值轻松调整渐变的位置(此处解释:Using percentage values with background-position on a linear-gradient)
如果半径是用像素值定义的,我们保留它,但如果它是用百分比值定义的,我们将它除以 2,因为它是相对于他增加的大小。如果两个半径都是百分比,我们可以将两者都除以 2,或者保留它们并将色标除以 2。
其次,我们移除at X Y
,这会使渐变居中,因此我们需要使用background-position
来校正位置。很明显,如果梯度为 0 0
,我们需要使用 background-position:100% 100%
绿色框是我们的背景,比元素(黑色框)大两倍,红色圆圈是我们的渐变。通过调整背景位置,我们在视觉上将渐变定位在 0 0
.
对于任何 X
、Y
值,逻辑上我们将有 background-position:calc(100% - X) calc(100% - Y)
如果X,Y是像素值我们也可以用background-position: right -X bottom -Y
(注意是-X
而不是- X
,我们用负值)
示例:
有像素值
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(20% 100px at 20px 30px,red 30%,blue 60%);"></div>
<div class="box" style="background:radial-gradient(10% 100px,red 30%,blue 60%) right -20px bottom -30px/200% 200%;"></div>
<br>
<div class="box" style="background:radial-gradient(40% 40% at 40px 50px,yellow 30%,blue);"></div>
<div class="box" style="background:radial-gradient(40% 40%,yellow 15%,blue 50%) right -40px bottom -50px/200% 200%;"></div>
<div class="box" style="background:radial-gradient(20% 20%,yellow 30%,blue) right -40px bottom -50px/200% 200%;"></div>
有百分比值
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(20% 100px at 50% 10%,red 30%,blue 60%);"></div>
<div class="box" style="background:radial-gradient(10% 100px,red 30%,blue 60%) calc(100% - 50%) calc(100% - 10%)/200% 200%;"></div>
<br>
<div class="box" style="background:radial-gradient(40% 40% at 30% 70%,yellow 30%,blue);"></div>
<div class="box" style="background:radial-gradient(40% 40%,yellow 15%,blue 50%) calc(100% - 30%) calc(100% - 70%)/200% 200%;"></div>
<div class="box" style="background:radial-gradient(20% 20%,yellow 30%,blue) calc(100% - 30%) calc(100% - 70%)/200% 200%;"></div>
所以如果我们想为来自以下位置的 gadient 设置动画:
radial-gradient(Rh Rv at X Y, color1 p1, color2 p2)
至
radial-gradient(Rh Rv at X1 Y2, color1 p1, color2 p2)
我们以不同的方式编写它并为 background-position
:
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
.first {
background:radial-gradient(10% 100px,red 30%,blue 60%) calc(100% - 50%) calc(100% - 10%)/200% 200%;
animation:change1 2s linear infinite alternate;
}
.second {
background:radial-gradient(20% 20%,yellow 30%,blue)right -50px bottom 0/200% 200%;
animation:change2 2s linear infinite alternate;
}
@keyframes change1 {
to {
background-position:calc(100% + 10%) calc(100% - 80%);
}
}
@keyframes change2 {
to {
background-position:right -100px bottom -100px;
}
}
<div class="box first" ></div>
<div class="box second"></div>
现在让我们考虑更棘手的情况,例如我们最初的示例,使用 farthest-side
来定义大小。我们将执行相同的逻辑并转换
radial-gradient(farthest-side at X Y, color1 p1, color2 p2);
至
radial-gradient(farthest-side, color1 p1, color2 p2) Px Py/Sx Sy no-repeat;
我会解释一个轴(X
),同样适用于另一个轴
farthest-side
定义半径为渐变中心到渐变框最远边的距离(渐变框默认是元素本身,因为我们没有定义任何大小)。如果 X
是一个百分比值,那么半径是 X
和 100% - X
之间的最大值,并且在转换后的梯度中,半径将为 50%
因为我们位于中心。所以我们需要匹配第一个半径 50%*Sx
如果 X
是 50%
那么 Sx
应该是 100%
如果 X
是 0
或者 100%
那么Sx
应该是 200%
.
公式为Sx = max(X,100% - X)*2
在这种情况下,由于形状应该接触一侧的渐变性质,位置更容易
- 如果
[0 50%[
中的X
Px
应该是100%
(right
) - 如果
X
是50%
,Px
的任何值都可以使用,因为Sx=100%
- 如果
]50% 100%]
中的X
Px
应该是0%
(left
)
相关问题:Using percentage values with background-position on a linear-gradient
示例:
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(farthest-side at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(farthest-side, red 20%, blue 100%, yellow 50%) 100% 0/calc(80%*2) calc(60%*2)"></div>
<br>
<div class="box" style='background:radial-gradient(farthest-side at 22% 100%,red 40%, blue 100%,yellow 100%)'></div>
<div class="box" style="background:radial-gradient(farthest-side,red 40%, blue 100%,yellow 100%) 100% 0/calc(78%*2) calc(100%*2)"></div>
对于farthest-corner
我们做的完全一样:
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(farthest-corner at 20% 60%, red 20%, blue 50%, yellow 60%)" ></div>
<div class="box" style="background:radial-gradient(farthest-corner, red 20%, blue 50%, yellow 60%) 100% 0%/calc(80%*2) calc(60%*2)"></div>
<br>
<div class="box" style="background:radial-gradient(farthest-corner at 40% 100%, red 20%, blue 50%, yellow 60%)" ></div>
<div class="box" style="background:radial-gradient(farthest-corner, red 20%, blue 50%, yellow 60%) 100% 0%/calc(60%*2) calc(100%*2)"></div>
我们也可以将 farthest-side
(或 farthest-corner
)转换为 Rh Rv
并进行前面的计算,但它对动画没有用,因为我们将有两个渐变不同的半径,而我们需要相同的梯度。
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(farthest-side at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(80% 60% at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(80% 60%, red 10%, blue 50%, yellow 50%) 80% 40%/200% 200%"></div>
如果X
是一个像素值我们有两种情况:
- 元素有一个固定的宽度:在这种情况下,我们可以简单地将
X
的像素值转换为宽度的百分比,我们做与上面相同的逻辑。 - 元素的宽度可变:在这种情况下,转换渐变会很棘手(可能不可能),因为形状会根据宽度改变。当
width-X > X
时,我们将有一个 可变的 半径,当width-X < X
时,我们将有一个 固定的 半径。我认为我们不能使用background-size
和background-position
来表达这一点。示例:
body {
margin:0;
height:100vh;
background:radial-gradient(farthest-side at 400px 200px,blue 40%,yellow 50%);
}
对于 closest-side
考虑 Sx=min(X,100% - X)*2
会执行相同的逻辑,但是我们应该添加 no-repeat
和 background-color
等于渐变中的最后一个颜色,因为大小小于 100%
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(closest-side at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(closest-side, red 20%, blue 100%, yellow 100%) 0 100%/calc(20%*2) calc(40%*2)"></div>
<div class="box" style="background:radial-gradient(closest-side, red 20%, blue 100%, yellow 100%) 0 100%/calc(20%*2) calc(40%*2) no-repeat,yellow"></div>
<br>
<div class="box" style='background:radial-gradient(closest-side at 22% 10%,red 40%, blue 100%,yellow 100%)'></div>
<div class="box" style="background:radial-gradient(closest-side,red 40%, blue 100%,yellow 100%) 0 0/calc(22%*2) calc(10%*2)"></div>
<div class="box" style="background:radial-gradient(closest-side,red 40%, blue 100%,yellow 100%) 0 0/calc(22%*2) calc(10%*2) no-repeat,yellow"></div>
我们可以对 closest-corner
做同样的事情,但是由于渐变会溢出渐变框,我们会遇到一些问题。
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(closest-corner at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(closest-corner, red 20%, blue 100%, yellow 100%) 0 100%/calc(20%*2) calc(40%*2)"></div>
<div class="box" style="background:radial-gradient(closest-corner, red 20%, blue 100%, yellow 100%) 0 100%/calc(20%*2) calc(40%*2) no-repeat,yellow"></div>
为了纠正这个问题,我们可以将色标除以 2,以确保我们将整个渐变保留在里面。然后我们把size变大一倍,我们把position改正
.box {
height:150px;
width:150px;
border:1px solid;
display:inline-block;
}
<div class="box" style="background:radial-gradient(closest-corner at 20% 60%, red 20%, blue 100%, yellow 100%)" ></div>
<div class="box" style="background:radial-gradient(closest-corner, red 10%, blue 50%, yellow 50%) -100% 33%/calc(20%*4) calc(40%*4)"></div>
<div class="box" style="background:radial-gradient(closest-corner, red 10%, blue 50%, yellow 50%) -100% 33%/calc(20%*4) calc(40%*4) no-repeat,yellow"></div>
<br>
<div class="box" style='background:radial-gradient(closest-corner at 22% 10%,red 40%, blue 100%,yellow 100%)'></div>
<div class="box" style="background:radial-gradient(closest-corner,red 20%, blue 50%,yellow 50%) -100% 0%/calc(22%*4) calc(10%*4)"></div>
<div class="box" style="background:radial-gradient(closest-corner,red 20%, blue 50%,yellow 50%) -164% -18%/calc(22%*4) calc(10%*4) no-repeat,yellow"></div>
即使没有动画,也更支持不带 at X Y
的渐变语法。 Safari 等浏览器不支持 at
(
SVG 解决方案
作者没有要求使用 SVG
解决他的问题。但是,以多种方式解决一个问题可能会有用。
渐变属性值取自@Temani Afif 响应。
本题SVG径向渐变公式:
<radialGradient id="radGrad" fx="0%" fy="5%" r="200%">
<stop offset="0%" stop-color ="#FFFFFF" />
<stop offset="4%" stop-color ="#ffb3ff" />
<stop offset="12.25%" stop-color ="#ff33ff" />
<stop offset="31.25%" stop-color ="#800080" />
<stop offset="50%" stop-color ="#b300b3" />
</radialGradient>
要为渐变设置动画,您可以使用公式中包含的任何属性。
下面的示例将使用属性 fx
和 fy
- 水平渐变运动动画
点击矩形后开始动画
svg {
width:50%;
height:50%;
}
.txt {
font-family:sans-serif;
font-size:28px;
font-weight:bold;
text-anchor:middle;
fill:#FFDD00;
}
<div id="shine-div">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 100">
<defs>
<radialGradient id="radGrad" fx="0%" fy="0%" r="200%">
<stop offset="0%" stop-color ="#FFFFFF" />
<stop offset="4%" stop-color ="#ffb3ff" />
<stop offset="12.25%" stop-color ="#ff33ff" />
<stop offset="31.25%" stop-color ="#800080" />
<stop offset="50%" stop-color ="#b300b3" />
</radialGradient>
</defs>
<g id="gr1" >
<rect id="rect1" fill="url(#radGrad)" x="5%" y="5%" width="95%" height="95%" rx="10%"/>
<text class="txt" x="50%" y="60%"> Sun shine </text>
</g>
<animate xlink:href="#radGrad"
attributeName="fx"
dur="3s"begin="gr1.click"
values="0%;100%;0%"
repeatCount="1"
restart="whenNotActive" />
</svg>
</div>
- 垂直渐变运动的动画。
svg {
width:50%;
height:50%;
}
.txt {
font-family:sans-serif;
font-size:28px;
font-weight:bold;
text-anchor:middle;
fill:#FFDD00;
}
<div id="shine-div">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 100">
<defs>
<radialGradient id="radGrad" fx="48%" fy="0%" r="200%">
<stop offset="0%" stop-color ="#FFFFFF" />
<stop offset="4%" stop-color ="#ffb3ff" />
<stop offset="12.25%" stop-color ="#ff33ff" />
<stop offset="31.25%" stop-color ="#800080" />
<stop offset="50%" stop-color ="#b300b3" />
</radialGradient>
</defs>
<g id="gr1" >
<rect id="rect1" fill="url(#radGrad)" x="5%" y="5%" width="95%" height="95%" rx="10%"/>
<text class="txt" x="50%" y="60%"> Sun shine </text>
</g>
<animate xlink:href="#radGrad"
attributeName="fy"
dur="2s"begin="gr1.click"
values="0%;50%;50%;100%;50%;50%;0%"
keyTimes="0;0.1;0.5;0.6;0.7;0.9;1"
repeatCount="1"
restart="whenNotActive" />
</svg>
</div>
- 沿对角线移动渐变
两个属性同时动画:fx
和fy
svg {
width:50%;
height:50%;
}
.txt {
font-family:sans-serif;
font-size:28px;
font-weight:bold;
text-anchor:middle;
fill:#FFDD00;
}
<div id="shine-div">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 100">
<defs>
<radialGradient id="radGrad" fx="0%" fy="0%" r="200%">
<stop offset="0%" stop-color ="#FFFFFF" />
<stop offset="4%" stop-color ="#ffb3ff" />
<stop offset="12.25%" stop-color ="#ff33ff" />
<stop offset="31.25%" stop-color ="#800080" />
<stop offset="50%" stop-color ="#b300b3" />
</radialGradient>
</defs>
<g id="gr1" >
<rect id="rect1" fill="url(#radGrad)" x="5%" y="5%" width="95%" height="95%" rx="10%"/>
<text class="txt" x="50%" y="60%"> Sun shine </text>
</g>
<animate xlink:href="#radGrad"
attributeName="fy"
dur="2s"begin="gr1.click"
values="0%;50%;50%;100%;0%"
keyTimes="0;0.1;0.5;0.9;1"
repeatCount="1"
restart="whenNotActive" />
<animate xlink:href="#radGrad"
attributeName="fx"
dur="2s"begin="gr1.click"
values="0%;50%;50%;100%;0%"
keyTimes="0;0.1;0.5;0.9;1"
repeatCount="1"
restart="whenNotActive" />
</svg>
</div>
使用 CSS 变量和新的 @property
we can easily animate radial-gradient
(or any kind of gradient). The support 目前仅涵盖 Chrome 和 Edge。
@property --x {
syntax: '<percentage>';
inherits: false;
initial-value: 0%;
}
#shine-div {
height: 30vh;
width: 60vw;
margin: auto;
border-radius: 10px;
background: radial-gradient(ellipse farthest-corner at var(--x) 0%, #FFFFFF 0%, #ffb3ff 8%, #ff33ff 25%, #800080 62.5%, #b300b3 100%);
animation: colorChange 5s infinite alternate;
}
@keyframes colorChange {
0% {
--x:0%;
}
50% {
--x:50%;
}
100% {
--x:100%;
}
}
<div id="shine-div"></div>
我们所要做的就是使用变量 --x
定义位置,该变量将使用百分比值,然后我们为该变量设置动画。就这么简单!