CSS实现前端布局更巧妙的方案!在 flex 布局中通过使用 margin 实现水平垂直居中以及其他常见的前端布局

2024-09-13 11:25:49 浏览数 (4)

在前端开发中,实现水平垂直居中一直是个热门话题。随着 CSS Flexbox 布局的普及,开发者们开始更多地使用 justify-contentalign-items 这两个属性来解决这个问题。

然而,还有一种更加简洁、灵活的方式——使用 margin: auto; 来实现居中以及更多实际场景下的特定效果。让我们一起回顾一下常见方式:justify-contentalign-items,然后再来探讨一下使用:margin 的优势,以及如何在实际项目中使用它。


一、常见方式:justify-contentalign-items

1.1 justify-content (用于水平对齐)

justify-content 决定主轴(通常是水平方向)上子元素如何分配空间。常见的取值有:

  • flex-start:元素排列在容器的起始位置(默认值)。
  • flex-end:元素排列在容器的末尾。
  • center:元素在容器内水平居中。
  • space-between:第一个元素与容器起点对齐,最后一个元素与容器终点对齐,其他元素之间均匀分布空间。
  • space-around:每个元素左右两侧都分配均等的空白区域(元素两边的空隙会有一半分布在两端)。
  • space-evenly:所有元素之间、以及与容器两端的空隙都相等。

1.2 align-items(用于垂直对齐)

align-items 决定交叉轴(通常是垂直方向)上子元素如何对齐。常见的取值有:

  • stretch:子元素在交叉轴上填满整个容器高度(默认值,前提是子元素没有设置具体的高度)。
  • flex-start:子元素在交叉轴的起始位置对齐。
  • flex-end:子元素在交叉轴的末端对齐。
  • center:子元素在交叉轴上垂直居中对齐。
  • baseline:子元素以其文本基线对齐。

1.3 flexbox 的常见用法

下面给出一些常见的 flexbox 的使用案例:

示例 : 公共样式
代码语言:javascript复制
.container {
    width: 800px;
    height: 200px;
    margin: 50px auto;
    display: flex;
    border: 1px solid black;
    padding: 10px;
    box-sizing: border-box;
}

.box {
    width: 50px;
    height: 50px;
    background-color: lightblue;
    text-align: center;
    line-height: 50px;
    border: 1px solid #333;
}
示例 1: 水平居中 垂直居中
代码语言:javascript复制
<div class="container example-1">
    <div class="box">1</div>
    <div class="box">2</div>
    <div class="box">3</div>
</div>
代码语言:javascript复制
.example-1 {
    justify-content: center;
    align-items: center;
}

如上图所示,元素在水平和垂直方向都居中了。

示例 2: 水平居中 垂直靠顶
代码语言:javascript复制
<div class="container example-2">
    <div class="box">1</div>
    <div class="box">2</div>
    <div class="box">3</div>
</div>
代码语言:javascript复制
.example-2 {
    justify-content: center;
    align-items: flex-start;
}

如上图所示,justify-content: center; 使元素在水平方向居中;align-items: flex-start; 使元素垂直方向靠近顶部。

示例 3: 水平等间距 垂直居中
代码语言:javascript复制
<div class="container example-3">
    <div class="box">1</div>
    <div class="box">2</div>
    <div class="box">3</div>
</div>
代码语言:javascript复制
.example-3 {
    justify-content: space-between;
    align-items: center;
}

如上图所示,justify-content: space-between; 使元素在垂直方向居中;align-items: center; 使元素在水平方向两端对齐。

示例 4: 水平左对齐 垂直底部对齐
代码语言:javascript复制
<div class="container example-4">
    <div class="box">1</div>
    <div class="box">2</div>
    <div class="box">3</div>
</div>
代码语言:javascript复制
.example-4 {
    justify-content: flex-start;
    align-items: flex-end;
}

如上图所示,justify-content: flex-start; 使元素在水平方向居左;align-items: flex-end; 使元素在垂直方向靠底。

示例 5: 水平等间距 垂直拉伸
代码语言:javascript复制
<div class="container example-5">
    <div class="box">1</div>
    <div class="box">2</div>
    <div class="box">3</div>
</div>
代码语言:javascript复制
.example-5 {
    height: auto;
    justify-content: space-evenly;
    align-items: stretch;
}

如上图所示,justify-content: space-evenly; 会使元素会在水平方向等间距;如果不设置元素的高度,使其自适应,align-items: stretch; 会使其垂直方向拉伸铺满。

1.4 思考与延伸

但你有没有想过,这些写法是否是最简洁的?能否实现我们日常开发的需求呢?有没有更优雅、更轻量的方案呢?

实际上在很多情况下这两个属性并不能够满足我们的开发需求。

比如我需要实现子元素部分集中的布局:

单纯依靠 justify-contentalign-items,很难让几个子元素集中在一起。比如我们希望某些元素靠近并且与其他元素保持一定的间距就会比较麻烦了。 此时为了实现这种布局,通常需要结合 flex-growmargin 或者 space-between,甚至需要使用嵌套的 flex 布局,增加了复杂性。

又或者是等宽子项的平均分布问题:

比如在导航菜单或展示商品卡片时,可能要求子项无论数量多少,都要从左向右均匀分布,并且保持等宽。 通过 justify-content: space-betweenspace-around 可以部分解决这个问题,但是往往会出现无法保证元素从左向右,或者是无法等分的问题。

以及一些其他的情况,如垂直排列的固定间距复杂的网格布局混合布局等,justify-contentalign-items都无法简洁、优雅的解决问题。


二、更优雅的方式:margin

2.1 下使用 margin: auto 使元素居中

其实,Flexbox 布局下还有另一种更加简洁的方法使元素居中——直接使用 margin: auto;。你可能会问,这怎么能居中呢?让我们先看一个例子:

