Skip to content
Advertisement

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

Good day fellas,

Can’t figure out a way to align those png icons along the curve. I’m looking for CSS or(and) Javascript solutions for this. Any ideas on how to do it?

icons aligned along the curve

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

And depending on the screen size the SVG height will be changed like this:

@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;
      }
    }

Answer

If the svg is shown in its entirety the whole layout can be done relative to that – the % positions of each icon being calculated in the CSS.

This snippet has the aspect ratio of the svg and the positions of each icon put in from being measured. CSS calc then produces the % distances. The sizes taper down across the width and the distance between icons is constant.

The measurements in this snippet are not absolutely accurate, just put in for this demo. You’ll probably want to do them for yourself.

* {
  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>
Advertisement