如何为网页蜂窝六边形网格添加半六边形填充屏幕角落空隙?
问题描述
我有一个基于HTML、CSS和JavaScript的网站,通过JS检测浏览器尺寸生成整页蜂窝六边形网格,但角落处因为放不下完整六边形存在空隙,想用半六边形填充这些空隙。以下是半六边形的SVG代码:
左半六边形:
<svg viewBox="0 0 50 116" width="50" height="116"> <polygon points="50,0 50,115.48 0,86.61 0,28.87" fill="#28282B"/> </svg>
右半六边形:
<svg viewBox="50 0 50 116" width="50" height="116"> <polygon points="50,0 100,28.87 100,86.61 50,115.48" fill="#28282B"/> </svg>
当前实现蜂窝网格的代码片段:
JavaScript
const hexagonWidth = 100; const hexagonHeight = 115.48; const rowHeight = 125; const numRows = 12; const numCols = 19; const container = document.getElementById("hexagons"); for (let i = 0; i < numRows; i++) { const row = document.createElement("div"); row.classList.add("row"); if (i % 2 !== 0) { row.classList.add("row-moved"); } for (let j = 0; j < numCols; j++) { const hexagon = document.createElement("div"); hexagon.classList.add("hexagon"); hexagon.style.width = hexagonWidth + "px"; hexagon.style.height = hexagonHeight + "px"; hexagon.style.margin = "5.5px 2px"; const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("height", rowHeight); const polygon1 = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); polygon1.setAttribute("points", "50,0 100,28.87 100,86.61 50,115.48 0,86.61 0,28.87"); polygon1.setAttribute("fill", "#28282B"); const polygon2 = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); polygon2.setAttribute("points", "50,0 100,28.87 100,86.61 50,115.48"); polygon2.setAttribute("fill", "#28282B"); svg.appendChild(polygon1); svg.appendChild(polygon2); hexagon.appendChild(svg); row.appendChild(hexagon); } container.appendChild(row); }
CSS
body { background: #171717; overflow: hidden; } .row { width: 100vw; height: 125px; overflow: hidden; display: flex; align-items: center; justify-content: center; flex-wrap: wrap; margin-top: -35px; margin-left: -33px; } .row .hexagon { position: relative; width: 100px; height: 115.48px; margin: 5.5px 2px; display: flex; justify-content: center; align-items: center; transition: all 0.2s linear; } .row .hexagon:hover polygon { fill: #3fff3c; } .row.row-moved { margin-left: 19px; } .row .hexagon svg polygon { transition: all 0.2s linear; } .row .hexagon svg polygon:hover { fill: #3fff3c; }
HTML
<div id="hexagons"></div>
解决方案
要填充角落空隙,需动态适配视口尺寸,在网格边缘位置插入半六边形,并调整布局规则确保全屏无空隙覆盖。
修改后的完整代码
HTML
<div id="hexagons"></div>
CSS
body { background: #171717; overflow: hidden; margin: 0; } .row { width: 100vw; height: 125px; overflow: hidden; display: flex; align-items: center; flex-wrap: nowrap; margin-top: -35px; position: relative; } .row .hexagon { position: relative; width: 100px; height: 115.48px; margin: 5.5px 2px; display: flex; justify-content: center; align-items: center; transition: all 0.2s linear; } .row .half-hexagon { position: relative; width: 50px; height: 115.48px; margin: 5.5px 0; display: flex; justify-content: center; align-items: center; transition: all 0.2s linear; } .row .hexagon:hover polygon, .row .half-hexagon:hover polygon { fill: #3fff3c; } .row.row-moved { padding-left: 52px; } .row .hexagon svg polygon, .row .half-hexagon svg polygon { transition: all 0.2s linear; }
JavaScript
const hexagonWidth = 100; const halfHexWidth = 50; const hexagonHeight = 115.48; const rowHeight = 125; const hexMarginX = 2; const hexMarginY = 5.5; // 动态计算视口适配的行列数 const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const fullHexPerRow = Math.floor((viewportWidth + hexMarginX) / (hexagonWidth + hexMarginX * 2)); const totalRows = Math.floor((viewportHeight + 35) / (rowHeight - 35)); const container = document.getElementById("hexagons"); // 生成蜂窝网格 generateGrid(); // 窗口尺寸变化时重新生成网格 window.addEventListener('resize', () => { container.innerHTML = ''; generateGrid(); }); function generateGrid() { const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const fullHexPerRow = Math.floor((viewportWidth + hexMarginX) / (hexagonWidth + hexMarginX * 2)); const totalRows = Math.floor((viewportHeight + 35) / (rowHeight - 35)); for (let i = 0; i < totalRows; i++) { const row = document.createElement("div"); row.classList.add("row"); const isOddRow = i % 2 !== 0; if (isOddRow) row.classList.add("row-moved"); let currentRowWidth = 0; // 偶数行左侧添加左半六边形填充空隙 if (!isOddRow) { row.appendChild(createHalfHexagon('left')); currentRowWidth += halfHexWidth; } // 添加完整六边形 for (let j = 0; j < fullHexPerRow; j++) { row.appendChild(createFullHexagon()); currentRowWidth += hexagonWidth + hexMarginX * 2; } // 剩余宽度足够时添加右半六边形 const remainingWidth = viewportWidth - currentRowWidth; if (remainingWidth >= halfHexWidth - hexMarginX) { row.appendChild(createHalfHexagon('right')); } container.appendChild(row); } } // 创建完整六边形元素 function createFullHexagon() { const hexagon = document.createElement("div"); hexagon.classList.add("hexagon"); hexagon.style.width = `${hexagonWidth}px`; hexagon.style.height = `${hexagonHeight}px`; hexagon.style.margin = `${hexMarginY}px ${hexMarginX}px`; const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", hexagonWidth); svg.setAttribute("height", hexagonHeight); const polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); polygon.setAttribute("points", "50,0 100,28.87 100,86.61 50,115.48 0,86.61 0,28.87"); polygon.setAttribute("fill", "#28282B"); svg.appendChild(polygon); hexagon.appendChild(svg); return hexagon; } // 创建半六边形元素 function createHalfHexagon(type) { const halfHex = document.createElement("div"); halfHex.classList.add("half-hexagon"); halfHex.style.width = `${halfHexWidth}px`; halfHex.style.height = `${hexagonHeight}px`; halfHex.style.margin = `${hexMarginY}px 0`; const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", halfHexWidth); svg.setAttribute("height", hexagonHeight); if (type === 'left') { svg.setAttribute("viewBox", "0 0 50 116"); const polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); polygon.setAttribute("points", "50,0 50,115.48 0,86.61 0,28.87"); polygon.setAttribute("fill", "#28282B"); svg.appendChild(polygon); } else { svg.setAttribute("viewBox", "50 0 50 116"); const polygon = document.createElementNS("http://www.w3.org/2000/svg", "polygon"); polygon.setAttribute("points", "50,0 100,28.87 100,86.61 50,115.48"); polygon.setAttribute("fill", "#28282B"); svg.appendChild(polygon); } halfHex.appendChild(svg); return halfHex; }
关键改动说明
- 动态适配视口:根据窗口尺寸自动计算可容纳的完整六边形数量和总行数,替代固定值适配不同屏幕。
- 半六边形封装:新增
createHalfHexagon函数,根据类型生成左/右半六边形,添加专属样式类控制尺寸和边距。 - 布局优化:
- 修改
.row的flex-wrap为nowrap避免换行空隙; - 偏移行(奇数行)用
padding-left替代margin-left,适配半六边形宽度确保对齐。
- 修改
- 边缘填充逻辑:偶数行左侧默认添加左半六边形,每行末尾根据剩余宽度判断是否添加右半六边形,完全覆盖角落空隙。
- 响应式支持:添加窗口 resize 监听,尺寸变化时重新生成网格,保持全屏填充效果。
内容的提问来源于stack exchange,提问作者Sam Kandalgaonkar
相关产品推荐
相关产品推荐

