如何使用 CSS、JS 沿曲线对齐 HTML 个元素(图标)

How to align HTML elements(icons) along the curve using CSS, JS

大家好,

无法找到沿曲线对齐这些 png 图标的方法。我正在为此寻找 CSS 或(和)Javascript 解决方案。有什么想法吗?

HTML

<div class="container">
  <div class="svg-curve">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 141">
      <path class="layer-1"
        d="M0,32c9.8,2.43,22.75,5.55,38,9,16,3.62,47.89,10.63,89,18,9,1.62,47.71,8.49,112,17,29.43,3.9,82.81,10.9,153,17,85.18,7.41,149.55,9.54,196,11,114.72,3.62,201,1.55,222,1,104.73-2.73,182.88-9.34,202-11,26-2.26,87.86-8,167-19,5.39-.75,32.57-5.1,66.52-10.53,22.55-3.61,45.94-7.39,52.48-8.47,27.81-4.59,72.7-13.43,142-32h0V0H0Z" />
      <path class="layer-2"
        d="M0,95c14.71,2.7,35.31,6.28,60,10,18.28,2.75,39.79,5.58,86.06,11,26.82,3.14,61.67,7.22,103.07,11,65.61,6,115.62,8.3,153.11,10,52.28,2.36,112.79,4,180.12,4,37.5,0,96.71-.13,175.12-4,28.61-1.4,91.33-4.87,172.12-13,65-6.54,130.95-13.26,217.15-29,55.91-10.19,98.43-20.15,123.09-26,67.74-16,125.3-32.33,170.12-46.07L1242.86,64.07h0c-59.38,10.1-139.89,21.83-236.16,30-13.44,1.13-52,4.4-106.08,7-129.63,6.2-240.37,5.09-326.22,2C295.06,93,113.9,56.09,71.05,47.09c-29.73-6.24-54.26-12-71-16Z" />
    </svg>
  </div>
</div>

CSS

    .container {
      margin:0;
      padding:0;
      position:relative;
    }
    .svg-curve {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      overflow: hidden;
    }

    .svg-curve svg {
      position: relative;
      display: block;
      height: 200px;
    }

    .svg-curve svg .layer-1 {
      fill: red;
    }

    .svg-curve svg .layer-2 {
      fill: blue;
    }

并且根据屏幕大小,SVG 高度将更改如下:

@media (min-width: 576px) {
      .svg-curve svg {
        height: 90px;
      }
    }

    @media (min-width: 768px) {
      .svg-curve svg {
        height: 120px;
      }
    }

    @media (min-width: 992px) {
      .svg-curve svg {
        height: 150px;
      }
    }

    @media (min-width: 1400px) {
      .svg-curve svg {
        height: 200px;
      }
    }

您可以使用合适的方程来计算绝对坐标。使用 CSS 无法做到这一点,因为您不能首先使用 CSS 定义曲线。

示例代码如下:

function curve(x) {
  const dx = 400;
  const dy = 100;
    return -0.0004 * (x - dx) * (x - dx) + dy;
}

for (let i = 0; i < 10; i++) {
    const div = document.createElement("div");
  div.classList.add('icon');
  const x = i * window.innerWidth / 10;
  const y = curve(x);
  div.style.transform = `translate(0, ${y}px)`;
  document.getElementById('curve').append(div);
}
#curve {
  position: relative;
  display: flex;
  justify-content: space-between;
}

#curve .icon {
  width: 30px;
  height: 30px;
  border: 1px solid grey;
}
<div id="curve"></div>

如果 svg 完整显示,则整个布局可以相对于它完成 - 每个图标的百分比位置在 CSS 中计算。

此代码段具有 svg 的纵横比和每个图标的位置,这些图标来自测量。 CSS calc 然后生成百分比距离。尺寸在宽度上逐渐变细,图标之间的距离保持不变。

此代码段中的测量值并非绝对准确,只是为了演示而添加的。您可能想自己做。

