I'm trying to create content loader but got a performance problem with background animation. It's smooth when there are only a few elements on the screen but dramatically drops fps while increasing stub elements count to 20-30. Now I know that animating background-position property is a bad idea and it is better to use transforms for this. but how can I do this? I'd like to keep seamless animation. Gradient should be relative to screen, not to container.
Here is some code:
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>
And demo: https://jsfiddle.net/3da4uzm2/57/