如何居中一个 Div 元素

如何居中一个 Div 元素

从基础的流式布局自动边距到高级的CSS Grid布局的多种居中方法。无论是简单的图片居中,复杂的对话框在视口中的居中,还是大小不一元素的层叠居中,你都能找到适合的解决方案。适合所有水平的开发者,旨在帮助你构建坚实的CSS知识基础,提升布局能力和创造力。
author
Wonderhows February 18, 2024

引言

长期以来,在父元素内居中一个子元素一直是CSS中的一个难题。随着CSS技术的发展,我们现在有了更多的工具来解决这个问题,选择也变得多样化。

我创建了这个教程,旨在帮助你理解不同居中方法之间的优劣,并提供一系列策略,帮助你在各种情况下实现元素的居中。

实际上,这个主题比我最初想象的要有趣得多 😅。即便你已经使用CSS一段时间,我相信你也能从中学到至少一种新的居中策略!

使用自动边距实现居中

我们首先看到的居中策略之一是使用自动边距。要在水平方向上居中一个元素,我们可以设置边距为特殊的auto值:

首先,我们需要限制元素的宽度。因为在默认的流式布局中,元素会水平扩展以填满所有可用空间,我们无法居中一个占满整个宽度的元素。

理想情况下,我希望元素能根据其内容自动调整大小。fit-content正是这样一个神奇的属性值,它让元素的宽度像高度一样,根据内容来确定大小。

为什么要设置max-width而不是width呢? 目的是防止元素水平方向上的无限扩展。如果设置了width,那么元素的大小就会被固定,当容器过窄时,元素就会溢出。如果你把“容器宽度”调节到最小,就会发现元素随着容器的缩小而缩小。

现在,当我们的元素宽度受到限制时,我们就可以使用 自动边距 来实现居中。

自动边距就像是 贪吃的河马,总是尽可能多地占据空间。例如,如果我们只设置margin-left: auto,所有额外的空间都会作为左边距。当我们同时设置margin-left: auto和margin-right: auto时,两边的空间会被平均占据,从而使元素居中。

此外,我之前用margin-left和margin-right是因为它们更常见,但现在有一个更现代的属性margin-inline,它可以同时设置左右边距为auto。这个属性在主流浏览器中都得到了很好的支持。

尽管这种居中方式已经存在很久了,但我仍然常常使用它。特别是在只需要居中一个子元素而不影响其他兄弟元素的场景中,例如在博客文章中段落之间插入图片时。

让我们继续探索更多居中技巧。

使用Flexbox实现居中

Flexbox是一个专为控制一组元素在主轴上的分布而设计的布局模式,它提供了强大的居中工具。

我们可以从同时在水平和垂直方向上居中一个元素开始:

Flexbox居中的一个特点是,即使子元素大小超出了其容器,它依然能够工作。试着缩小宽度和高度,你会发现元素是如何对称地溢出的。

Flexbox同样适用于多个子元素。我们可以通过flex-direction属性来控制它们的排列方式。

在本教程中,Flexbox是我最常使用的居中模式。它非常灵活,适用于各种情况,是一个很好的默认选择。

在视口中居中

到目前为止,我们讨论的都是如何在父容器内居中元素。但如果我们想在更大的范围内,比如整个视口中居中元素,又该怎么做呢?这类元素包括对话框、提示框和GDPR横幅。

这就涉及到了 定位布局,这是一种在流布局之外,将元素锚定到其他位置的布局方式。

下面是一个例子:

在所有我们将讨论的策略中,这可能是最复杂的。让我们逐步分析。

我们使用position: fixed来将元素固定在视口中。可以将视口想象成网站前面的一块玻璃板,像是火车窗外滚动的风景。而固定定位的元素就像是附在这块玻璃上的小虫子。

然后,我们设置inset: 0px,这是一个简写,它同时设置top、left、right和bottom为0px。

仅凭这两个属性,元素会填满整个视口,从每个边缘扩展到0px。这在某些情况下可能有用,但不适用于我们现在的需求。我们需要对其大小进行限制。

我们选取的确切值取决于具体情况,但通常我们需要设置默认的宽度和高度(使用width和height),以及最大宽度和高度(使用max-width和max-height),以防元素在较小的视口上溢出。

这里有一个有趣的地方:我们设置了一个看似不可能的条件。我们的元素不能同时靠近左边和右边,并且宽度只有12rem(假设视口比12rem宽)。我们只能满足其中两个条件:

