有没有办法在 CSS/HTML/JS 中以三角形/金字塔方式生成六边形?

Posted

技术标签:

【中文标题】有没有办法在 CSS/HTML/JS 中以三角形/金字塔方式生成六边形?【英文标题】:Is there a way to generate Hexagons in a triangular/pyramid fashion in CSS/HTML/JS? 【发布时间】:2021-11-24 15:13:32 【问题描述】:

我试图开始我的一个个人项目,我想在特定的Pattern 中生成六边形,并且每个新行都是根据用户输入生成的。我浏览了所有的 *** 答案,每个人似乎都直接在网站上制作了整个网格或只是 svg 模式。对我来说问题是我想为每个六边形设置动画并且需要访问每个六边形元素。有没有办法在 CSS/html/JS 中或一般使用其他语言来做到这一点。

【问题讨论】:

您也可以访问每个element using svg。除非您想选择canvas,否则我想您必须在 HTML 中使用两个元素 - 一个旋转 - 用于每个六边形或 css3。 你用普通的div元素和clip-path调查过吗? 我认为 css3 或 svg 可以工作,但我怎样才能每次都生成一个新行.. @AHaworth 是的,我花了一整天的时间尝试,但如果我遗漏了什么,你可以将我与我联系起来,再次感谢 很快就会提出建议作为答案。 【参考方案1】:

您可以将模式存储到一个数组中,然后通过该数组动态循环创建元素。

只需创建一个容器 div,然后动态创建行并将六边形放入行中,然后将行附加到容器中。

const container = document.querySelector('.container');
const hexagonPattern = [1, 2, 3, 4];

for (let i = 0; i < hexagonPattern.length; i++) 
    const row = document.createElement('div');
    row.classList.add('row');
     for (let j = 0; j < hexagonPattern[i]; j++) 
          const hexagon = document.createElement('div');
          hexagon.classList.add('hexagon');
          row.appendChild(hexagon);
      
      container.appendChild(row);
.container 
    display: flex;
     flex-direction: column;
     align-items: center;
   
     
   .row 
     margin-bottom: -30px;
   
   
   .hexagon 
     display: inline-block;
     box-shadow: 10px 10px 5px #000;
     width: 100px; 
     height: 100px;
     background: grey;
     -webkit-clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
     transition: .7s;
     margin: 2px;
   
   .hexagon:hover 
     background: red;
     transform: rotateY(-180deg);
     transition: .7s;
   
  <div class="container">
  </div>

【讨论】:

这是一个简单而准确的形式,非常感谢您的帮助! 如果有帮助,请考虑接受它作为答案并投票 我想这样做,但我没有足够的声誉是它所说的,但当我获得足够的声誉时肯定会这样做。【参考方案2】:

您可以结合使用 CSS 剪辑路径和对几何图形的基本了解来获得正确的位置。假设您要定义单个六边形的宽度,则高度与宽度的比率为1.157...(准确地说是2 / Math.sqrt(3)),但为了便于计算,我们将其四舍五入为1.2

六边形(长对角线垂直)的 CSS 剪辑路径是:

clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);

然后就是应用这些计算来获得正确的布局。我在下面的示例中使用了 CSS 自定义属性,因此您可以在需要时调整位置。

.stage 
  --cell-width: 100px;
  --cell-height: calc(var(--cell-width) * 1.2);
  --cell-spacing: 4px;
  
  padding-top: calc(var(--cell-width) * 0.25);
  padding-bottom: calc(var(--cell-width) * 0.25);
  background-color: #ddd;


.row 
  display: flex;
  justify-content: center;
  margin-top: calc(var(--cell-width) * -0.27 + var(--cell-spacing));
  margin-bottom: calc(var(--cell-width) * -0.27 + var(--cell-spacing));


.cell 
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  background-color: steelblue;
  width: var(--cell-width);
  height: var(--cell-height);
  margin-left: var(--cell-spacing);
  margin-right: var(--cell-spacing);
<div class="stage">
  <div class="row">
    <div class="cell"></div>
  </div>
  <div class="row">
    <div class="cell"></div>
    <div class="cell"></div>
  </div>
  <div class="row">
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
  </div>
  <div class="row">
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
  </div>
</div>

【讨论】:

谢谢你的详细解释,上面的答案更有意义。谢谢老哥【参考方案3】:

您可以使用剪辑路径多边形将元素制作成六边形。

然后根据用户输入,您可以创建任意数量的六边形并将它们并排放置在新行中。

这个sn-p是一个简化版,它在点击时创建一个六边形并将其放在一行中。

它使用 CSS 变量来定义六边形的边长,因此您可以轻松更改。

const row = document.querySelector('.row');

function createHexagon() 
  const hexagon = document.createElement('div');
  hexagon.classList.add('hexagon');
  return hexagon;
.hexagon 
  --sin30: 0.5;
  --side: 10vmin;
  --x: calc(var(--side) * var(--sin30));
  background-color: gray;
  clip-path: polygon(var(--x) 0, calc(100% - var(--x)) 0, 100% 50%, calc(100% - var(--x)) 100%, var(--x) 100%, 0% 50%);
  width: calc(2 * var(--side));
  height: calc(2 * var(--side));
  display: inline-block;
  margin: 1vmin;
