The correct formula should be (20px / cos(45deg)) * N
. Then you can make the background-size
to be 200% 100%
(twice bigger than the element) and you animate it from left to right:
li {
display: inline-block;
width: calc( (20px / 0.707) * 3); /*cos(45deg) = 0.707*/
height: 50px;
margin-bottom:10px;
background-color: blue;
background-image: repeating-linear-gradient(-45deg, transparent, transparent 10px, black 10px, black 20px);
background-size: 200% 100%;
background-color: blue;
animation: loading-slide 3s linear infinite;
}
@keyframes loading-slide {
from {
background-position: left;
}
to {
background-position: right;
}
}
.alt li {
width: calc( (20px / 0.707) * 6);
}
<ul>
<li>test</li><li>test</li>
</ul>
<ul class="alt">
<li>test</li><li>test</li>
</ul>
You can consider any degree and adjust the formula as needed. (20px / cos(90deg - |Xdeg|)) * N
with X
between -90deg
and 90deg
Example with -60deg
li {
display: inline-block;
width: calc((20px / 0.866) * var(--n,3)); /*cos(30deg) = 0.866*/
height: 50px;
margin-bottom:10px;
background-color: blue;
background-image: repeating-linear-gradient(-60deg, transparent, transparent 10px, black 10px, black 20px);
background-size: 200% 100%;
background-color: blue;
animation: loading-slide 3s linear infinite;
}
@keyframes loading-slide {
from {
background-position: left;
}
to {
background-position: right;
}
}
.alt li {
--n:6;
}
<ul>
<li>test</li><li>test</li>
</ul>
<ul class="alt">
<li>test</li><li>test</li>
</ul>
Example with 30deg
li {
display: inline-block;
width: calc((20px / 0.5) * var(--n,8)); /*cos(60deg) = 0.5*/
height: 50px;
margin-bottom:10px;
background-color: blue;
background-image: repeating-linear-gradient(30deg, transparent, transparent 10px, black 10px, black 20px);
background-size: 200% 100%;
background-color: blue;
animation: loading-slide 3s linear infinite;
}
@keyframes loading-slide {
from {
background-position: left;
}
to {
background-position: right;
}
}
.alt li {
--n:12;
}
<ul>
<li>test</li><li>test</li>
</ul>
<ul class="alt">
<li>test</li><li>test</li>
</ul>
Example with 80deg
li {
display: inline-block;
width: calc((20px / 0.9848) * var(--n,8)); /*cos(10deg) = 0.9848*/
height: 50px;
margin-bottom:10px;
background-color: blue;
background-image: repeating-linear-gradient(80deg, transparent, transparent 10px, black 10px, black 20px);
background-size: 200% 100%;
background-color: blue;
animation: loading-slide 3s linear infinite;
}
@keyframes loading-slide {
from {
background-position: left;
}
to {
background-position: right;
}
}
.alt li {
--n:12;
}
<ul>
<li>test</li><li>test</li>
</ul>
<ul class="alt">
<li>test</li><li>test</li>
</ul>
You can clearly identify the trivial case where X=+/-90deg
(vertical stripes) and we will have cos(0)=1
thus the formula will be 20px * N
. Also when X=0
(horizontal stripes) we will have cos(90deg) = 0
and any width will work since there is no vertical pattern (the formula is no more defined)
li {
display: inline-block;
width: calc(20px * var(--n,8));
height: 50px;
margin-bottom:10px;
background-color: blue;
background-image: repeating-linear-gradient(90deg, transparent, transparent 10px, black 10px, black 20px);
background-size: 200% 100%;
background-color: blue;
animation: loading-slide 3s linear infinite;
}
@keyframes loading-slide {
from {
background-position: left;
}
to {
background-position: right;
}
}
.alt li {
background-image:repeating-linear-gradient(0deg, transparent, transparent 10px, black 10px, black 20px);
}
<ul>
<li>test</li><li>test</li>
</ul>
<ul class="alt">
<li>test</li><li>test</li>
</ul>
What about value outside [-90deg,90deg]
?
The above range already cover 180deg
and since we are dealing with something symetric, all the value can be represented inside that range.
Example: 110deg
is the same as -70deg
li {
display: inline-block;
width: calc((20px / 0.9396) * var(--n,8)); /*cos(20deg) = 0.9396*/
height: 50px;
margin-bottom:10px;
background-color: blue;
background-image: repeating-linear-gradient(110deg, transparent, transparent 10px, black 10px, black 20px);
background-size: 200% 100%;
background-color: blue;
animation: loading-slide 3s linear infinite;
}
.alt li {
--n:12;
background-image: repeating-linear-gradient(-70deg, transparent, transparent 10px, black 10px, black 20px);
}
@keyframes loading-slide {
from {
background-position: left;
}
to {
background-position: right;
}
}
<ul>
<li>test</li><li>test</li>
</ul>
<ul class="alt">
<li>test</li><li>test</li>
</ul>
Example: -150deg
is the same as 30deg
li {
display: inline-block;
width: calc((20px / 0.5) * var(--n,4)); /*cos(60deg) = 0.5*/
height: 50px;
margin-bottom:10px;
background-color: blue;
background-image: repeating-linear-gradient(-150deg, transparent, transparent 10px, black 10px, black 20px);
background-size: 200% 100%;
background-color: blue;
animation: loading-slide 3s linear infinite;
}
.alt li {
--n:6;
background-image: repeating-linear-gradient(30deg, transparent, transparent 10px, black 10px, black 20px);
}
@keyframes loading-slide {
from {
background-position: left;
}
to {
background-position: right;
}
}
<ul>
<li>test</li><li>test</li>
</ul>
<ul class="alt">
<li>test</li><li>test</li>
</ul>
basically we add/remove 180deg
until we get inside [-90deg,90deg]
in order to be able to apply the formula.
Check this answer for more details about how background-size
/background-position
works: Using percentage values with background-position on a linear-gradient
Another Approach
Here is a complete different idea where you can rely on skew
transformation and pseudo element. The trick here is that you don't have to define the width based on the stripes but the stripes will follow the width you will define so it will be easier to handle.
li {
display: inline-block;
width: calc( 20px * 3); /* it's only 20px * N */
height: 50px;
margin-bottom:10px;
background-color: blue;
position:relative;
z-index:0;
overflow:hidden
}
li::before {
content:"";
position:absolute;
top:0;
bottom:0;
left:0;
width:400%;
/*we keep 0deg in the gradient*/
background-image: repeating-linear-gradient(90deg, transparent, transparent 10px, black 10px, black 20px);
transform:skewX(30deg);
transform-origin:bottom left;
animation: loading-slide 4s linear infinite;
}
@keyframes loading-slide {
to {
transform: translateX(-50%) skewX(30deg);
}
}
.alt li {
width: calc( 20px * 6);
}
<ul>
<li>test</li><li>test</li>
</ul>
<ul class="alt">
<li>test</li><li>test</li>
</ul>
As you can see, we keep a vertical gradient, we define the width of the element based on the width of the gradient. We make the pseudo element big enough and we apply a translation on it. The only thing you need to adjust is the skew transformation to control the degree.
With this approach you will also have better performance since you will animate transform instead of background-size
.
More examples:
li {
display: inline-block;
width: calc( 20px * var(--n,3)); /* it's only 20px * N */
height: 50px;
margin-bottom:10px;
background-color: blue;
position:relative;
z-index:0;
overflow:hidden
}
li::before {
content:"";
position:absolute;
top:0;
bottom:0;
left:-400%;
right:-800%;
/*we keep 0deg in the gradient*/
background-image: repeating-linear-gradient(90deg, transparent, transparent 10px, black 10px, black 20px);
transform:skewX(var(--d,30deg));
animation: loading-slide 12s linear infinite;
}
@keyframes loading-slide {
to {
transform: translateX(-50%) skewX(var(--d,30deg));
}
}
<ul>
<li>test</li><li>test</li>
</ul>
<ul style="--n:6;--d:45deg">
<li>test</li><li>test</li>
</ul>
<ul style="--n:8;--d:-70deg">
<li>test</li><li>test</li>
</ul>
<ul style="--n:8;--d:30deg">
<li>test</li><li>test</li>
</ul>