资讯动态

HTML/CSS 居中布局全解:水平、垂直、Flex 与 Grid 选型指南

发布时间:2026/9/30 16:09:30 来源:尧图企业网站定制
1. 把居中这件事先拆开别上来就写代码刚入行那会儿我最怕听到需求里出现居中两个字。后来做久了才发现这个需求之所以让人头疼不是因为它难而是因为提问的人和自己都没把居中这个词拆清楚。HTML 标签元素的居中显示本质上要回答三个问题是水平居中还是垂直居中被居中的是一个行内级元素文字、图片、span、a还是一个块级元素div、p、ul父容器的高度是确定的还是由内容撑开的这三个问题没想清楚代码写十行也是白写。1.1 方向、元素类型、高度确定性居中的三个坐标轴先说明一下分类逻辑。水平居中相对简单因为 CSS 里有一条从 CSS2 时代就存在的规则块级元素设置固定宽度后左右外边距设为auto浏览器会自动把剩余空间平分到两侧。这条规则到今天依然是很多场景下最干净的解法不需要flex不需要定位兼容性可以一直往前数很多年。垂直居中就不一样了。CSS 的文档流模型是自上而下堆叠的高度天然由内容决定没有一个剩余空间的概念所以早期的垂直居中只能靠一些借力的技巧借line-height把单行文字撑到跟容器一样高借table-cell把块级盒子变成表格单元格借绝对定位把元素从文档流里抽出来再手动摆位置。这些方案能用但都有各自的适用边界。第三个坐标轴是父容器高度是否确定。这是新手最容易忽略的一点。给一个div写height: 100%结果发现完全没反应原因往往不是写错了而是它的父元素没有显式高度百分比高度找不到参照系浏览器就按auto处理了。搞清楚这一点之后你会明白为什么100vh在很多居中场景里比100%更省心也会明白flex为什么能绕开这个坑——因为flex容器的align-items对齐的是交叉轴上的可用空间不依赖子元素的百分比高度。提示拿到居中需求时先在纸上写三行方向水平/垂直/两者、元素类型行内/块级、父高是否确定。写出来之后再挑方案能省掉一大半调试时间。1.2 保持文档流还是脱离文档流选型的分水岭我后来给自己总结了一条判断标准能用文档流解决的就不要用绝对定位。原因很现实。绝对定位会把元素从文档流中拿出来它不再影响兄弟元素的位置也不会被兄弟元素影响看起来自由代价是父容器不再因为它的高度而撑开。做弹窗、做遮罩层的时候这不是问题但如果你只是想给一个卡片标题做居中用了绝对定位就属于拿大炮打蚊子还得额外给父容器补position: relative多了一层层叠上下文后面写z-index的时候又多一个变量。现代浏览器环境下flex和grid是我默认的第一选择。它们对文档流的破坏最小子元素仍然是正常的盒子只是对齐方式由容器统一控制。一个display: flex加两行对齐属性水平垂直一起解决代码量和可读性都优于定位方案。唯一的顾虑是极老的浏览器但这个顾虑在今天的项目里基本可以忽略除非你要给某些内嵌浏览器或邮件模板做兼容——这是一个特殊的例外后面我会单独说。因此整篇文章的展开顺序我按从文档流内到文档流外来排水平居中 → 垂直居中 → flex/grid → 实战场景 → 排查清单。这样你读到最后手里应该有一张完整的方案地图而不是零散的代码片段。2. 水平居中的实现细节与参数推导水平居中看似简单但它是问题最多的一块。我见过太多人把text-align: center写在块级元素自己身上然后疑惑为什么没生效。这节把每个方案的生效条件和失效原因都摊开说。2.1 行内元素与文本text-align 的作用边界text-align: center的作用对象是块级容器的行内内容包括纯文本、img、span、a、input、button以及display: inline-block的元素。它的关键点是你要写在父容器上而不是元素自己身上。div classbanner span这段文字会居中/span img srclogo.png alt示例图 /div.banner { text-align: center; /* 写在父容器上作用于内部的文字和图片 */ }为什么不写在子元素上因为text-align是一个继承属性它描述的是容器内部的文本如何排列不是一个可以对自己生效的对齐方式。子元素如果不是块级容器就没有内部内容可以对齐自然看不到效果。这一点和margin: auto的逻辑正好相反很多人就是在这两个属性之间反复横跳。还有个细节inline-block元素之间会因为 HTML 源码里的换行和空格产生一个空白字符宽度大约是当前字体大小的四分之一到三分之一。做导航菜单的时候这个空白会让等宽排列出现细微偏差。常用的处理方式是把父容器font-size设为0再在子元素上把字号恢复回来也有团队直接用注释把标签之间的换行吃掉。我个人倾向font-size: 0因为它在模板里更直观不需要破坏 HTML 的缩进结构。注意text-align: center对display: block且宽度撑满父容器的子元素是看起来无效的因为它的左右边界已经贴住了父容器的边界没有可移动的余地。这不是属性失效是没有剩余空间。2.2 块级元素margin 0 auto 生效的四个前提margin: 0 auto是水平居中的经典解法但它的生效条件比很多人想的严格。我把它归结为四条元素必须是块级盒子或者被显式设置为display: block/display: table。行内元素设了也没用行内元素不参与外边距的自动分配。元素必须有确定的宽度。如果width是auto块级元素的默认行为是撑满父容器宽度此时左右margin都只能算作 0自然居不了中。元素不能是浮动状态。float之后元素变成块级但会收缩包裹内容margin: auto的自动分配行为不再适用。元素不能是绝对定位且未设置左右偏移。绝对定位元素如果要靠margin: auto水平居中需要同时设置left: 0; right: 0;再配合margin: 0 auto和确定宽度这个后面在讲绝对定位时会细说。宽度这块有个容易踩的地方max-width和width同时用时浏览器会先用width计算出内容盒宽度再用max-width做上限约束居中计算依据的是约束之后的宽度。所以在响应式布局里width: 100%; max-width: 1200px; margin: 0 auto;这套组合是非常常见的写法它让容器在大屏上固定宽度居中在小屏上自动退化成满宽。.container { width: 100%; max-width: 1200px; margin: 0 auto; /* 剩余空间平均分给左右 */ padding: 0 16px; box-sizing: border-box; }顺便说一句box-sizing。默认的content-box会让padding加在宽度之外导致设置了max-width: 1200px的容器实际占位变成 1200 加左右内边距在小屏上可能直接撑出横向滚动条。统一设成border-box能避免这类问题这也是绝大多数现代项目在全局样式里重置box-sizing的原因。2.3 宽度由内容决定时fit-content 与 display: table有些时候你不想给元素写死宽度比如一个标签列表宽度应该由内部的文字长度决定。这时候块级元素的默认行为会让它撑满父容器margin: 0 auto就失效了。解决办法是让元素收缩包裹内容。第一种写法是用width: fit-content。它告诉浏览器宽度按内容计算但不要超过可用空间。配合margin: 0 auto就能实现宽度随内容变化、整体保持居中的效果。.tag-list { width: fit-content; /* 宽度包裹内容 */ margin: 8px auto; /* 在父容器里水平居中 */ padding: 6px 12px; background: #f5f5f5; border-radius: 4px; }第二种写法是display: table。这是更早期的技巧table元素的宽度天然收缩包裹内容同时又是块级盒子可以接受margin: auto的分配。它的兼容性比fit-content更好代价是会在视觉上产生一个块级格式化上下文内部的float会被包含进来某些布局下会带来意料之外的结果。我在新项目里优先用fit-content只有在维护老代码时才用display: table。第三种情况是display: inline-block配合父容器的text-align: center。它同样能让元素宽度收缩到内容尺寸并且居中。但前面提到的空白字符间隙在这条路径上同样存在而且元素之间是行内关系垂直方向的基线对齐会引入额外的间距需要额外处理。所以如果不是语义上真的需要行内级元素我更推荐fit-content这条路。3. 垂直居中从老技巧到现代布局的完整演进垂直居中之所以在 CSS 社区被讨论了十几年是因为它长期没有一个自然的解法。了解这些老方案的原理并不只是为了怀旧很多遗留项目和特殊场景比如 HTML 邮件里它们仍然是唯一选择而且理解它们能帮你更清楚地看到 flex 和 grid 到底替我们解决了什么。3.1 line-height 与 table-cell 的适用场景与坑line-height做垂直居中的原理很直观行高的计算方式是让文本行在行框里垂直居中如果line-height等于容器高度那一行文字就自然落在容器正中间。这个方案代码极短一行搞定.single-line-btn { height: 44px; line-height: 44px; /* 与 height 相等单行文字垂直居中 */ }但它有三个硬限制。第一只适用于单行文本一旦文字换行第二行的位置会继续往下走整个文本块不再居中。第二容器高度必须写死line-height无法写成百分比来跟随一个不确定的高度。第三如果容器里有图片或其他行内元素line-height撑开的是行框不是元素盒子图片的基线对齐会让整体视觉重心偏移——这个坑我在做按钮里的图标加文字时踩过最后是靠给图标加vertical-align: middle才把视觉拉正的。table-cell方案则是另一条思路。把父容器设为display: table子元素设为display: table-cell然后给子元素加vertical-align: middle.tb-parent { display: table; height: 200px; width: 100%; } .tb-child { display: table-cell; vertical-align: middle; /* 单元格内的内容垂直居中 */ text-align: center; /* 顺带解决水平居中 */ }它的优点是能处理多行内容和不确定宽高的子元素而且水平垂直可以一起解决。缺点是引入了一整套表格布局的计算规则父容器在宽度上的表现会变得奇怪——比如子元素的margin在表格单元格里会被忽略。另外table-cell元素对浮动和定位子元素也有特殊处理嵌套复杂布局时容易失控。我现在的态度是能用 flex 就别用它但如果目标环境是某些老旧的渲染引擎它依然是可靠的备胎。3.2 绝对定位加 transform一个需要算清楚的坐标推导绝对定位这套方案很多人是背下来的但没真正算明白。我来把数学过程走一遍你就再也不会记错了。一个绝对定位元素的定位基点是它自身的左上角外边距框。设置top: 50%时这个 50% 是相对包含块的高度计算的。也就是说元素的左上角被放到了父容器的垂直中线位置。问题来了元素的上半部分在中线上方下半部分在中线下方整体是上边贴着中线不是居中。要真正居中需要把元素向上移动自身高度的 50%。transform: translateY(-50%)里的百分比参照对象恰好是元素自身的尺寸而不是父容器。这就是关键差别top的百分比看父容器translate的百分比看自己。两者配合才能把基点从中线挪到中线减半个自身高度实现真正的居中。.modal { position: absolute; /* 或 fixed视需求而定 */ top: 50%; left: 50%; transform: translate(-50%, -50%); }这套写法的最大优势是不要求元素有确定宽高内容多长都能居中。放在弹窗场景里非常实用。但它有两个副作用需要留意。一是transform会创建新的层叠上下文如果这个元素内部还有position: fixed的子元素fixed 的参照物会变成这个被 transform 的元素而不是视口弹窗里嵌一个固定定位的工具栏就会表现出意想不到的行为。二是低版本的某些浏览器需要-webkit-transform前缀现在这个顾虑已经基本没有了但如果项目要兼容很老的移动端内核加上前缀是稳妥的做法。3.3 absolute 加 margin auto另一种不需要 transform 的解法如果你不喜欢transform带来的层叠上下文副作用还有一条路给绝对定位元素同时设置四个方向的偏移为 0再让margin: auto去分配剩余空间。.box { position: absolute; inset: 0; /* 等价于 top/right/bottom/left 都为 0 */ width: 320px; height: 180px; margin: auto; /* 四个方向的剩余空间平均分配两轴同时居中 */ }原理是当左右偏移都为 0 且元素宽度确定时水平方向的剩余空间就是包含块宽度减去元素宽度margin-left和margin-right设为auto会平分这部分空间元素自然水平居中垂直方向同理。这个方法要求元素有确定的宽高因为如果宽度是auto在inset: 0的约束下元素会被拉伸填满整个包含块就没有剩余空间可分配了。我把这两套方案的取舍整理成一个对照方便你直接选方案是否需确定宽高主要副作用适用场景top/left: 50%translate(-50%,-50%)不需要创建层叠上下文影响内部 fixed 元素不定宽高弹窗、提示框inset: 0margin: auto需要宽高写死不随内容变化尺寸固定的浮层、图标top: 50%margin-top: -高度的一半需要且必须知道具体像素高度改动要同步改 margin老项目、固定尺寸元素line-height等于容器高单行文本多行失效图片对齐偏移按钮、单行标题提示如果你的绝对定位元素内部需要用到position: fixed优先选inset: 0加margin: auto避免transform带来的包含块变化。4. Flex 与 Grid现在最值得掌握的两套方案前面讲的都是绕路的解法接下来这两套才是现代布局的正解。它们的设计思路是由父容器统一声明对齐规则子元素不需要知道自己在被怎么摆。这个思路上的转变比记住几个属性名重要得多。4.1 Flex 三件套主轴、交叉轴和 margin autoflex的对齐逻辑围绕两条轴展开。默认情况下flex-direction: row主轴是水平方向交叉轴是垂直方向。justify-content控制主轴上的分布align-items控制交叉轴上的对齐。所以水平垂直居中的标准写法是.center-box { display: flex; justify-content: center; /* 主轴默认水平居中 */ align-items: center; /* 交叉轴默认垂直居中 */ min-height: 300px; }注意我写的是min-height而不是height。用min-height的好处是容器可以被内容撑高超过 300px 时对齐规则依然生效不会出现内容溢出容器的情况。这一点在写卡片列表的时候很有用因为卡片内容长度不可控写死高度迟早会翻车。这里最容易搞混的就是justify-content和align-items谁管哪个方向。我的记法是justify-content管排队方向也就是元素沿主轴怎么排align-items管对齐方式也就是元素在交叉轴上怎么贴。如果某天把flex-direction改成了column主轴变成垂直方向这两个属性的作用方向就互换了原来的水平居中代码会变成垂直居中。所以改flex-direction之后一定要回头检查对齐属性这是我在重构时踩过的坑。另外还有一个很多人没注意的用法在 flex 容器里给单个子元素加margin: auto它会在两个轴上同时居中。原理是 flex 容器中auto外边距会吸收主轴和交叉轴上的剩余空间四个方向的auto会平分掉所有剩余空间。这个写法的妙处在于如果容器里有多个子元素你可以只让其中一个居中其余保持原位.nav { display: flex; align-items: center; } .nav .logo { margin-right: auto; /* 把右侧空间全部吃掉logo 贴左其余元素贴右 */ } .nav .menu { margin-left: auto; /* 菜单整体贴右 */ }这是导航栏布局里非常常用的一招比用justify-content: space-between更灵活因为你可以精确控制哪一块吸收空白。4.2 Grid 的 place-items两行代码收工grid的居中写法更短。关键在于place-items这个简写属性它同时设置align-items和justify-items而这两个属性作用于网格项在两个轴上的对齐.center-grid { display: grid; place-items: center; /* 等价于 align-items: center; justify-items: center */ min-height: 100vh; }对于只有一个子元素的场景place-items: center基本是最短的正解。如果网格里有多行多列的轨道还需要区分place-items和place-contentplace-items控制的是每个网格项在它自己所在的网格区域里怎么对齐是对项目的约束。place-content控制的是整个网格轨道组在容器里怎么对齐是对轨道的约束。单行单列的场景下两者效果看起来一样但一旦网格变复杂行为就分道扬镳了。我一般记成只会一个格子就用place-items要让整片网格整体挪位置就用place-content。写代码的时候别图省事混用出问题的时候排查成本很高。grid还有一个特别适合居中的隐藏能力父容器不需要给子元素设任何东西子元素也不需要有宽度。因为网格区域的尺寸由轨道决定项目在轨道内居中内容多大多小都不影响居中结果。这一点比 flex 还省心因为 flex 中子元素如果设了margin或者被拉伸可能会干扰交叉轴对齐。4.3 两套方案的参数对照与选型建议到底什么时候用 flex什么时候用 grid我的经验是一维排列用 flex二维布局用 grid。所谓一维是指你主要关心一行元素怎么排、怎么对齐二维是指你要同时控制行和列。居中本身大多是一维问题所以 flex 出场的频率更高。对比项FlexGrid定位一维布局沿主轴排列二维布局行列同时控制居中写法justify-contentalign-itemsplace-items: center子元素宽度可能被拉伸或收缩需要flex-shrink: 0保护默认按轨道尺寸放置剩余空间分配用margin: auto或flex-grow用轨道单位fr或place-content兼容性极广覆盖几乎所有在用的浏览器略晚出现但现代环境完全可用适合场景导航、按钮组、卡片内元素对齐整页骨架、网格画廊、弹窗遮罩层关于flex中子元素被压缩这一点我再强调一下。默认flex-shrink: 1意思是空间不够时子元素会被压缩。如果你把一个固定宽度的按钮放进 flex 容器容器宽度不足时按钮会变形文字会被挤成两行。给按钮加flex-shrink: 0就能锁住宽度。这个细节在移动端特别重要很多按钮突然变窄的诡异现象都是它造成的。5. 实战场景拆解把方案落到真实页面上理论讲完了接下来用几个具体场景把前面的知识串起来。这部分我尽量按真实项目的做法写包括那些文档里不会提的处理细节。5.1 不定宽高的弹窗居中与溢出处理弹窗是居中需求里最典型也最容易出问题的一个。基础做法是把遮罩层设为固定定位铺满视口然后把内容盒在里面居中.overlay { position: fixed; inset: 0; display: flex; justify-content: center; align-items: center; background: rgba(0, 0, 0, 0.45); padding: 24px; box-sizing: border-box; } .dialog { width: 100%; max-width: 520px; max-height: calc(100vh - 48px); overflow-y: auto; background: #fff; border-radius: 8px; }这里有几个细节值得展开。遮罩层用flex而不是绝对定位是因为flex能让弹窗在内容变高时自动参与布局不会跟视口边缘打架。给遮罩层加padding是为了让弹窗在小屏幕上不贴边给弹窗设max-height加overflow-y: auto是为了内容过长时内部滚动而不是让整个弹窗被裁掉。但如果内容特别长flex居中会有一个已知问题当弹窗高度接近容器高度时居中会让上下两端同时溢出而滚动条只能滚到顶部导致上半部分的内容被永久裁掉。解决方式有两种一种是把justify-content和align-items从center换成safe center让浏览器在空间不足时退化为起始对齐.overlay { align-items: safe center; }不过safe关键字的支持度还不算全面所以更稳妥的办法是给弹窗加margin: auto让它在 flex 容器里自己吸收剩余空间.dialog { margin: auto; /* 空间充足时居中空间不足时自动靠上配合 overflow 可滚动 */ }这个margin: auto的写法我在生产环境验证过很多次比safe center靠谱而且不需要考虑兼容性。它的原理和前面 flex 那节讲的一样只不过这次是用在遮罩层内部的弹窗元素上。注意弹窗打开时记得给body加overflow: hidden否则背景页面还能滚动移动端会出现穿透滚动的体感问题。关闭弹窗时再把样式移除。5.2 图片与行内元素居中的基线陷阱图片居中看起来是text-align: center一行的事但实际做起来经常出现底部多出几个像素空白的情况。原因是img默认是行内级替换元素它的基线是图片的底边而行框的基线下方需要留出空间给字母的下沉部分比如g、y的尾巴。这个空间由父容器的line-height和字体度量决定视觉上就表现为图片下方的一条缝隙。三种处理方式按我的推荐顺序排/* 方案一最干净直接让图片变成块级 */ .img-block { display: block; margin: 0 auto; /* 块级图片的水平居中 */ } /* 方案二保持行内改垂直对齐 */ .img-wrap { text-align: center; line-height: 0; /* 或者 font-size: 0 */ } .img-wrap img { vertical-align: middle; } /* 方案三给图片加 display: inline-block 配合 vertical-align */如果图片只是水平居中方案一最省事display: block加margin: 0 auto之后连父容器的text-align都不用写。如果需要行内排列多张图片或者图片和文字混排就用方案二。我个人的习惯是单图居中一律用块级图集才用行内方案。还有一个相关场景是在图片上叠加文字并让文字居中。常见做法是给图片容器设position: relative文字层用绝对定位加translate居中。这里要注意文字层不要用inset: 0加margin: auto因为文字层往往需要撑满容器来接收点击事件。正确做法是文字层宽高都设为 100%然后用display: flex在内部做居中.card { position: relative; } .card-title { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; text-align: center; padding: 16px; box-sizing: border-box; }这样文字层完全覆盖图片点击热区没问题文字也稳定居中。5.3 全屏加载与自适应居中容器全屏加载动画是最简单也最能体现方案差异的场景。目标是让一个图标在视口正中央不管窗口怎么缩放都不跑偏。.loading-screen { position: fixed; inset: 0; display: grid; place-items: center; background: rgba(255, 255, 255, 0.9); }这里我用grid加place-items因为只有一个子元素代码最短语义也最清晰。用inset: 0而不是width: 100%; height: 100%是因为固定定位下inset会让元素自动贴合视口四边不需要处理滚动条宽度带来的那点偏差。说到滚动条这是全屏居中的一个经典坑。用width: 100vw的时候vw单位是包含滚动条宽度的如果页面存在垂直滚动条容器会被撑出一点点横向溢出出现横向滚动条。用width: 100%或者用inset: 0就不会有这个问题因为它们的参照是视口的可见区域不含滚动条。我在一个后台项目里排查了半小时才定位到这个原因从那以后全屏容器统一用inset: 0。另外如果容器高度用100vh在移动端浏览器里也有个老问题地址栏收起和展开时vh的计算方式不一致会导致布局跳动。现代做法是用100dvh动态视口高度它会跟随地址栏状态变化。如果项目需要兼容不支持dvh的环境可以写成.hero { min-height: 100vh; min-height: 100dvh; /* 支持的浏览器会覆盖上一行 */ }这种先写兜底值、再写新单位的写法是很通用的渐进增强套路值得记住。6. 常见问题排查与避坑清单这一节是我这些年攒下来的问题记录基本覆盖了居中失效的绝大多数情况。你可以把它当成速查表用。6.1 居中失效原因速查表现象可能原因处理方式margin: 0 auto没反应元素宽度是auto撑满了父容器设width或max-width或用width: fit-contentmargin: 0 auto没反应元素是行内级或者被float了改display: block或取消浮动text-align: center没反应属性写在了子元素上移到父容器或者改用margin: autoheight: 100%没反应父元素没有确定高度给父元素设高或改用100vh/min-heightflex 垂直居中失效容器高度由内容撑开没有剩余空间给容器加min-height或固定高度flex 子元素被压扁默认flex-shrink: 1给子元素加flex-shrink: 0图片底部有缝隙行内元素基线对齐留白加display: block或父容器line-height: 0绝对定位居中后位置偏移用margin-top写死了负数改用translate或inset加margin: auto弹窗内容多时上半部分被裁居中对齐导致两端溢出弹窗改用margin: auto配合max-height和溢出滚动出现横向滚动条用了100vw且存在纵向滚动条改用100%或inset: 06.2 几个我从实际项目里踩出来的坑坑一transform让内部的固定定位元素失去参照。有一次做弹窗弹窗用translate居中里面有个关闭按钮用了position: fixed想固定在屏幕右上角结果它跑到弹窗所在位置去了。原因就是transform创建了新的包含块固定定位元素的参照物从视口变成了这个被变换的祖先元素。修复方式是把按钮模板挪到弹窗外的层级或者把居中方案换成inset: 0加margin: auto。坑二给table-cell里的元素加margin完全无效。表格单元格的布局规则和外边距处理跟普通块级盒子不一样内部元素的外边距经常被忽略。如果一定要在单元格里做间距用padding更可靠。这也是我不太推荐table-cell方案的原因之一它的行为太特殊容易让后来维护的人困惑。坑三多个子元素时误用 flex 居中导致布局全乱。在一个卡片里同时放了头像、标题、标签三个元素给容器加了justify-content: center; align-items: center结果三个元素挤在中间还各自垂直居中跟设计稿完全不符。这种情况正确的做法是给容器加display: flex; align-items: center然后用margin-left: auto把右侧元素推过去或者给子元素之间加gap。居中是针对单个元素的需求元素多了要考虑的是排列而不是居中。坑四响应式断点切换时忘了检查对齐方向。在移动端把flex-direction从row改成column之后原来的justify-content: center变成了垂直方向居中视觉上没有问题但align-items: stretch让元素在水平方向被拉满原本想要的居中显示卡片变成了卡片占满整行。改方向之后一定要把两个对齐属性都过一遍。坑五min-height: 100vh在移动端地址栏展开时导致内容被顶。这个前面提过用dvh单位解决或者用height: 100%配合html, body都设高。后者的写法是html, body { height: 100%; margin: 0; } .full-screen { min-height: 100%; display: grid; place-items: center; }这套写法在移动端的老项目里很稳因为html和body的高度就是视口的可见高度不受地址栏状态影响。7. 一些关于选型的个人体会写了这么多方案最后落到实际开发上我自己的选择顺序其实很固定。单行文字或简单按钮line-height一把过快而且没有副作用。图片水平居中display: block加margin: 0 auto两行搞定。块级容器水平居中width或max-width配margin: 0 auto这是最不容易出错的一条路。垂直居中或者两个方向都要居中直接上flex需要更短写法或者只有一个子元素时用grid加place-items。只有在需要脱离文档流、做浮层或者兼容特殊环境时才回头考虑绝对定位和table-cell。这套顺序不是最优的只是我在真实项目里用下来调试成本最低的。因为居中问题最麻烦的地方不在于写不出来而在于写完之后出现的那些看起来对、实际上差几个像素的偏差以及在不同屏幕尺寸下的表现差异。选一个副作用少的方案把精力留给真正复杂的布局逻辑这是我这些年做前端最实在的一条经验。顺带说一句邮件模板这个特殊场景。HTML 邮件的渲染引擎对flex和grid的支持非常有限很多邮件客户端甚至不支持外部样式表。这种情况下表格布局加align属性反而是唯一可靠的选择margin: 0 auto都经常失效。如果你要做邮件模板的居中别参考网页的做法老老实实用table配aligncenter和valignmiddle这是那个领域里的通用做法跟现代前端是两套体系。还有一个小技巧分享一下。当你实在搞不清某个居中为什么失效时最快的排查方式不是猜而是打开开发者工具在元素面板里把鼠标悬到那个盒子上看它的外边距区域有没有可分配的空间。如果左右外边距区域是零宽度的那说明元素自身已经撑满了父容器问题不在居中属性上而在宽度设置上。这个观察方法比一行行删样式快得多我几乎每次调试居中问题都是从这个动作开始的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