<div class="row"></div>
<button onclick="row.appendChild(createHexagon());">Click to add a hexagon</button>

【讨论】:

【参考方案4】:

这是我写的文章中的一个演示:https://css-tricks.com/hexagons-and-beyond-flexible-responsive-grid-patterns-sans-media-queries/

它是响应式八边形网格。在全屏上运行它以查看将回退到小屏幕上的正常网格的金字塔形网格。我邀请您阅读上述文章以了解此技术背后的技术细节。

您所要做的就是调整变量以获得您的六边形网格:

let inputs = document.querySelectorAll('input[type=range]')
let elem = document.querySelector('.main')


inputs.forEach(input => 
   input.addEventListener('change', function(e) 
      var p = e.target.getAttribute('name');
      if(p=="s" || p=="mv") 
        elem.style.setProperty("--"+p, this.value+"px");
            e.target.previousElementSibling.innerHTML = this.value+"px";
       else  
        elem.style.setProperty("--"+p, this.value);
          e.target.previousElementSibling.innerHTML = this.value;
      
    );
);
.main 
  display:flex;
  --s: 100px; /* size */
  --r: 1; /* ratio */
  /* clip-path */
  --h: 0.25;  
  --v: 0.35; 
  --hc:calc(clamp(0,var(--h),0.5) * var(--s)) ;
  --vc:calc(clamp(0,var(--v),0.5) * var(--s) * var(--r)); 
  
  /*margin */
  --mv: 4px; /* vertical */
  --mh: calc(var(--mv) + (var(--s) - 2*var(--hc))/2); /* horizontal */
  /* for the float*/
  --f: calc(2*var(--s)*var(--r) + 4*var(--mv)  - 2*var(--vc) - 2px);
  --nr:6;
  --lw:calc(var(--nr)*(var(--s) + 2*var(--mh)));


.container 
  font-size: 0; /*disable white space between inline block element */
  max-width:var(--lw);
  margin:0 auto;


.container div 
  width: var(--s);
  margin: var(--mv) var(--mh);
  height: calc(var(--s)*var(--r)); 
  display: inline-block;
  font-size:initial;
  clip-path: polygon(var(--hc) 0, calc(100% - var(--hc)) 0,100% var(--vc),100% calc(100% - var(--vc)), calc(100% - var(--hc)) 100%,var(--hc) 100%,0 calc(100% - var(--vc)),0 var(--vc));
  background: red;
  margin-bottom: calc(var(--mv) - var(--vc)); 

.container div:nth-child(odd) 
  background:green;



.container::before 
  content: "";
  width: clamp(0px, (var(--lw) - 100%)*1000,calc(var(--s)/2 + var(--mh)));
  float: left;
  height: 120%; 
  shape-outside: repeating-linear-gradient(#0000 0 calc(var(--f) - 3px),#000 0 var(--f));


.container i::before ,
.container i::after
  content: "";
  width: clamp(0px, (100% - var(--lw) + 1px)*1000,calc(50% - var(--mh) - var(--s)/2));
  float: left;
  height: calc(var(--f)*(var(--nr) - 1)/2);
  shape-outside: linear-gradient(to bottom right,#000 50.5%,#0000 0);

.container i::after 
  float:right;
  shape-outside: linear-gradient(to bottom left,#000 49%,#0000 0);


.panel position: fixed;top: 20px;right: 20px;padding: 10px;border: 1px solid;border-radius: 10px;background: #fff;font-family: sans-serif;opacity:.5
.panel:hover opacity:1
.panel > div:not(:last-child) border-bottom: 1px solid;padding-bottom: 10px;margin-bottom: 10px;
*,*::before transition:0.5s linear
<div class="main">
  <div class="container">
    <i></i>
    <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>
  </div>
</div>

<div class="panel">
<div>Size: [<span>100px</span>] <input type="range" min="20" max="200" step="10" value="100" name="s"></div>
<div>Ratio: [<span>1</span>] <input type="range" min="0" max="2" step="0.05" value="1" name="r"></div>
<div>Spacing: [<span>4px</span>]<input type="range" min="0" max="10" step="1" value="4" name="mv"></div>
<div>Clip-path<br>
hc: [<span>0.25</span>]<input type="range" min="0" max=".5" step=".05" value=".25" name="h"><br>
vc: [<span>0.35</span>]<input type="range" min="0" max=".5" step=".05" value=".35" name="v"></div></div>

【讨论】:

以上是关于有没有办法在 CSS/HTML/JS 中以三角形/金字塔方式生成六边形?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 JooQ 中以编程方式回滚事务?

有没有办法在 Windows 上的 C++ 中以编程方式设置环境路径?

有没有办法在黑莓中以字符串的形式获取异常的堆栈跟踪?

有没有办法在多 GPU 环境中以编程方式选择渲染 GPU? (视窗)

有没有办法在Swift中以编程方式设置NSCollectionView?

有没有办法从我的 Joomla 组件中以编程方式添加菜单项?