让2048棋盘适应窄屏:Grid、宽高比与长数字的排版边界
昨天讨论了2048满盘时的结束判定。这一篇换到界面层:桌面看着规整的4×4棋盘,为什么到了窄屏会出现横向滚动、格子被撑宽,或者四位数字挤出方块?
本文给出独立的布局教学示例,不修改此前部署的游戏,也不声称已做真机兼容测试。重点是把容器尺寸、网格轨道和数字内容分开处理,让问题可以逐层定位。
一、先让棋盘跟随父容器
固定写width:500px,再在手机上加一个transform:scale(…),常常只是把视觉内容缩小。元素原本占据的布局空间仍可能存在,周围的按钮、说明文字与点击区域也不容易同步。更直接的方式是让棋盘宽度由父容器约束,上限只负责限制桌面尺寸。
<meta name="viewport" content="width=device-width, initial-scale=1">
<main class="game">
<h1>2048</h1>
<p>相同数字合并,继续挑战更高分。</p>
<div class="board">
<div class="tile">2</div><div class="tile">4</div>
<div class="tile">8</div><div class="tile">16</div>
<div class="tile">32</div><div class="tile">64</div>
<div class="tile">128</div><div class="tile">256</div>
<div class="tile">512</div><div class="tile">1024</div>
<div class="tile">2048</div><div class="tile">4096</div>
<div class="tile">8192</div><div class="tile">16384</div>
<div class="tile tile--long">32768</div>
<div class="tile tile--long">65536</div>
</div>
</main>
这里有16个静态格子,只用于观察排版,不含移动、分数或随机生成逻辑。viewport设置也不禁止用户缩放;不要为了让棋盘“看起来不乱”,加入user-scalable=no来牺牲可读性。
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; padding: 1rem; }
.game { width: min(100%, 32rem); margin-inline: auto; }
.board {
--space: clamp(0.35rem, 1.5vw, 0.75rem);
width: 100%;
height: auto;
aspect-ratio: 1 / 1;
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
grid-template-rows: repeat(4, minmax(0, 1fr));
gap: var(--space);
padding: var(--space);
border-radius: 0.75rem;
background: #b9aca0;
}
.tile {
min-width: 0;
min-height: 0;
display: grid;
place-items: center;
border-radius: 0.4rem;
background: #eee4da;
color: #51483f;
font: 700 clamp(1rem, 5vw, 2.5rem) / 1.1 system-ui, sans-serif;
white-space: nowrap;
}
.tile--long { font-size: clamp(0.8rem, 3.5vw, 1.75rem); }
width:100%参照的是父容器,不是整个屏幕。body的内边距先留出两侧空间,game再取得剩余宽度,桌面时最多32rem。统一border-box后,board的内边距包含在其声明宽度内,不会在100%之外再额外增加一圈宽度。
二、正方形不是同时写死宽和高
MDN对aspect-ratio的说明强调,至少一个尺寸需要自动计算,宽高比才会参与尺寸推导。这里宽度由父容器决定,高度保留auto,期望比例为1:1。不要再叠加height:500px,否则窄屏时会得到又窄又高的棋盘。
aspect-ratio表达的是首选比例,不是任何内容条件下都必须维持的硬约束。最小尺寸、最大尺寸、内容贡献以及其他布局规则都可能影响最终结果。排查时应查看实际盒尺寸,而不是仅看到CSS里有1/1就认定页面一定是正方形。
示例明确指定四行四列,格子数量保持16个。增加提示文字、失败遮罩或动画层时,不要把它们作为第17个普通网格子项塞进同一层;可以放到棋盘外,或设计独立的覆盖层。
三、四列1fr仍可能被内容顶开
仅写repeat(4,1fr),并不总等于“每列无条件占四分之一”。网格轨道存在自动最小尺寸,长内容可能影响最小宽度。这里用minmax(0,1fr)明确允许轨道缩小,同时在tile上设置min-width:0。
但允许轨道缩小,不等于文字自动变小。布局系统和字体适配是两件事:即使格子已经正确均分,65536仍可能比2需要更多空间。因此示例给长数字单独的字体规则。实际游戏应由渲染层按数字位数选择样式,不让排版类参与合并算法。
例如,五位以上数字可以使用tile–long。这个阈值只是示例策略,字体、可用宽度和支持的最大数字都会影响最终选择。若允许无限继续挑战,就不能承诺一套固定字号适配任意长度;需要为更多位数制定进一步的显示策略并验证。
不要用text-overflow:ellipsis把32768变成327…,也不要直接overflow:hidden把关键数字裁掉。数字是游戏状态的一部分,隐藏它会让布局看似整齐,却让玩家无法正确判断。
四、间距需要一起进入尺寸计算
把棋盘的实际边长记作B,内边距为p,列间距为g;本例没有边框,那么每个格子的可用边长可以写成:
cell = (B - 2p - 3g) / 4
四列之间只有三条间隔,外侧空白由padding提供。若B为320px、p和g都为8px,则cell为70px。这是根据假设尺寸计算的示例,不是真机测量结果。
窄屏下若坚持很大的固定间距,数字真正得到的空间会越来越少。clamp让间距有上下限,并在中间随视口变化。也要记住,vw参照视口;如果棋盘被放进桌面侧栏,视口很宽而父容器很窄,间距仍可能达到上限。遇到这种嵌入场景,可以改用更小的固定间距或容器查询,不能把全屏页面的参数直接当成通用组件参数。
五、验收要包含内容和缩放
下面是建议执行的接入检查,本篇没有把这些检查冒称为已经通过的测试:
- 在320、375、768像素等不同宽度下查看页面,确认没有意外横向滚动,棋盘四列四行完整。
- 同时放入一位、四位、五位及产品允许的最长数字,检查是否完整可读;只用2做演示无法覆盖问题。
- 增大浏览器缩放和默认字体,确认按钮、标题和说明仍可阅读,必要时允许页面纵向滚动。
- 在横屏低高度窗口检查上下内容。优先保留正常滚动,不为一屏放下所有内容把按钮缩得过小。
- 若真实游戏采用绝对定位的棋子动画层,检查它和背景格使用同一套padding、gap与尺寸来源,避免静态格正确而动画落点偏移。
这个静态示例没有处理触摸手势、键盘焦点、动画、屏幕阅读器播报或完整的颜色对比度审计。响应式布局做对,只说明尺寸约束更清楚,不能代替交互和无障碍验收。
参考:MDN《aspect-ratio》:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/aspect-ratio。该资料用于核对首选宽高比和自动尺寸的语义;棋盘示例及尺寸推导为本文独立整理。
写作说明:本文由AI辅助整理与撰写,代码为独立教学示例,不涉及本机文件上传,也未修改线上项目。
- 点赞
- 收藏
- 关注作者
评论(0)