如何解决Etch-a-Sketch网格特定尺寸下右、底边变白问题?
问题分析与解决方案
核心原因
你遇到的问题本质是小数像素的渲染精度问题:当800除以51、44这类数时,得到的是带小数的像素值(比如800/51≈15.686px),浏览器无法渲染真正的小数像素,会进行取整处理。加上flex布局的换行计算误差,导致所有方块的总宽度/高度略小于容器的800px,露出容器的白色背景;Firefox对flex小数像素的处理逻辑更严格,所以错乱更严重。
另外,每个方块的1px边框会进一步加剧尺寸计算的偏差——即使你用了box-sizing:border-box,小数像素加上边框后,总尺寸的累积误差会被放大。
修复方案
改用CSS Grid布局代替flex,它天生就是为网格场景设计的,能自动处理单元格的尺寸分配,彻底避免手动计算像素带来的精度问题。同时调整边框的实现方式,用gap或仅添加部分边框来减少尺寸干扰。
修改后的代码
JavaScript
let container = document.querySelector(".container"); createGrid(16); function createGrid(gridDimensions) { // 用CSS Grid设置网格布局,自动分配单元格尺寸 container.style.gridTemplateColumns = `repeat(${gridDimensions}, 1fr)`; container.style.gridTemplateRows = `repeat(${gridDimensions}, 1fr)`; // 清空容器后创建方块 container.innerHTML = ""; for(let row = 1; row <= gridDimensions; row++) { for(let column = 1; column <= gridDimensions; column++) { let square = document.createElement("div"); square.id = `square-${row}-${column}`; square.className = "squares"; container.appendChild(square); } } drawOnGrid(); } function drawOnGrid() { let squares = document.querySelectorAll(".squares"); let hasColorBeenSet = []; // 移到函数内,避免作用域问题 squares.forEach((square) => { let squareDark = document.createElement("div"); squareDark.className = "square-dark"; // 用CSS类代替内联样式 square.appendChild(squareDark); let squareDarkOpacity = 0; square.addEventListener("mouseover", (e) => { if(!hasColorBeenSet.includes(square)) { hasColorBeenSet.push(square); let randomColor = Math.floor(Math.random() * 16777215).toString(16); square.style.backgroundColor = `#${randomColor}`; } squareDarkOpacity = Math.min(squareDarkOpacity + 0.1, 1); // 限制不超过1 squareDark.style.opacity = squareDarkOpacity; }); }); } function changeGridSize() { let validAnswer = false; while(!validAnswer) { let userInput = prompt("How big should the grid be? Enter a number between 8 to 100."); userInput = Number(userInput); userInput = Math.round(userInput); if(userInput >= 8 && userInput <= 100) { validAnswer = true; createGrid(userInput); } } }
CSS
* { padding: 0; margin: 0; box-sizing: border-box; } body { height: 100vh; background-color: rgb(90, 101, 110); display: flex; flex-direction: column; gap: 50px; justify-content: center; align-items: center; } .container-border { border: 1px solid black; } .container { height: 800px; width: 800px; background-color: white; display: grid; /* 改用Grid布局 */ gap: 1px; /* 用gap实现方块之间的分隔线,代替每个方块的边框 */ } .squares { background-color: white; /* 初始白色背景 */ } .square-dark { width: 100%; height: 100%; background-color: black; opacity: 0; } button { font-size: 26px; padding: 10px 20px; border-radius: 5px; } button:hover { transition: 0.2s; background-color: orange; cursor: pointer; }
HTML
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="./style.css"> <script src="main.js" defer></script> <title>Etch-a-sketch</title> </head> <body> <button onclick="changeGridSize()">Change grid size...</button> <div class="container-border"> <div class="container"></div> </div> </body> </html>
关键修改点
- CSS Grid替代Flex:用
repeat(gridDimensions, 1fr)让每个单元格自动占满容器的1/N,完全避免手动计算小数像素。 - 用gap代替边框:
gap:1px实现方块之间的黑色分隔线,不需要给每个方块加边框,消除边框带来的尺寸偏差。 - 自适应内部元素:
.square-dark用100%宽高自适应单元格,不需要传递像素尺寸。 - 修复作用域问题:把
hasColorBeenSet移到drawOnGrid函数内部,避免多次调用时的变量污染。 - 限制不透明度上限:添加
Math.min(...,1)防止不透明度超过1。
这样修改后,不管输入任何8-100之间的数值,网格都能完美填满容器,不会出现白边或布局错乱的问题。
内容的提问来源于stack exchange,提问作者alexanderherta
相关产品推荐
相关产品推荐

