【问题标题】:How to create an infinite background pattern animation using linear-gradient?如何使用线性渐变创建无限背景图案动画?
【发布时间】:2019-02-27 15:46:18
【问题描述】:

我正在尝试创建一个动画重复模式(斜条纹水平滑动),作为加载块的占位符(在本例中为li)。

如何使动画平滑/连续,从而产生图案无限滑动的错觉?

  • 如何计算元素width,使得模式是连续的? (条纹不应看起来破损/中断)。
  • 如何让它看起来像它没有重新启动而是无限滑动一样循环? (100% 的帧应该毫无故障地传递到 0% 的帧)

目标是有一个可以添加到任何块中的类,并且在视觉上看起来像加载/处理。

注意:没有JS;纯 CSS。

li {
  display: inline-block;
  width: calc(20px * 8); /* how to calculate this, relative to the width (of the pattern or the step), to achieve pattern continuity exactly?
    Of course without doing trying&error to know it should be 24.75px * 8.
  */
  height: 200px;
  background-color: blue;

  background-image: repeating-linear-gradient(-45deg, transparent, transparent 10px, black 10px, black 20px);
  animation: loading-slide 1s linear infinite;

}
  @keyframes loading-slide {
    from { background-position: 0% 0% }
    to { background-position: 100% 0% }
  }
<ul>
    <li>test
    <li>test
</ul>

【问题讨论】:

  • 我在下面的公式中犯了一个小错误,现在它是正确的......我正在乘以 cos,它给出了正确的结果但不是正确的条纹数。视觉上两者是等价的,但划分更准确
  • 我已经编辑以包含另一种方法;)可能更容易处理
  • 感谢您的奉献、每日编辑和更正。这是一个很好的答案☺️

标签: css css-animations linear-gradients repeating-linear-gradient


【解决方案1】:

正确的公式应该是(20px / cos(45deg)) * N。然后您可以将background-size 设为200% 100%(比元素大两倍),然后从左到右对其进行动画处理:

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>

您可以考虑任何程度并根据需要调整公式。 (20px / cos(90deg - |Xdeg|)) * NX-90deg90deg 之间

-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>

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>

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>

您可以清楚地识别X=+/-90deg(垂直条纹)和我们将有cos(0)=1 的简单情况,因此公式将为20px * N。此外,当X=0(水平条纹)我们将拥有cos(90deg) = 0,并且任何宽度都可以使用,因为没有垂直图案(公式不再定义)

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>

[-90deg,90deg] 之外的价值呢?

上面的范围已经覆盖了180deg,因为我们正在处理一些对称的东西,所以所有的值都可以在这个范围内表示。

示例:110deg-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>

示例:-150deg30deg 相同

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>

基本上我们添加/删除180deg,直到我们进入[-90deg,90deg],以便能够应用公式。


查看此答案以获取有关background-size/background-position 工作原理的更多详细信息:Using percentage values with background-position on a linear-gradient


另一种方法

这是一个完全不同的想法,您可以依赖skew 转换和伪元素。这里的诀窍是您不必根据条纹定义宽度,但条纹将遵循您定义的宽度,因此更容易处理。

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>

如您所见,我们保持垂直渐变,我们根据渐变的宽度定义元素的宽度。我们使伪元素足够大,并在其上应用翻译。唯一需要调整的就是控制度数的倾斜变换。

使用这种方法,您还将获得更好的性能,因为您将动画变换而不是 background-size

更多示例:

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>

【讨论】:

  • 不确定它是否是 Chrome,但当动画随机重复并且有时会有点卡顿时,动画仍然显示带有轻微偏移的线条/中断。更大的版本更是如此。较小的看起来更平滑,但也显示相同,只是不像较大的那样频繁。也许只是我的浏览器。
  • @Nope 不确定,我也在 Chrome 和 firefox 上进行测试(看起来都很好)。
  • 试图找到一个不同的解决方案,但这个答案真的很好。
  • @Persijn 谢谢,我有另一个解决方案,在伪元素上使用倾斜变换,这将使计算更容易,我可能稍后会添加它,不确定
  • @TemaniAfif 正在考虑为它制作一个 svg 解决方案,但我认为路径动画将变得复杂且难以制作。
猜你喜欢
  • 2020-02-08
  • 2021-05-14
  • 1970-01-01
  • 2020-06-13
  • 2022-10-14
  • 2021-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多