在现代 Web 开发中,Flexbox 和 Grid 已成为主流布局方案,它们通过启发式算法高效处理常见场景。然而,当面对高度复杂的、多重优先级约束或 “超约束”(over-constrained)布局时,这些方案往往陷入冲突或退化为固定尺寸,无法提供灵活的最优解。这里的观点是:通过将 CSS 布局重构为约束求解问题,并引入 Cassowary 算法,可以实现一个超越传统范式的原型引擎,支持优先级权衡与增量更新。
Cassowary 是一种增量线性约束求解器,专为用户界面布局设计。“Cassowary is an incremental constraint solving toolkit that efficiently solves systems of linear equalities and inequalities.” 该算法源于 1997 年的论文,将布局建模为线性等式 / 不等式系统(如 width_A == 0.5 * container_width),通过单纯形法(Simplex)变体求解,支持动态添加 / 删除约束,并在超约束时根据优先级(strength)选择最优解。这与 Flex/Grid 的刚性规则不同,后者无法优雅处理如 “按钮宽度至少 100px 但不超过父级 50%,优先居中对齐” 等冲突需求。
证据在于历史应用:Cassowary 驱动 iOS Auto Layout 和早期 Firefox XUL 布局;在 Web 端,cassowary.js 库证明其在浏览器中可行。此外,Rust 的 tui-rs 终端 UI 库使用 cassowary-rs 实现比例布局,确保区域尺寸精确匹配约束。基准测试显示,对于 80 个视图的 160 条约束,增量更新仅需 2.5ms,远优于从零重算。
实现该原型的关键是:将 DOM 元素映射为变量(位置 / 尺寸),CSS 属性解析为约束,注入 Cassowary 求解器。以下是可落地步骤与参数清单:
-
准备环境与库:
- 使用 cassowary.js(npm install cassowary),或 Kiwi.js(现代 fork)。
- 参数:solver = new kiwi.Solver (); 强度级别:required (1000)、strong (800)、medium (400)、weak (200)、默认 600。
-
变量建模:
- 为每个元素创建变量:x(left)、y(top)、w(width)、h(height)。
- 示例:const elemA = {x: new kiwi.Variable ('a_x'), w: new kiwi.Variable ('a_w') };
-
约束解析:
- 扩展 CSS:支持
constraint: left == parent.left + 10px; width >= 100px priority:strong;。 - 解析器函数:
function parseConstraint(rule) { // 伪代码:解析 'elem.left == parent.right + 20 priority:medium' const c = new kiwi.Constraint( elem.left, kiwi.OP.EQ, parent.right.clone().plus(20), kiwi.Strength.medium ); solver.addConstraint(c); } - 处理超约束:优先级冲突时,solver 自动降级低优先级约束。
- 扩展 CSS:支持
-
布局求解与应用:
- ResizeObserver 监听尺寸变化,触发增量更新:solver.updateVar (container_w, newWidth)。
- 应用结果:elem.style.left = elem.x.value () + 'px';。
- 阈值参数:约束上限 500 / 树(防 O (n^2) 退化);更新频率 throttle 16ms(60fps)。
-
高级特性:
- 基线对齐:constraint: elem.baseline == sibling.baseline;
- 比例:width == 0.618 * parent.width priority:required;
- 回滚策略:捕获 solver.solve () 失败(冲突),移除 weak 约束重试。
- 性能监控:Profiler 记录求解时间,若 >5ms 则简化树(flatten 嵌套)。
原型示例:三栏布局,左侧固定 200px、中间 flex 剩余、右侧 >=150px 优先 sticky。
<div class="container">
<div id="left">Left</div>
<div id="center">Center</div>
<div id="right">Right</div>
</div>
约束:
- left.w == 200 required
- center.x == left.x + left.w + 10
- right.w >= 150 strong
- container.w == left.w + 10 + center.w + 10 + right.w
- center.w == (container.w - 420) * 0.8 medium // 超约束示例
求解后,即使容器缩小时,solver 优先保证 right >=150,center 压缩。
风险与限制:DOM 树深 >10 时性能降(树状约束传播);浏览器不支持需 polyfill。回滚:fallback 到 Grid,阈值 treeDepth >8。
此原型扩展性强,可集成 PostCSS 插件解析自定义属性。相比 Flex/Grid,它在设计系统中提供 “声明式优化”,如优先内容拥抱(hugging) vs 拉伸(stretching)。
资料来源:cassowary.js GitHub;tui-rs 布局模块文档;Cassowary 原论文。