最近我在用 AI 辅助写前端界面时,遇到一个很典型的问题:页面看起来能跑,但 DOM 结构经常“里三层外三层”,尤其是移动端适配时,AI 特别喜欢不断加容器、加 padding、加 overflow、加 max-width。
一开始我以为这只是代码风格问题。后来越看越发现,这背后其实是 AI 写界面时的一种默认倾向:AI 喜欢“防御式布局”,但前端工程更需要“责任边界清楚的布局”。
所谓“防御式布局”,就是 AI 在不确定父级布局、页面结构、组件边界时,会倾向于自己再包一层容器,然后在这层容器上加 padding、width、height、overflow、background 等样式。这样做的好处是局部看起来更稳定,不容易马上炸版;但坏处也很明显:一旦放进真实页面,就容易出现重复间距、奇怪滚动、内容溢出、组件之间对不齐。
比如一个 table 的分组标题行,本来语义上应该是整行跨列显示,但 AI 可能会先把它塞进第一列,再发现文本换行,于是去调第一列宽度。这个方向其实已经错了。问题不是列宽不够,而是这行本来就不应该受某一列约束。
为什么 AI 容易这样写?
第一,它缺少完整上下文。AI 经常只看到当前组件,不知道外层页面、drawer、modal、card、layout shell 已经提供了哪些约束。所以它会在当前组件里重复实现一套布局保护。
第二,它容易把“视觉分组”误判成“DOM 分组”。设计稿里有留白、有层次、有卡片感,但这些不一定都需要额外 wrapper。很多时候,间距应该来自父级 gap、table cell padding、section spacing,而不是每块内容都包一层 div。
第三,移动端会放大这种倾向。因为移动端最容易出现文本换行、按钮挤压、横向溢出。AI 为了保险,会加更多 px、max-width、overflow-auto、flex-col。短期看像是修复,长期看会让布局越来越难维护。
更好的做法,是先问清楚每一层布局的责任:
页面负责整体宽度和主区域间距。
Section 负责区域之间的 spacing。
Shared component 负责自己的内部结构。
Table row/cell 负责表格节奏。
业务组件只负责业务状态和必要组合。
如果一个子组件开始控制页面级宽度、滚动、高度,那通常就是边界模糊了。
我现在会给 AI 更明确的约束:
不要为了间距随手包 wrapper。
新增容器前先说明它解决什么布局问题。
优先复用父级 gap 和 shared component 的 padding。
不要在业务组件里随便写页面级 max-width、height、overflow。
移动端优先用合理的 grid/flex 规则,而不是无限加壳。
AI 能很快把界面“堆出来”,但工程质量不只是看截图接近不接近。真正好的前端结构,应该能清楚回答:这个间距是谁负责的?这个滚动是谁负责的?这个宽度是谁负责的?
当这些责任边界清楚以后,页面才会稳定,组件才会可复用,后续维护也不会变成一场 CSS 考古。
一句话总结:AI 喜欢防御式布局,但前端工程需要责任边界清楚的布局。
夜雨聆风