如何使用 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>
大家好,
无法找到沿曲线对齐这些 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>