在今年柏林举行的Beyond Tellerrand大会上,Andy Bell 发表了题为“把核心代码做好,弹性代码自然会随之而来”的精彩演讲,展示了如何在团队内部理性地讨论编码问题。他还在自己的博客上发表了一篇更深入的文章。
Andy 描述的问题是,他有一个CSS网格系统,其中的内容列并排排列,然后客户要求每次页面刷新时随机排列网格的顺序,以便公司的每个部门都能获得短暂的展示机会。Andy 非常重视代码的弹性,因此他对使用 JavaScript 解决此类问题持批评态度。移动整个DOM结构会很慢,而且每次交互时都将整个网格作为组件重新写入也存在风险。
于是我琢磨着该怎么办,想起了CSS的order属性可以用于flex和grid布局项。利用这个属性,你可以重新排列元素的视觉顺序。
你可能从未听说过的优秀乐队
伊里叛乱
路灯宣言
Dubioza Kolektiv
爱尔兰芥末酱
如果将第三个元素的顺序改为减一,它就会排在第一位:
ul {
显示方式:flex;
弯曲方向:柱;
间隙:1em;
}
#dk {
顺序:-1;
}
这样就把所有重新排序的工作都保留在了CSS引擎中。但是由于CSS目前还无法实现随机排序,我们需要一些 JavaScript 代码来实现这个功能。最初的想法是将排序作为内联样式添加,但这仍然需要操作DOM ,并且需要遍历所有元素。因此,我考虑使用CSS自定义属性:
ul {—customorder: -1;
显示方式:flex;
弯曲方向:柱;
}
#dk {
订单:var(—customorder);
}
这样我就可以访问父元素上的 `customorder` 属性了:
let ul = document.querySelector('ul');
ul.style.setProperty('—customorder',-1);
综合以上所有功能,我为您带来GridShuffle ,您可以在 GitHub 上查看代码:
关于
这是 order.html 文件。
消息
最新消息将显示在此处。
接触
联系信息将显示在此处。
案例研究
案例研究将在此展示。
洗牌
上面的网格会在每次页面刷新或点击“随机排列”按钮时重新排列。实现这种效果的方法有很多,但本示例仅使用CSS属性来设置网格项的顺序。除了访问父元素的CSS属性之外,没有修改HTML 代码,也没有进行任何DOM操作。这应该能带来很高的性能。JavaScript 代码通过更改定义网格项顺序的CSS变量来轮换网格项的顺序。以下是用于设置网格和随机排列网格项的相关代码:
#contentgrid {—items: 4;—item1-order: 1;—item2-order: 1;—item3-order: 1;—item4-order: 1;
显示方式:网格;
间隙:20px;
grid-template-columns: repeat(
自动适应,最小最大尺寸(200像素,1fr)
);
}
#about { order: var(—item1-order); }
#news { order: var(—item2-order); }
#联系{ 订单: var(—item3-订单); }
#casestudies { order: var(—item4-order); }
我们将每个元素的顺序定义为 `1`,这意味着如果我们将其中任何一个元素的值设置为 `0`,它将在网格中首先显示。例如,如果我们执行以下操作,“案例研究”部分将显示在最前面:
#contentgrid {—items: 4;—item1-order: 1;—item2-order: 1;—item3-order: 1;—item4-order: 0;
/* … */
}
#about { order: var(—item1-order); }
#news { order: var(—item2-order); }
#联系{ 订单: var(—item3-订单); }
#casestudies { order: var(—item4-order); }
这可以在服务器端或使用 JavaScript 实现,如下所示:
let root = document.querySelector('#contentgrid');
let itemcount = getComputedStyle(root)。
getPropertyValue('—items');
let old = 1;
const shuffleorder = () => {
let random = Math.floor(Math.random() * itemcount) + 1;
root.style.setProperty('—item' + old + '-order', 1);
root.style.setProperty('—item' + random + '-order', 0);
旧 = 随机;
};
shuffleorder();
我们通过读取根元素上 `–items` CSS属性的值来获取网格中的项目数量,并将当前第一个项目存储在 `old` 变量中。然后,我们随机选择一个介于 1 和项目总数之间的数字,并将旧项目的顺序设置为 `1`,将随机生成的新项目设置为 `0`。最后,我们将 `old` 重新定义为新项目的顺序。
这是最基本的方法,但它并非真正的打乱,因为它只是按固定顺序旋转元素。您可以参考“打乱网格”示例,了解更高级的实现方式,该示例会随机化所有元素的数组。您还可以通过移动数组来旋转元素,如“旋转网格”示例所示。
其他示例也不需要设置任何自定义属性,而是直接创建它们。这意味着需要进行更多一些的JS和 DOM 交互,但简化了流程。
let root = document.querySelector('#contentgrid');
let cssvar = `—item$x-order`;
// 获取物品数量
let elms = root.querySelectorAll(
root.firstElementChild.tagName
);
all = elms.length;
// 初始化订单数组和
// 设置商品顺序
let orders = [];
for (let i = 1; i <= all; i++) {
orders.push(i);
elms[i – 1].style.setProperty(
'order', 'var(' + cssvar.replace('$x', i) + ')'
);
root.style.setProperty(cssvar.replace('$x', i), i);
}
但如果你完全不想使用 JavaScript 来实现这个目标呢?Andy 在演讲中展示的解决方案是在服务器端随机化页面顺序,这在很多语言中都很容易实现。他使用 Jekyll 的方案是每隔几分钟生成一次页面,并使用 sample 过滤器,这看起来有点浪费资源,但很稳定。
当前和未来的纯CSS解决方案
目前仅使用CSS无法实现随机化或打乱元素顺序。不过,有一些方法可以利用 Sass ,但这需要进行预处理。另一种巧妙的方案是使用 `@property`,而 `@property` 目前尚未得到广泛支持。
CSS规范定义了一个random() 函数,可以在不使用 JavaScript 的情况下实现这种效果。但是,目前只有Safari 技术预览版 170支持此功能。
CSS 的polyfill 并不容易,所以目前来说,在你的解决方案中添加少量 JavaScript 来实现类似的效果或许是个不错的选择。在我看来,这种方法是一个不错的折衷方案,因为它保留了CSS的功能,而无需重新调整整个DOM树或重写整个网格系统。
原文: https://christianheilmann.com/2025/11/24/shuffling-a-css-grid-using-custom-properties/