CSS渲染引擎会通过优先级来解决这个矛盾。它会优先考虑宽度约束,因为这看起来更重要。如果无法同时靠近左边和右边,它会根据页面的阅读方向来选择一个边缘;比如,在英语这样的从左到右的语言中,元素会靠近左边缘。

但是,当我们引入margin: auto时,情况就变了。这个属性改变了浏览器解决这个矛盾的方式;它会让元素居中,而不是靠边。

与流布局中的自动边距不同,这个技巧可以同时在水平和垂直方向上居中元素。

这个技巧有四个关键要素:

固定定位 使用inset: 0px固定在所有四个边缘 限制宽度和高度 自动边距 我们同样可以使用这个技巧在单一方向上居中元素。例如,我们可以制作一个水平居中但靠近视口底部的GDPR cookie横幅:

省略top: 0px后,我们就消除了垂直方向上的不可能条件,横幅就被固定在底部边缘。我还使用了calc函数来限制最大宽度,确保元素周围总是有一定的缓冲空间。

我还将margin: auto替换为margin-inline: auto,虽然这不是必需的,但更为精确。

居中未知大小的元素

上面的方法要求我们为元素指定一个确切的大小,但如果我们不知道元素应该有多大怎么办呢?

过去,我们不得不依赖变换技巧来实现这一点,但幸运的是,我们的朋友fit-content也可以在这里帮助我们!

这将使元素根据其内容自动缩小。我们仍然可以设置一个max-width来限制它的大小(例如 max-width: 60vw),但我们不必设置最大宽度;元素会自动适应视口的大小。

使用CSS Grid实现居中

我所知道的最简洁的方式来同时在水平和垂直方向上居中某物是使用CSS Grid:

place-content属性是justify-content和align-content的简写,同时对行和列应用相同的值。结果是一个1×1网格,其单元格恰好位于父容器的中心。

与Flexbox的区别

这个解决方案看起来很像我们的Flexbox解决方案,但重要的是要记住它使用了完全不同的布局算法。在我自己的项目中,我发现CSS Grid解决方案并不像Flexbox那样普遍有效。

例如,考虑以下设置:

奇怪吧?为什么CSS Grid版本变得这么小?

原因在于:子元素被赋予了width: 50%和height: 50%。在Flexbox中,这些百分比是基于父元素.container计算的,这正是我们所期望的。

然而,在CSS Grid中,这些百分比是相对于网格单元格的。我们说子元素的宽度应该是其所在列的50%,高度是其所在行的50%。

我们实际上没有给行或列指定一个明确的尺寸,我们没有定义grid-template-columns或grid-template-rows。当我们省略这些信息时,网格轨道会根据其内容计算大小,围绕其内部的内容缩小。

最终结果是我们的网格单元格与.element的原始尺寸相同,然后该元素缩小到该网格单元格的50%。

这是一个复杂的话题,我不想偏离主题;我的意思是CSS Grid是一个复杂的布局算法,有时它的复杂性可能会成为障碍。我们可以通过添加更多的CSS来解决这个问题,但使用Flexbox可能更简单。

居中元素堆叠

CSS Grid还提供了另一种居中的超能力。通过CSS Grid,我们可以将多个元素分配到同一个单元格中:

一小堆彩虹色玩具放在桌子上

.element

一堆彩色的水滴在黑色背景上

.element

一幅粉红色的城市天际线

.element

一个霓虹和平标志

.element

我们依然保持一个1×1的网格,但现在让 多个 子元素占据同一个单元格,使用grid-row / grid-column实现。

如果不清楚,这是这种布局的HTML结构示意:

在其他布局模式下,元素会水平或垂直排列,但在这种CSS Grid布局中,元素会从后向前堆叠,因为它们都被安排在同一个网格空间中。这是一个很有趣的设计!

令人惊讶的是,即使子元素的大小不同,这种方法也能奏效。看看这个:

一小堆彩虹色玩具放在桌子上

.element

一堆彩色的水滴在黑色背景上

.element

一幅粉红色的城市天际线

.element

一个霓虹和平标志

.element

揭示网格

在这个演示中,我们添加了虚线红线来显示网格行和列的位置。注意这些线是如何扩展以包含最大的子元素的;当所有元素加入后,生成的单元格的大小与粉红色的天际线图片一样宽,与多彩的太空图片一样高!

为了使这种布局有效,我们还需要另一个属性place-items: center。place-items是justify-items和align-items的简写,用于控制图像在网格单元格内的对齐方式。

没有这个属性,网格单元格虽然居中,但单元格内的图像都会堆积在左上角:

