如何使用 CSS、JS 沿曲线对齐 HTML 元素(图标)
Posted
技术标签:
【中文标题】如何使用 CSS、JS 沿曲线对齐 HTML 元素(图标)【英文标题】:How to align HTML elements(icons) along the curve using CSS, JS 【发布时间】:2021-11-16 14:12:07 【问题描述】:大家好,
无法找到沿曲线对齐这些 png 图标的方法。我正在为此寻找 CSS 或(和)javascript 解决方案。关于如何做到这一点的任何想法?
<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;
【问题讨论】:
你需要一个方程来生成这样的曲线,然后使用计算出的坐标绝对定位图标。 你是怎么画曲线的?如果您有图像,请测量与图像相关的所有内容并以百分比形式定位所有图标 - 这样它就可以响应。但是如果你的曲线随着视口的变化而变化,那就不同了。包括到目前为止的代码,以便我们查看。 @AHaworth,它是一个 SVG 文件,是的,我认为它会随着视口而改变。 请向我们展示您的代码,包括 svg。这将取决于它如何变化。 @AHaworth 刚刚更新 【参考方案1】:您可以使用合适的公式来计算绝对坐标。使用 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, $ypx)`;
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 文件,无论如何我可以使用 SVG 或其路径生成用于定位的曲线? 理论上你可以从 SVG 中提取路径,解析它的坐标并使用它们。在实践中,SVG 将是固定大小或以线性方式改变大小,这两种情况都可以通过调整曲线方程来处理。 @Dave 编辑了我的答案以使其具有响应性。【参考方案2】:如果 svg 完整显示,则可以相对于它完成整个布局 - 在 CSS 中计算每个图标的 % 位置。
这个 sn-p 有 svg 的纵横比和每个图标的位置从被测量。 CSS calc 然后产生 % 距离。尺寸在宽度上逐渐减小,图标之间的距离是恒定的。
此 sn-p 中的测量值并非绝对准确,仅用于此演示。你可能想自己做。
*
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>
【讨论】:
以上是关于如何使用 CSS、JS 沿曲线对齐 HTML 元素(图标)的主要内容,如果未能解决你的问题,请参考以下文章
CSS:有没有办法在每个列表元素之前垂直对齐数字/项目符号?
CSS:有没有办法在每个列表元素之前垂直对齐数字/项目符号?
CSS:有没有办法在每个列表元素之前垂直对齐数字/项目符号?