代码语言:javascript复制
<div class="box">
	<div class="item"></div>
</div>
代码语言:javascript复制
.box {
    width: 200px;
    height: 100px;
    border: 2px solid #ccc;
    display: flex; /* 启用 Flex 布局 */
    margin: 100px auto;
}

.item {
    background: red;
    width: 50px;
    height: 50px;
    margin: auto; /* 自动分配外边距 */
}

在这个例子中,我们没有使用 justify-contentalign-items,仅通过设置 .item 元素的 margin: auto;,就实现了水平和垂直居中。

它的工作原理是:在 Flexbox 布局中,margin: auto;根据父容器的剩余空间自动调整元素的外边距,直到子元素居中。

在传统布局中,margin: auto; 主要用于水平居中对齐,不适用于垂直居中。因为普通流布局的垂直方向是由文档流控制的,不支持类似 Flexbox 中的自动调整行为。

代码语言:javascript复制
.container {
    width: 500px;
}

.element {
    width: 200px;
    margin: 0 auto; /* 左右外边距自动分配,实现水平居中 */
}

相比之下,在 Flexbox 布局中,margin: auto; 具有更多的灵活性,可以同时实现水平和垂直居中对齐。

它不仅可以处理水平居中,还可以在 Flexbox 布局下根据剩余空间自动调整外边距,实现完全的居中对齐。

2.2 实现更多实际开发中的布局

示例 1:实现子元素部分集中

在实际开发中,我们常遇到这样一种需求:将元素水平分布在容器内,其中某些元素需要靠近在一起,与其他元素保持一定的自适应距离。 在这种情况下使用 justify-content: space-between 是一种常见的办法,但这种方法也有一定的局限性:每个元素之间平等分配剩余空间,无法实现特定元素之间紧密靠拢。

代码实现:

代码语言:javascript复制
<div class="container c2">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
代码语言:javascript复制
* {
    margin: 0;
    padding: 0;
}

.container {
    width: 500px;
    background: #eee;
    margin: 50px auto;
    padding: 10px;
    display: flex;
}

.item {
    width: 50px;
    height: 50px;
    border: 1px solid #333;
    box-sizing: border-box;
}

.item:nth-child(odd) {
    background: #046f4e;
}

.item:nth-child(even) {
    background: #d53b3b;
}

.c2 .item:nth-child(2){
    margin: 0 0 0 auto; /* 第二个 item 右对齐 */
}

.c2 .item:nth-child(4){
    margin: 0 auto 0 0; /* 第四个 item 左对齐 */
}

在上述代码中,其实除掉一些基本样式的设置,实现了这个布局的关键代码就2行。 具体来说,.c2 .item:nth-child(2)margin: 0 0 0 auto; 使得第二个 .item 紧贴容器的右边缘,而 .c2 .item:nth-child(4)margin: 0 auto 0 0; 使得第四个 .item 紧贴容器的左边缘。这样就使第二个元素的左侧和第四个元素的右侧将会自适应边距间隔。 因此,我们可以使用 margin 巧妙地通过调整子元素的外边距,实现元素的部分集中和对齐布局。

示例 2:实现等宽子项的平均分布

在很多情况下,我们需要将商品卡片或其他内容等宽地分布在每一行中,使每个子项都具有相同的宽度并且平均分布,每一行都是从左到右。

这种布局通常用于网格展示或商品列表等场景,确保每个子项在视觉上统一且整齐。

在这种情况下直接使用 justify-contentalign-items 可能会出现以下问题:

  1. 使用 space-between 时如果最后一行的元素数量不足以填满整行,剩余的元素会分散到两侧,留出较大的空白区域,导致布局不整齐。
  1. 使用 space-around 时如果最后一行的元素数量不满,元素会在行中均匀分布,导致它们集中在中间,而不是靠左或对齐其他行。

大家在遇到这些情况时是不是就在考虑换用 grid 布局了呢?先别急,我们其实直接通过 margin 就可以直接实现的!

在这里我们可以使用 margin 的动态计算来实现等宽子项的平均分布

代码实现:

代码语言:javascript复制
<div class="container c3">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
代码语言:javascript复制
* {
    margin: 0;
    padding: 0;
}

.container {
    width: 500px;
    background: #eee;
    margin: 50px auto;
    padding: 10px;
    display: flex;
    flex-wrap: wrap;
}

.item {
    width: 50px;
    height: 50px;
    border: 1px solid #333;
    box-sizing: border-box;
}

.item:nth-child(odd) {
    background: #046f4e;
}

.item:nth-child(even) {
    background: #d53b3b;
}

.c3 .item {
    --n: 5; /* 每行显示的子项数量 */
    --item-width: 50px; /* 子项宽度 */
    --space: calc(100% / var(--n) - var(--item-width)); /* 计算子项之间的间距 */
    --m: calc(var(--space) / 2); /* 左右间距的一半 */
    margin: 10px var(--m); /* 动态计算左右的间距 */
}

在在上述代码中,除掉基础的样式,实现了这个布局的关键代码仅仅5行。通过动态计算 margin,我们能够简单而有效地实现等宽子项的平均分布,使布局更加简洁明了。


三、总结

在前端开发中,实现各种页面布局一直是一个常见的需求。

传统的做法如使用 justify-contentalign-items 属性已经被广泛采用,但这种方法有时可能显得不够简洁或灵活。

在适当的情况下直接使用 margin 进行布局是一种更优雅、简洁的替代方案,可以在 Flexbox 布局中有效地实现居中对齐和一些复杂的布局需求。掌握并运用这种方法,可以提高开发效率,并使布局更加优雅。快来玩起来吧!

0 人点赞