如何在不使用背景位置的情况下为线性渐变设置动画?
How to animate linear-gradient without using background-position?
我正在尝试创建内容加载器,但遇到了背景动画的性能问题。
当屏幕上只有几个元素时它很流畅,但在将存根元素数增加到 20-30 时 fps 会急剧下降。
现在我知道动画背景位置 属性 是个坏主意,最好为此使用变换。但我该怎么做呢?
我想保持无缝动画。渐变应与屏幕相关,而不是与容器相关。
这是一些代码:
const cardsRoot = document.getElementById('cards')
const addButton = document.getElementById('add')
const card = document.getElementsByClassName('card')[0]
let cardsCount = 1
addButton.addEventListener('click', () => {
cardsRoot.innerHTML = ''
cardsCount++
for (let i = 0; i < cardsCount; i++) {
let cardClone = card.cloneNode(true)
cardsRoot.appendChild(cardClone)
}
})
body {
padding: 40px;
}
.card {
display: flex;
margin-top: 20px;
}
.stub {
width: 300px;
height: 12px;
margin: 8px;
border-radius: 8px;
background: linear-gradient(to right, rgba(0, 0, 0, 0.04), rgba(0, 0, 0, 0.1) 10%, rgba(0, 0, 0, 0.04) 20%) fixed;
animation: stub 1.3s linear infinite;
margin-bottom: 8px;
}
.circle {
width: 40px;
height: 40px;
margin-right: 12px;
border-radius: 20px;
}
@keyframes stub {
0% { background-position: 0vw; }
100% { background-position: 100vw; }
}
<button id="add">
ADD CARD
</button>
<div id="cards">
<div class="card">
<div>
<div class="stub circle"></div>
</div>
<div>
<div class="stub"></div>
<div class="stub"></div>
<div class="stub"></div>
</div>
</div>
</div>
您可以在应用翻译的地方使用伪元素替换动画。诀窍是考虑用固定元素替换 background-attachment:fixed
,然后让元素比屏幕大两倍,然后从左向右平移它。
const cardsRoot = document.getElementById('cards')
const addButton = document.getElementById('add')
const card = document.getElementsByClassName('card')[0]
let cardsCount = 1
addButton.addEventListener('click', () => {
cardsRoot.innerHTML = ''
cardsCount++
for (let i = 0; i < cardsCount; i++) {
let cardClone = card.cloneNode(true)
cardsRoot.appendChild(cardClone)
}
})
body {
padding: 40px;
}
.card {
display: inline-flex;
margin-top: 20px;
}
.stub {
width: 150px;
height: 12px;
margin: 8px;
border-radius: 8px;
margin-bottom: 8px;
position:relative;
z-index:0;
/*overflow:hidden; this is no more working, using mask instead */
-webkit-mask:linear-gradient(#fff 0 0);
/* OR clip-path:inset(0) */
}
.stub:before {
content:"";
position:fixed;
z-index:-1;
top:0;
right:0;
width:200vw;
bottom:0;
background:
linear-gradient(rgba(0, 0, 0, 0.04),rgba(0, 0, 0, 0.04)) left/50% 100%,
linear-gradient(to right, rgba(0, 0, 0, 0.04), rgba(0, 0, 0, 0.1) 10%, rgba(0, 0, 0, 0.04) 20%) right/50% 100%;
background-repeat:no-repeat;
animation: stub 1.3s linear infinite;
pointer-events:none;
}
.circle {
width: 40px;
height: 40px;
margin-right: 12px;
border-radius: 20px;
}
@keyframes stub {
0% { transform:translate(0); }
100% { transform:translate(50%); }
}
<button id="add">
ADD CARD
</button>
<div id="cards">
<div class="card">
<div>
<div class="stub circle"></div>
</div>
<div>
<div class="stub"></div>
<div class="stub"></div>
<div class="stub"></div>
</div>
</div>
<div class="card">
<div>
<div class="stub circle"></div>
</div>
<div>
<div class="stub"></div>
<div class="stub"></div>
<div class="stub"></div>
</div>
</div>
</div>
为了更好地理解这里发生的事情是一个简化版本,其中只有一个元素,我还更改了渐变颜色。
body:before {
content:"";
position:fixed; /*relative to the screen*/
z-index:-1;
top:0;
right:0;
width:200vw; /*2x100vw*/
bottom:0;
background:
/*will cover the left area while sliding*/
linear-gradient(red,red) left/50% 100%, /*the red should be green*/
/*the main gradient*/
linear-gradient(to right, green, blue 10%, green 20%) right/50% 100%;
background-repeat:no-repeat;
animation: stub 3s linear infinite;
}
@keyframes stub {
0% { transform:translate(0); }
100% { transform:translate(50%); } /*50% will be 200vw/2 = 100vw*/
}
相关了解背景值背后的技巧:Using percentage values with background-position on a linear-gradient
我正在尝试创建内容加载器,但遇到了背景动画的性能问题。 当屏幕上只有几个元素时它很流畅,但在将存根元素数增加到 20-30 时 fps 会急剧下降。 现在我知道动画背景位置 属性 是个坏主意,最好为此使用变换。但我该怎么做呢? 我想保持无缝动画。渐变应与屏幕相关,而不是与容器相关。
这是一些代码:
const cardsRoot = document.getElementById('cards')
const addButton = document.getElementById('add')
const card = document.getElementsByClassName('card')[0]
let cardsCount = 1
addButton.addEventListener('click', () => {
cardsRoot.innerHTML = ''
cardsCount++
for (let i = 0; i < cardsCount; i++) {
let cardClone = card.cloneNode(true)
cardsRoot.appendChild(cardClone)
}
})
body {
padding: 40px;
}
.card {
display: flex;
margin-top: 20px;
}
.stub {
width: 300px;
height: 12px;
margin: 8px;
border-radius: 8px;
background: linear-gradient(to right, rgba(0, 0, 0, 0.04), rgba(0, 0, 0, 0.1) 10%, rgba(0, 0, 0, 0.04) 20%) fixed;
animation: stub 1.3s linear infinite;
margin-bottom: 8px;
}
.circle {
width: 40px;
height: 40px;
margin-right: 12px;
border-radius: 20px;
}
@keyframes stub {
0% { background-position: 0vw; }
100% { background-position: 100vw; }
}
<button id="add">
ADD CARD
</button>
<div id="cards">
<div class="card">
<div>
<div class="stub circle"></div>
</div>
<div>
<div class="stub"></div>
<div class="stub"></div>
<div class="stub"></div>
</div>
</div>
</div>
您可以在应用翻译的地方使用伪元素替换动画。诀窍是考虑用固定元素替换 background-attachment:fixed
,然后让元素比屏幕大两倍,然后从左向右平移它。
const cardsRoot = document.getElementById('cards')
const addButton = document.getElementById('add')
const card = document.getElementsByClassName('card')[0]
let cardsCount = 1
addButton.addEventListener('click', () => {
cardsRoot.innerHTML = ''
cardsCount++
for (let i = 0; i < cardsCount; i++) {
let cardClone = card.cloneNode(true)
cardsRoot.appendChild(cardClone)
}
})
body {
padding: 40px;
}
.card {
display: inline-flex;
margin-top: 20px;
}
.stub {
width: 150px;
height: 12px;
margin: 8px;
border-radius: 8px;
margin-bottom: 8px;
position:relative;
z-index:0;
/*overflow:hidden; this is no more working, using mask instead */
-webkit-mask:linear-gradient(#fff 0 0);
/* OR clip-path:inset(0) */
}
.stub:before {
content:"";
position:fixed;
z-index:-1;
top:0;
right:0;
width:200vw;
bottom:0;
background:
linear-gradient(rgba(0, 0, 0, 0.04),rgba(0, 0, 0, 0.04)) left/50% 100%,
linear-gradient(to right, rgba(0, 0, 0, 0.04), rgba(0, 0, 0, 0.1) 10%, rgba(0, 0, 0, 0.04) 20%) right/50% 100%;
background-repeat:no-repeat;
animation: stub 1.3s linear infinite;
pointer-events:none;
}
.circle {
width: 40px;
height: 40px;
margin-right: 12px;
border-radius: 20px;
}
@keyframes stub {
0% { transform:translate(0); }
100% { transform:translate(50%); }
}
<button id="add">
ADD CARD
</button>
<div id="cards">
<div class="card">
<div>
<div class="stub circle"></div>
</div>
<div>
<div class="stub"></div>
<div class="stub"></div>
<div class="stub"></div>
</div>
</div>
<div class="card">
<div>
<div class="stub circle"></div>
</div>
<div>
<div class="stub"></div>
<div class="stub"></div>
<div class="stub"></div>
</div>
</div>
</div>
为了更好地理解这里发生的事情是一个简化版本,其中只有一个元素,我还更改了渐变颜色。
body:before {
content:"";
position:fixed; /*relative to the screen*/
z-index:-1;
top:0;
right:0;
width:200vw; /*2x100vw*/
bottom:0;
background:
/*will cover the left area while sliding*/
linear-gradient(red,red) left/50% 100%, /*the red should be green*/
/*the main gradient*/
linear-gradient(to right, green, blue 10%, green 20%) right/50% 100%;
background-repeat:no-repeat;
animation: stub 3s linear infinite;
}
@keyframes stub {
0% { transform:translate(0); }
100% { transform:translate(50%); } /*50% will be 200vw/2 = 100vw*/
}
相关了解背景值背后的技巧:Using percentage values with background-position on a linear-gradient