* {
  padding: 0;
  margin: 0;
}
    .container {
      --svgAspectRatio: calc(1440 / 141);
      margin:0;
      padding:0;
      position:relative;
      width: 100vw;
      height: calc(100vw / var(--svgAspectRatio) );
      display: flex;
      justify-content: center;
      
    }
    .svg-curve {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      overflow: hidden;
      line-height: 0;
      background: transparent;
    }

    .svg-curve svg {
      position: relative;
      display: block;
      width: 100%;
    }

    .svg-curve svg .layer-1 {
      fill: red;
    }

    .svg-curve svg .layer-2 {
      fill: blue;
    }

    .icons {
      --measuredW: 60.96; /* the measured width of the icons picture */
      --measuredH: 10.03;
      --w: calc(100vw - 8vw);
      width: var(--w);
      height: auto;
      position: relative;
      top: 0;
      left: 0;
      display: inline-block;
    }
    .icon {
      --iconW: calc(((14 - var(--n)) / 13) * 2vw);
      width: var(--iconW);
      height: var(--iconW);
      background-color: #eeeeee; 
      display: inline-block;
      position: absolute;
      left: calc(100% * (var(--n) - 1) / 13);
      z-index: 1;
      background-size: contain;
      background-position: center center;
      background-repeat: no-repeat no-repeat;
      background-image: var(--bg);
      top: calc(var(--t) / var(--measuredH) * 100%);
      }
      .icon:nth-child(1) {
      --n: 1;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 4.6;
      }
      .icon:nth-child(2) {
      --n: 2;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 5.6;
      }
      .icon:nth-child(3) {
      --n: 3;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 6.48;
      }
      .icon:nth-child(4) {
      --n: 4;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 7.2;
      }
      .icon:nth-child(5) {
      --n: 5;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 7.8;
      }
      .icon:nth-child(6) {
      --n: 6;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 8.1;
      }
      .icon:nth-child(7) {
      --n: 7;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 8.1;
      }
      .icon:nth-child(8) {
      --n: 8;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 8.1;
      }
      .icon:nth-child(9) {
      --n: 9;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 7.8;
      }
      .icon:nth-child(10) {
      --n: 10;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 7.3;
      }
      .icon:nth-child(11) {
      --n: 11;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 6.5;
      }
      .icon:nth-child(12) {
      --n: 12;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 5.5;
      }
      .icon:nth-child(13) {
      --n: 13;
      --bg: url(https://i.stack.imgur.com/DWx67.png);
      --t: 4.5;
      }
<div class="container">
  <div class="svg-curve">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 141">
      <path class="layer-1"
        d="M0,32c9.8,2.43,22.75,5.55,38,9,16,3.62,47.89,10.63,89,18,9,1.62,47.71,8.49,112,17,29.43,3.9,82.81,10.9,153,17,85.18,7.41,149.55,9.54,196,11,114.72,3.62,201,1.55,222,1,104.73-2.73,182.88-9.34,202-11,26-2.26,87.86-8,167-19,5.39-.75,32.57-5.1,66.52-10.53,22.55-3.61,45.94-7.39,52.48-8.47,27.81-4.59,72.7-13.43,142-32h0V0H0Z" />
      <path class="layer-2"
        d="M0,95c14.71,2.7,35.31,6.28,60,10,18.28,2.75,39.79,5.58,86.06,11,26.82,3.14,61.67,7.22,103.07,11,65.61,6,115.62,8.3,153.11,10,52.28,2.36,112.79,4,180.12,4,37.5,0,96.71-.13,175.12-4,28.61-1.4,91.33-4.87,172.12-13,65-6.54,130.95-13.26,217.15-29,55.91-10.19,98.43-20.15,123.09-26,67.74-16,125.3-32.33,170.12-46.07L1242.86,64.07h0c-59.38,10.1-139.89,21.83-236.16,30-13.44,1.13-52,4.4-106.08,7-129.63,6.2-240.37,5.09-326.22,2C295.06,93,113.9,56.09,71.05,47.09c-29.73-6.24-54.26-12-71-16Z" />
    </svg>
  </div>
  <div class="icons">
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
  <div class="icon"></div>
</div>
</div>