一小堆彩虹色玩具放在桌子上

.element

一堆彩色的水滴在黑色背景上

.element

一幅粉红色的城市天际线

.element

一个霓虹和平标志

.element

揭示网格

这是CSS中的高级内容。你可以在我最近发布的CSS Grid的交互式指南中了解更多关于CSS Grid布局模式的工作原理。

居中文本 在CSS中,文本有其独特的处理方式。我们不能使用本文中探讨的技术来影响文本中的单个字符。

例如,如果我们尝试用Flexbox居中一个段落,我们实际上是在居中整个文本块,而不是文本本身:

Lorem Ipsum只是印刷和排版行业的虚拟文本。自1500年代以来,Lorem Ipsum一直是该行业的标准虚拟文本。

Flexbox会将段落在视口中居中,但不会影响文本中的单个字符。它们仍然保持左对齐。

我们需要使用text-align属性来实现文本的居中:

Lorem Ipsum只是印刷和排版行业的虚拟文本。自1500年代以来,Lorem Ipsum一直是该行业的标准虚拟文本。

未来的居中方式

之前,我们看到可以使用自动边距在流式布局中实现元素的水平居中。如果我们想要元素同时垂直居中,我们需要切换到其他布局模式,比如Flexbox或Grid。

但未来可能会有变化。

看看这个:

这是怎么回事? align-content原本是CSS Grid的属性,但这里我们并没有设置display: grid。这是怎么实现的呢?

我对CSS的一个重要认识是,它实际上是一系列布局算法的集合。我们编写的属性是这些算法的输入。align-content最初在Flexbox中实现,在CSS Grid中扮演了更重要的角色,但它并未在默认的流式布局中实现,至少直到现在。

正如我在2024年初写这篇文章时所说,浏览器制造商正在将align-content引入流式布局,使其可以控制内容在“块”方向上的对齐。这个新特性目前还处于早期阶段;目前只有Chrome Canary(需要启用特定功能标志)和Safari Technical Preview支持。

(我必须指出,上面的演示是虚构的。我在Chrome Canary和Safari TP中体验了新的align-content支持,然后使用Flexbox重新创建了完全相同的效果。对于这种误导,我表示歉意!)

超越常规模式

多年来,我一直将CSS视为一系列可重复使用的模式。我有许多记忆中的代码片段,可以用来解决当前面临的问题。

这种方法效果不错,但有时感觉有限。偶尔,一些我曾经多次使用的代码片段突然表现出不同的行为。

当我深入学习CSS时,我对这种语言的理解发生了彻底的变化。很多事情变得清晰起来。我不再依赖记忆中的代码片段,而是依赖我的直觉!✨

在这个教程中,我们探讨了一些实用的居中模式,希望它们在你下次需要居中时能派上用场。然而,我们这里只是触及了表面;现代CSS提供了 众多 实现居中的方法!与其记住更多的代码片段,不如建立一个关于CSS工作原理的坚实的心智模型,这样我们就可以随时想出解决方案。

我花了两年时间创造了深入了解CSS的终极资源,名为 CSS for JavaScript Developers。

如果你觉得这个教程有帮助,你一定会从我的课程中获益良多。我们对整个CSS语言采用了类似的方法,构建了对所有不同布局算法如何工作的直观理解。

它包含了交互式文本内容(如本博客文章),还有视频、练习、现实世界启发的研讨会,甚至还有一些小游戏。这与你参加过的任何其他课程都不同。

如果这听起来对你有吸引力,你可以在这里了解更多信息:

选择合适的居中方法

在结束之前,让我们总结一下我们所学的内容,构建一个决策树,以帮助我们确定何时使用哪种居中方法。

  • 如果我们想要水平居中一个单独的元素,而不干扰其兄弟元素,我们可以使用流式布局的自动边距策略。
  • 对于像模态框或横幅这样的浮动UI元素,我们可以使用定位布局和自动边距来实现居中。
  • 要居中堆叠的一组元素,我们可以使用CSS Grid。
  • 要居中文本,我们可以使用text-align。这可以与其他任何方法结合使用。
  • 最后,在大多数其他情况下,我们可以使用Flexbox。这是最通用的方法,适用于居中一个或多个子元素,无论是水平还是垂直,无论它们是被包含还是溢出的。

就像木匠的工作室一样,我们在这个教程中介绍了许多有用的工具,每个工具都有其特定的用途。我希望你在这里学到了一些新的居中策略!愉快地进行居中吧。❤️

comments powered by Disqus