ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Foundation水平堆叠实战:断点、Flex与避坑指南

Foundation水平堆叠实战:断点、Flex与避坑指南 如果你用Foundation做过两三个页面大概率遇到过这种尴尬明明把几个内容块老老实实写进了同一个.row里手机上看它们排得好好的结果一到桌面端全挤成一团或者直接断行又或者反过来你希望它们在桌面端水平并排展示结果屏幕上全都竖着排队。这背后的核心问题就是Foundation网格系统里的“水平堆叠”。别小看这四个字它既是Foundation最基础也最常用的能力也是很多人从入门到放弃的分水岭。这篇文章不聊天花乱坠的原理直接以我实际做项目时摸出来的路子把水平堆叠这件事讲透顺便把那些文档里不写的坑也都翻出来晒太阳。1. 先搞懂Foundation网格里的“水平堆叠”到底怎么工作1.1 从一段最少代码开始很多教程喜欢上来就甩一大段Sass配置其实没必要。你先记住这个最经典的结构div classrow div classcolumns small-12 medium-6 large-4区块A/div div classcolumns small-12 medium-6 large-4区块B/div div classcolumns small-12 medium-6 large-4区块C/div /div这段代码的行为就是水平堆叠最典型的例子在手机这种小屏下三个区块各自占满一整行垂直一个接一个往下“叠”一旦屏幕到达中等宽度medium断点A和B两个区块先并排成一行C折到下一行再到大屏large断点三个区块就稳稳地水平排在同一个水平线上谁也不挤谁。注意我用的类名顺序先small-12再medium-6最后large-4。这个顺序不是随手写的Foundation的类名有明确的覆盖逻辑后面出现的断点类会在对应屏幕宽度下覆盖前面的设置。你把large-4写在medium-6前面也能编译但很容易让人看晕我自己维护项目时一律按“小到中再到大”排这算是团队协作里的隐形规范。1.2 为什么叫“水平堆叠”而不是直接叫“并排”原因在于响应式设计里堆叠方向是动态的。窄屏设备本身宽度有限你不可能让三个导航链接、三张卡片、三个输入框全部保持水平排列那样每个元素会被压缩到没法看。所以常规做法是小屏让元素垂直堆叠一个占一行大屏再切换成水平堆叠多个共享一行。Foundation管这种能力叫“堆叠”其实就是控制列在水平方向上的排列逻辑。你理解了这一点后面看任何响应式框架的网格本质上都逃不过这套思维一个容器行里面若干个列列在某个断点下决定自己是占满整行还是与兄弟列共享一行。拿这个思路去读Bootstrap的col-md-6、Bulma的columns你会发现原理惊人的一致也正因为一致网上才总有“到底哪个框架好用”的争论其实大家拼的就是那套断点细节和类名习惯。2. 实现水平堆叠的几种写法选哪种看你的项目体质Foundation从6.x开始网格系统实际上分成了两条技术路线经典float路线和后来加入的flex路线。很多人搞不清自己项目里用的到底是哪种导致查了一堆资料代码复制过来却看不出效果。我把两种路线拆开讲。2.1 经典float网格老项目里最稳的并排手段Foundation最早靠float实现列的并排。原理很简单每一列都是一个带有百分比宽度的块用float: left让它们往左靠一个接一个排成水平线。比如三列都设large-4每列宽度就是33.333%三列合计刚好100%自然排成一行。但float有个老毛病——浮动元素会脱离文档流父容器高度会塌掉。所以Foundation给.row内置了clearfix目的就是在行的结尾清除浮动让父容器重新“兜住”这些浮动的列。因此一个地方容易被忽略如果你自己又给.row额外加了overflow: hidden或者覆盖了display: block之类的样式可能就破坏了它的清除浮动逻辑水平排列还是乖乖的但后续元素的位置就开始飘了排查起来特别费劲。float网格的好处是兼容性极好连很老的浏览器都能正常渲染。如果你在维护一个上线多年的项目团队成员还在用老旧浏览器打开后台页面用float网格几乎不用考虑降级问题。它的缺点是垂直居中和等分高度比较麻烦做导航栏两段式布局时左边logo、右边菜单要垂直对齐用float往往得自己写绝对定位或者负margin。2.2 flex网格更省事、更现代的水平排列如果你项目不是特别在意古董浏览器我建议新页面直接用flex网格。Foundation在Sass里预留了一个全局开关$global-flexbox: true。你把这个变量打开后重新编译.row就不再依赖float去排列而是直接变成flex容器里面的.columns自动成为flex项水平排列成了默认行为做垂直对齐、等高分列都轻松得多。开启flex模式后一根导航栏里如果既有logo又有菜单按钮不再需要自己写浮动的奇技淫巧给容器加一行align-items: center内容就整整齐齐居中。原来float网格里的small-push-*、small-pull-*这类源序重排类在flex模式下作用逻辑也会变化如果你的老代码里用了这些类升级flex之后一定要回归一遍页面。2.3 用断点类切换堆叠方向不管float还是flex真正让水平堆叠“活”起来的是断点类。Foundation的默认断点分五档平时最常用的三档是small0到640px、medium641px到1024px、large1025px往上。你写small-12 medium-6表示在small范围之内列占12格整行到了medium范围变成6格半行。如果只写medium-6不写large-*那large范围会继续沿用medium的6格不会再自动变回12。这个规则很多人搞反以为不写large就会“恢复”成整行实际上断点类只会被后面更大的断点覆盖不会被“遗忘”。我自己总结了一套决策口诀左边一列的页面全用small-12两列布局用small-12 medium-6三列布局用small-12 medium-6 large-4四列布局用small-6 large-3因为四个小卡片在手机上两两并排也完全能看清。先定好页面上每行要放几个模块再去填断点类代码写起来快一倍。3. 实操三个页面场景把水平堆叠用熟练3.1 导航栏小屏折叠大屏水平展开导航栏是水平堆叠最频繁出现的场景。移动端受宽度限制菜单链接一般收起大屏再平铺展示。用一个实际项目里的写法div classrow align-middle div classcolumns small-12 large-3 a href/ classlogo某站点/a /div div classcolumns small-12 large-9 ul classmenu align-right lia href#features功能/a/li lia href#pricing定价/a/li lia href#about关于/a/li /ul /div /div这里的small-12让logo和菜单在手机上各占一行垂直堆叠large-3和large-9让它们在桌面端左右水平排列。align-middle是flex网格下的垂直居中类在float模式下想达到同样效果得自己加间距这也是我建议新项目直接开flex模式的原因。实际调试时我碰到过一个小问题菜单里的logo在手机上总是和下面一行粘连间距特别近。原因是.row默认会带一个负margin用于对齐列间隙而在小屏下两个small-12列之间没有额外的垂直间距。解决方案很简单给logo列加一个padding-bottom或者干脆在small-12的区块内用一个内部容器管理间距不要直接依赖行列间的缝隙。把布局和视觉间距分开管理后面改样式才不会被网格的默认行为牵制。3.2 卡片列表移动端单列桌面三列卡片列表是内容型网站的重头戏。我做过一个资讯类页面后台一篇文章对应一张卡片卡片包含标题、摘要、日期。最初我把三张卡片放进同一个.row每张都用large-4结果文章数量不是三的倍数最后一行要么左对齐空一块要么下一行开头单独一张卡片视觉上乱得不行。后来改为一行放六张卡片每张用small-12 medium-6 large-4div classrow div classcolumns small-12 medium-6 large-4 div classcard内容一/div /div div classcolumns small-12 medium-6 large-4 div classcard内容二/div /div !-- 循环生成就可以了 -- /div这样移动端一屏一张很清爽平板端一屏两张刚好适合阅读桌面端一屏三张信息密度也舒服。这里有个我在项目里踩过的坑卡片之间颜色不同或者一侧带背景色时列本身的留白不是每个卡片内部的padding而是网格的gutter。你在.columns的padding里加背景会发现左右两列的背景贴到屏幕边缘中间有条明显的间隔。这是因为.row左右有负margin抵消了容器padding列的实际可视区域是紧贴父容器的。遇到这种情况我给每张卡片内部再加个.card容器背景和边框全绘在.card上列本身保持透明这样无论网格gap怎么变卡片之间始终有均匀的呼吸感。3.3 表单标签和控件水平对齐不再换行打架做表单时水平堆叠同样重要。注册页面常见的布局是左边标签、右边输入框而不是标签在上面、输入框在下面。用Foundation实现时很多人直接把标签放在一个small-12里输入框放在下一个small-12里结果手机上没问题桌面端就成了标签和输入框上下两行非常拖沓。推荐写法是给label和input各套一个列断点类写medium-4和medium-8div classrow div classcolumns small-12 medium-4 label forusername用户名/label /div div classcolumns small-12 medium-8 input typetext idusername placeholder请输入用户名 /div /div手机端标签和输入框各占一行符合移动端从上至下的填写习惯桌面端标签和输入框并列在同一水平线上眼睛扫过去很轻松。尤其要注意的是Foundation表单控件默认是display: block; width: 100%所以在medium-8列里输入框会自动撑满整个列宽不需要你再写宽度。如果谁给你推荐那种“输入框宽度300px”的代码直接略过那在响应式网格里就是定时炸弹。4. 水平堆叠最常见的坑和排查清单4.1 列没有并排反而竖着排遇到这个问题先别急着怀疑框架。我的排查顺序固定是第一看列类名有没有写错。large-4写成了large4或者col-lg-4Foundation根本不认识列就会退化为普通的block元素向下排。第二看列是不是直接放在.row下面。如果你在列和.row之间又套了一个div而这个div不是Foundation的网格类它会变成一个非网格的中间层把列的宽度撑破或者挡住水平排列就会失效。第三如果开了flex模式看看是不是有人在.row上覆盖了display: block。有些同事会为了做背景色去改row的样式顺手加个display: blockflex容器就废了。这条排查路径我吃过太多次亏。最典型的是一次功能页面突然从并排变成上下排检查了半小时才发现是某个公共样式文件里写了.row { display: block !important; }也不知道是哪位前辈为了兼容某个老模块留下的。4.2 列间隙忽大忽小大家最爱问的问题就是为什么两列之间的空隙和列到屏幕边缘的空隙不一样。答案是Foundation的gutter机制每一列左右各有padding.row用负margin把整行的左右两端缩回去所以第一列左边没有多余空隙最后一列右边也没有列与列之间则有双份padding。这是框架的默认设计为了让你能够塞进一个容器背景而不露边。如果你想要所有列之间包括边缘都有统一间距就在.row外面再套一层带内边距的容器如果你想彻底取消列间隙用.collapse类div classrow collapse div classcolumns large-6半边/div div classcolumns large-6另半边/div /div不过.collapse是全局生效的取消之后列里的内容直接贴边视觉上可能变得很秃。我一般只会在做图片拼贴墙这类效果时才用常规文字页面还是保留默认gutter更舒服。顺便提一句Foundation还支持small-collapse、medium-collapse这种只对某个断点生效的间隙控制类如果只想在小屏取消间隙、大屏保留就用它。4.3 同时引用多个前端框架类名互相打架实际项目里把Foundation和Bootstrap的默认CSS一起引进来的人不在少数都是历史遗留问题。这两个框架都有.row和.container一旦同时加载说不好哪个规则先生效。表现就是列宽度莫名其妙错乱明明写了large-4却没有按33%宽度渲染。处理办法不是去找“哪个框架优先级更高”的黑魔法而是明确项目里以哪个框架为主。我当时的做法是全站只保留Foundation的网格类把Bootstrap的网格相关样式从编译产物里剔除组件样式单独维护。如果实在因为组件需要无法剔除那就在你重用网格的页面里给最外层加一个自定义命名空间比如.project-grid .row后续用这个命名空间覆盖所有框架默认的row规则把自己的布局规则和第三方库隔离。5. 进阶偏移、源序重排和嵌套进一步控制水平堆叠5.1 用偏移类让列在水平方向上错位有时候你不想让所有列都从最左边开始。比如右侧要放一张配图左侧正文只需要占一半宽度如果用large-6加一个居中的感觉Perfect。但更常见的是给某一列增加前导空白。Foundation提供了offset类div classrow div classcolumns small-12 medium-6 medium-offset-3 居中的内容区块 /div /divmedium-offset-3表示这个列在中等屏幕上从第4格开始前面空出3格加上自身6格宽度正好占据中间位置。这个写法的好处是不用额外包装一个空列来占位。移动端由于是small-12偏移不起作用内容依然顶格符合小屏阅读习惯。注意偏移类也按断点区分large-offset-*、medium-offset-*、small-offset-*各管各的。另外偏移列的总宽度加上偏移量不能超过12否则会把后面的列挤到下一行。具体能不能超过在float网格和flex网格里表现不完全一致最稳妥的做法是写完实际预览一下别只靠心算。5.2 push/pull在水平堆叠中的应用源序重排是网格系统里比较高级的功能。直白说HTML源码里第一个出现的区块在页面上却显示在右边第二个出现的区块显示在左边。这在图文混排页面里很常见——移动端想先让用户看到核心内容桌面端又希望视觉顺序符合阅读习惯。div classrow div classcolumns small-12 large-6 large-push-6图片区/div div classcolumns small-12 large-6 large-pull-6文字区/div /div源码里图片区排在前面但large-push-6会把它往右推6格文字区用large-pull-6往回拉6格于是视觉上变成了文字在左、图片在右。这招在旧项目里很管用因为它不改变DOM顺序也不影响移动端从上到下的渲染顺序只是在大屏下做了一个水平方向的“乾坤大挪移”。flex模式下这套push/pull类仍然可用不过如果你在Sass里开了flexbox有些版本的Foundation会建议改用order相关类来调整排列顺序。具体用哪种要在项目编译后的实际效果里验证。我自己在升级flex模式时碰到过large-pull-*在某些边界宽度下没有完全拉回原位的情况最后直接放弃重排类改用flex的order属性微调。5.3 嵌套网格一格内再做一层水平堆叠布局复杂度上去后你会在某个列里面继续细分。比如左侧栏是一整列但左侧栏内部又分成头像区和文字区两块。这时就在列里再写一个.rowdiv classcolumns small-12 large-4 div classrow div classcolumns small-4头像/div div classcolumns small-8昵称与简介/div /div /div嵌套网格的思想很简单每一层独立使用自己的12列体系内层不再受外层列宽的影响。外层只负责提供宽度范围内层在它的宽度里再自行分配。这里有一个容易绕进去的问题内层.row的负margin会和外层列的padding相互作用。如果你在列的背景色上直接看到左右两边出现小小的白色缝隙多半就是这组“负margin加padding”相互抵消留下的。解决方式是在内层.row外面再包一层不带grid样式的普通容器把背景画在它上面。嵌套用多了你会发现水平堆叠其实是一套递归结构。把一个页面拆成一行一行每一行里拆成一列一列列里再拆成行层层嵌套就能拼出几乎任何界面。这也是我后来面对复杂页面时不再慌张的原因——越是复杂的页面越要从一层网格开始画草稿而不是一上来就写几十个类名。做这套东西做久了我觉得最值钱的不是背了多少类名而是脑子里能随时把“页面布局”翻译成“几行几列”的网格草图。Foundation的水平堆叠也好其他框架的响应式网格也好本质都是同一件事在一根水平线上处理少数元素如何共享空间多数元素如何优雅地交给下一行。你先用最简单的.row加.columns把页面骨架立起来再根据断点去调整每列的宽度最后用偏移、重排和嵌套去打磨细节整个过程比想象中顺畅得多。如果真遇到什么奇怪的布局问题别先怪框架回到这五个字——水平堆叠想想它在这个断点上到底应该占几格问题往往就迎刃而解。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进