具有自定义逻辑的弯曲无限滚动或选框

问题描述 投票:0回答:1

我一直在努力构建这个(如图所示)。我想制作一个弯曲的选框或无限滚动轮播,其中每个项目(在本例中为标志)将从左向右移动。当标志进入视口中心时,在这种情况下进入窗口区域 - 窗口背景将被更改。我该如何构建这个?如有任何疑问,请告诉我。

注意:任何第三方库(如 gsap)都可以使用,我没有问题。

enter image description here

javascript html css reactjs gsap
1个回答
0
投票

这是一个基本想法。 每个标志都位于 div 的“末尾”作为背景图像。

每个 div 都按照您决定的宽度居中放置,并与下一个标志围绕您定义的圆弧放置一定距离。

然后计算 div 的高度,以使该距离在它们从中心点旋转放置时发生。

然后整体无限旋转。

顶部矩形的颜色变化是单独完成的,但动画持续时间相同。

此关键帧将 CSS 变量 --bg 设置为与第一个、第二个等标志相关的背景颜色。

此设置仅在 CSS 中作为演示。在现实生活中,我会实现一些 JS 来减少设置的繁琐,因此可以从 DOM 中获取标志数量并相应地设置关键帧。

我担心 CPU 使用率,但即使在没有高级 GPU 的简单笔记本电脑上,它似乎也只有百分之几。

body {
  margin: 0;
  display: flex;
  flex-direction: column;
  width: 100vw;
  justify-content: center;
  position: relative;
  align-items: center;
  overflow: hidden;
}

.flags-container {
  overflow: hidden;
  clip-path: polygon(0 0, 100% 0, 100% 25%, 0 25%);
  position: relative;
  --num: 20;
  /* number of flags */
  --a: 10vmin;
  /* set this to the distance along the arc between two flags that you want */
  --r: calc(2 * var(--a) * var(--num) / pi);
  --w: calc(2 * var(--r));
  width: var(--w);
  aspect-ratio: 1;
  top: 15vmin;
  display: block;
}

.flags-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 10%;
  aspect-ratio: 2 / 1;
  animation: color 60s infinite linear;
  z-index: -1;
  background-color: var(--bg);
}

@keyframes color {
  0% {
    --bg: red;
  }
  5% {
    --bg: green;
  }
  10% {
    --bg: blue;
  }
  15% {
    --bg: black;
  }
  20% {
    --bg: cyan;
  }
  25% {
    --bg: magenta;
  }
  30% {
    --bg: yellow;
  }
  35% {
    --bg: red;
  }
  40% {
    --bg: green;
  }
  45% {
    --bg: blue;
  }
  50% {
    --bg: black;
  }
  55% {
    --bg: cyan;
  }
  60% {
    --bg: magenta;
  }
  65% {
    --bg: yellow;
  }
  70% {
    --bg: red;
  }
  75% {
    --bg: green;
  }
  80% {
    --bg: blue;
  }
  85% {
    --bg: black;
  }
  90% {
    --bg: cyan;
  }
  95% {
    --bg: magenta;
  }
  100% {
    --bg: red;
  }
}

.flags {
  width: 100%;
  height: 100%;
  position: relative;
  animation: rotate 60s infinite linear;
  top: 1vmin;
}

@keyframes rotate {
  from {
    transform: rotate(0);
  }
  to {
    transform: rotate(360deg);
  }
}

.flags>* {
  width: 5%;
  height: var(--r);
  position: absolute;
  top: 0;
  left: 50%;
  transform-origin: center bottom;
  transform: translateX(-50%) rotate(calc((var(--n) - 1) * 360deg / var(--num)));
  --bgi: url(https://i.sstatic.net/Yjh0wFnx.webp);
  background-image: var(--bgi);
  background-size: 100% auto;
  background-position: center top;
  background-repeat: no-repeat;
}

.flags>*:nth-child(1) {
  --n: 1;
  --bgi: url(https://i.sstatic.net/Yjh0wFnx.webp);
  /* REMEMBER to set --bgi for each flag */
}

.flags>*:nth-child(2) {
  --n: 2;
}

.flags>*:nth-child(3) {
  --n: 3;
}

.flags>*:nth-child(4) {
  --n: 4;
}

.flags>*:nth-child(5) {
  --n: 5;
}

.flags>*:nth-child(6) {
  --n: 6;
}

.flags>*:nth-child(7) {
  --n: 7;
}

.flags>*:nth-child(8) {
  --n: 8;
}

.flags>*:nth-child(9) {
  --n: 9;
}

.flags>*:nth-child(10) {
  --n: 10;
}

.flags>*:nth-child(11) {
  --n: 11;
}

.flags>*:nth-child(12) {
  --n: 12;
}

.flags>*:nth-child(13) {
  --n: 13;
}

.flags>*:nth-child(14) {
  --n: 14;
}

.flags>*:nth-child(15) {
  --n: 15;
}

.flags>*:nth-child(16) {
  --n: 16;
}

.flags>*:nth-child(17) {
  --n: 17;
}

.flags>*:nth-child(18) {
  --n: 18;
}

.flags>*:nth-child(19) {
  --n: 19;
}

.flags>*:nth-child(20) {
  --n: 20;
}
<div class="flags-container">
  <div class="bg"></div>
  <div class="flags">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
</div>
<style>
  .mask1 {
    mask-image: linear-gradient(black 0 100px, transparent 100px 100%);
    mask-size: 100px 100px;
    mask-repeat: no-repeat;
    mask-position: 50% 10%;
    background-image: conic-gradient(red, yellow, blue, green);
    width: 600px;
    height: 300px;
  }

© www.soinside.com 2019 - 2024. All rights reserved.