使用Flexbox构建经典布局

220 阅读6分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

使用Flexbox构建经典布局

Flexbox提供了一种非常有效的方式来定位,排序和分布元素,即使在视窗或元素大小不明确或动态变化时亦是如此。

Flexbox 的优势可以用一句话来表达:“在不需要复杂的计算之下,元素的大小和顺序可以灵活排列 ”,即“Flexbox 为您提供了元素大小和顺序的灵活性”。如此一来,可以让 Web 的布局变得简单地多。

Flexbox构建一些经典布局,也是在实践中经常使用的一些布局,比如等高布局,分屏(或等分列),水平垂直居中Sticky Footer圣杯布局Grid Frameworks(简单的网格系统) 等,我们平常使用的比如: 浮动(float),定位(position)和内联块(display:inline-block)等实现布局会比较困难,甚至还需要一定的CSS黑魔法(Hark手段),但我们使用Flexbox就容易的多。

而在Web布局中,水平垂直居中是使用很频繁的,比如Icon图标在容器中水平垂直居中,一个标题在导航栏中水平垂直居中等。

水平垂直居中常见的效果一般有两种,单行(或单列)水平垂直居中和多行(或多列)水平垂直居中。

在Flexbox中,我们可以在flex容器上使用:

justify-content:center;让flex项目水平居中。

  • 对于单行而言,使用align-items:center;可以让flex项目垂直居中,当然也可以使用align-content:center;不过要显式设置flex-wrap的值为wrap或wrap-reverse.
  • 对于多行而言,flex-direction的值设置为column,可以使用align-items:center让flex项目水平居中,然后使用justify-content:center实现垂直方向居中
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="container">
      <div class="item-single">元素</div>
      <div class="item-multiple"><span>1</span><span>2</span><span>3</span></div>
    </div>
  </body>
</html>
<style>
  .container {
    display: flex;
    border: 1px solid #000;
    width: 500px;
    height: 300px;
  }
  .item-single {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100px;
    height: 100px;
    background: skyblue;
  }
  .item-multiple {
    display: flex;
    flex-direction: column;
    width: 100px;
    height: 100px;
    background: gray;
    justify-content: center;
    align-items: center;
  }
</style>

你还可以使用align-self来实现flex项目垂直居中,设置align-self:center即可

.container {
  display: flex;
  justify-content: center;
}
.item {
  align-self: center;
}

如果要实现单个flex项目在flex容器中水平垂直居中,你还可以使用justify-content和align-content的简写place-content来设置为center,但需要配合flex-wrap来使用,一般设置为wrap.

.container {
 display: flex;
 place-content:center;
}
​

当然我们只需要控制一个flex项目在容器中水平垂直居中时,使用margin:auto;也是可以的。

等高布局

在设置一些多卡片内容,多个盒子排布的时候,需要给他们设置相同高度的排列布局,这时我们使用flexbox就很容易实现。

img

如果要实现上面这种等高布局的卡片排列形式,我们使用Flexbox来布局

<div class="cards">
    <div class="card">
        <figure>
            <img src="thumb.png" alt="缩略图" />
        </figure>
        <h3>Card Title</h3>
        <p>Card Describe</p>
        <button>Button</button>
    </div>
    <!-- 其他 Card -->
</div>
<style>
  .cards {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
​
.card {
  display: flex;
  flex-direction: column;
  flex: 1 1 300px;
}
</style>

我们给卡片都设置了flex,使所有的卡片都变成等高的,但这时也会有一个问题,虽然卡片都是等高的了,但是里面的内容会因为数量而造成扩展和压缩,所有我们设置给内容标签p上flex-grow:1;就可以解决卡片内容的大小;当然我们也可以设置底部按钮button元素margin-top:auto;如果不希望按钮宽度占满整行,还可以设置align-self:flex-start(flex-end)。

均分列(等分列)布局

在Web中,均分列的布局效果有很多,特别是在Web移动端中,像一些底部菜单栏,商品展览栏,卡片分布栏等,这些布局效果最大的特点就是每列的宽度是相等的。

image-20221212115827825

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div class="container">
      <div class="item">code <span>首页</span></div>
      <div class="item">code <span>逛一逛</span></div>
      <div class="item">code <span>商品</span></div>
      <div class="item">code <span>我的页面</span></div>
    </div>
  </body>
</html>
<style>
  .container {
    display: flex;
  }
​
  .item {
    flex: 1;
    min-width: 0;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
  }
</style>

要真正达到均分列,只在 Flex 项目上显式设置 flex:1 是不够的,还需要在 Flex 项目上显式设置 min-width 值为 0 。这也就是说,为什么 min-width:0 很重要。

不过,在使用 flex:1 的时候,需要额外注意的是,这个 1 会被视为 flex-grow 的值。如果你要使用 flex ,更建议的做法是,显式地使用 flex 属性的三个值,比如 flex: 1 1 0%flex: 1 1 100%

圣杯布局

对于经典的圣杯布局,它有:

页头

页脚

主内容

左侧边栏

右侧边栏

在HTML源码的文档中,主内容

位于两个侧边栏之前

页头

和页脚没有固定额的高度,由其内容或盒模型属性值(margin,padding,border)决定相关大小

在垂直方向上,中间三列(

)的高度占据和之外的浏览器视窗高度,并且随着内容的增多而变高。

在水平方向,一般情况之下两个侧边栏也是由其内容来决定大小,但多数情况之下会给两个侧边栏设置一个固定宽度。中间主内容列 <article> 占据两侧边栏之外的浏览器视窗宽度,并且随着内容增加,不会出现水平滚动条。

Sticky Footer布局

页脚

的位置会随着页头(Header),主内容(Content)高度而变化,但当页头和主内容内容较小,其高度总和小于浏览器视窗高度时,页脚始终位于浏览器视窗底部

而对于Sticky Footer布局,使用Flexbox只需要保持主内容容器随着父容器的剩余空间扩展,其实就是给主容器设置一个flex-grow:1;就可以了。

如果不希望当浏览器视窗高度较小,主内容容器高度进行收缩,你可以将其flex-chrink设置为0,同样,为了避免页头和页脚收缩,也可以在它们上面设置flex-chrink为0。

除了上面这种方法外,还可以设置页脚margin-top:auto来实现布局效果。

百分百无滚动布局

百分百不滚动布局也是Web中常见的一种布局,比如要设置一个弹窗,包括顶部容器,下面滚动容器

需要效果是顶部不动,中间的内容较多时可以滚动

主体代码是:

<!-- 整个 Modal 高度是 100vh -->
<modal>
    <modal-header>
        <!-- 固定高度 -->
    </modal-header>
    <modal-content>
        <!-- 滚动容器:flex: 1 -->
    </modal-content>
</modal>
modal {
  height: 100vh;
  display:flex;
  flex-direction:column;
}
modal-header {
  height:120px;
}
modal-content {
 flex:1;
 overflow-y:auto;
}

经过上面书写,会在ios系统上触发一个Bug,就是在滚动内容上显式设置overflow-y:scroll,滚动依然会失效,成这个 Bug 是因为我们上面的 CSS 代码触发了 Flex 项目的边缘情况。

这时关键是需要给设置flex:1的滚动容器的父元素设置min-width:0,在设置flex:1的flex项目上尽可能重置它的最小尺寸值。