正文
2、核心技术原理
光看这代码量就像用牙签拼城堡,这个项目之所以能运作起来,Simon Willison 解释称,关键技巧是将
标签与 has()
选择器组合使用才得以实现。
对此,整个页面中有
35001 个
和
5840 个
单选按钮组成了
状态存储引擎。
每个方块的六个面都相当于一个标签,点击任意一面,就像触发了一个隐藏的开关,
通过
的
for
属性精准「链接」到相邻方块的状态。
当你想给方块换材质时,其实是在切换可见的标签组。CSS 里的
has()
选择器就像个「大管家」,比如当你选中「石头」材质的单选按钮时,它会立刻让其他材质的方块「隐身」(
display: none
),只留下石头方块在界面上显示。具体实现代码如下:
.controls:has(
> .block-chooser > .stone > input[type=radio]:checked
) ~ main .cubes-container > .cube:not(.stone) {
display: none;
}
值得一提的是,因为这个项目要生成上万行 HTML 标签,比如几万个
下面是这个 Pug 模板的简化版本
(完整代码详见:https://github.com/BenjaminAster/CSS-Minecraft/blob/main/index.pug)
,可以帮助大家理解 HTML 的结构:
- const blocks = ["air", "stone", "grass", "dirt", "log", "wood", "leaves", "glass"];
- const layers = 9;
- const rows = 9;
- const columns = 9;
<html lang="en" style="--layers: #{layers}; --rows: #{rows}; --columns: #{columns}">
<div class="blocks">
for _, layer in Array(layers)
for _, row in Array(rows)
for _, column in Array(columns)
<div class="cubes-container" style="--layer: #{layer}; --row: #{row}; --column: #{column}">
- const selectedBlock = layer === layers - 1 ? "grass" : "air";
- const name = `cube-layer-${layer}-row-${row}-column-${column}`;
<div class="cube #{blocks[0]}">
- const id = `${name}-${blocks[0]}`;
<input type="radio" name="#{name}" id="#{id}" !{selectedBlock === blocks[0] ? "checked" :