You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为网页蜂窝六边形网格添加半六边形填充屏幕角落空隙?

问题描述

我有一个基于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;
}

关键改动说明

  1. 动态适配视口:根据窗口尺寸自动计算可容纳的完整六边形数量和总行数,替代固定值适配不同屏幕。
  2. 半六边形封装:新增createHalfHexagon函数,根据类型生成左/右半六边形,添加专属样式类控制尺寸和边距。
  3. 布局优化:
    • 修改.row的flex-wrap为nowrap避免换行空隙;
    • 偏移行(奇数行)用padding-left替代margin-left,适配半六边形宽度确保对齐。
  4. 边缘填充逻辑:偶数行左侧默认添加左半六边形,每行末尾根据剩余宽度判断是否添加右半六边形,完全覆盖角落空隙。
  5. 响应式支持:添加窗口 resize 监听,尺寸变化时重新生成网格,保持全屏填充效果。

内容的提问来源于stack exchange,提问作者Sam Kandalgaonkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:59:14