Flexbox布局指南

CSS:Flexbox布局全指南

Posted by Ted on December 20, 2017

本文翻译来自https://css-tricks.com/snippets/css/a-guide-to-flexbox/

一、背景

Flexbox Layout 模块旨在让容器container内的item布局、排列、散布item变得更加高效, 尽管它们的尺寸是未知或者是动态的(所以是flex可伸缩的)。

Flexbox Layout 背后的主要思想是为了让容器container有能力去调整它的items的宽高顺序,从而最好地填充可用的空间(主要是为了适应各种尺寸的设备和屏幕),一个可伸缩的container扩展它的items去填充可用的剩余空间,或者让它们缩小以防止超出范围。

更为重要的是,与常规的相比(block基于垂直,inline基于水平), Flexbox Layout 是方向不可知的。虽然常规的那些布局对于页面也有效,但是它们缺乏灵活性来支持大型或复杂的应用程序(特别是在改变方向,调整大小,拉伸,缩小等方面)。

注意: Flexbox布局最适合应用程序的组件和小规模布局,而Grid布局则适用于较大规模的布局。

二、基础和术语

由于flexbox是一个完整的模块,而不是一个单一的属性,它涉及到很多东西,包括整套属性。 其中的一些属性是用来设置container(父元素,被称为“flex container”),而其他的是用来设置在items(子元素,称为“flex items”)。

img

img

如果常规布局基于block和inline流动方向,则 flex layout基于“弹性流动方向”。 请从规范中看一下这个数字,它们解释了flex布局背后的主要思想。

img

一般来说,将会沿着主轴 main axis(从 main-startmain-end) 或者纵轴 cross axis(从 cross-startcross-end)来放置items

  • main axis - 主轴,用来布置items的主要轴线,小心,它不一定是水平的,还是要看 flex-direction 这个属性
  • main-start main-end - flex items 将会被放置在container 上,从 main-start 开始一直到 main-end.
  • main size - 主轴方向上的大小
  • cross axis - 垂直于主轴方向的轴被称为纵轴. 它的方向取决于主轴的方向
  • cross-start cross-end - items填充在 container里,沿着 cross-start 朝着cross-end.
  • cross size - 纵轴方向上的大小

三、Container属性

display

定义了container是一个弹性可伸缩的,值有可能为flex或者inline-flex

.container {
  display: flex; /* or inline-flex */
}

flex-direction

建立了主轴,从而决定了items放置在container里的方向, Flexbox是(除了可选的wrapping)单向布局的概念。 将items视为主要布置在水平行或垂直列中。

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}

img

依次对应

flex-wrap

一般默认情况,items都会试图填充进一行里,如果你不想这样,你可以通过这个属性来改变它

img

.container{
  flex-wrap: nowrap | wrap | wrap-reverse;
}
  • nowrap (默认): 所有的弹性items都在一行
  • wrap: 弹性items将会变成多行,从上到下
  • wrap-reverse: 从下到上的多行.

flex-flow

适用于父容器元素,这是一个简短的flex-directionflex-wrap属性,它们一起定义了flex container的主轴和交叉轴。 默认是row nowrap。

flex-flow: <‘flex-direction’> || <‘flex-wrap’>

justify-content

这定义了沿主轴的对齐方式。 当一条线上的所有items都不是弹性,或者是弹性的、但已经达到其最大尺寸时,它有助于分配剩余空间。 当items溢出时,它也对项目的对齐进行控制。

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}

img

  • flex-start (默认): items 从开始的地方一一放置
  • flex-end: items从结束的地方一一惊喜放置
  • center: 从中间沿着轴向两边
  • space-between: items 均匀地分布在轴上; 第一个items在轴开始, 最后一个在轴结束的地方
  • space-around: items均匀分布在轴上,周围有相同的间隙。请注意,视觉上间隙不相等,因为所有的项目在两边都有相同的间隙,第一个item左边只有一个间隙,最后一个item右边只有一个间隙,其他的左右均有两个间隙
  • space-evenly: items均匀分布在轴上,所有的items间隙都相同。不管是第一个或是最后一个。

align-items

这定义了如何在当前轴上沿纵向对齐的方式。 把它看作是纵轴轴(垂直于主轴)的 justify-content 版本。

.container {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

img

  • stretch (默认): 填充整个container (依旧遵照min-width/max-width)
  • flex-start: 靠上对齐
  • flex-end: 靠底部对齐
  • center: 纵轴中间对齐
  • baseline: 与基线对齐方式一样

align-content

这种对齐方式是用于多行对齐,类似于’段落对齐’,与justify-content类似,不过这里是每一行在纵轴方向

注意:只有一行items时,此属性不起作用。

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

img

  • stretch (默认): 除了保留间隙会填满
  • flex-start: 靠上对齐
  • flex-end: 靠下对齐
  • center: 居中对齐
  • space-between: 均匀分布,相等空隙
  • space-around: 均匀分布

四、item属性

order

默认情况下,Flex项目按源代码顺序排列。 但是,order属性可以控制它们在container中的显示顺序。

.item {
  order: <integer>; /* default is 0 */
}

img

flex-grow

.item {
  flex-grow: <number>; /* default 0 */
}

这定义了item在必要时增长空间的能力。它接受一个没有单位的数字,用作比例。 它规定了该itme应该占用container内的可用空间量。 如果所有item的flex-grow的值设为1,则容器中的剩余空间将平均分配给所有的item, 如果其中一个item的值为2,其他为1,则剩余空间将占用其他空间的两倍(或者至少会尝试)。

img

flex-shrink

定义了item在必要时进行缩小的能力

.item {
  flex-shrink: <number>; /* default 1,必须大于0 */
}

flex-basis

.item {
  flex-basis: <length> | auto; /* default auto */
}

在剩余空间分配之前,这个定义了元素的默认大小。 它可以是一个长度(例如20%,5rem等)或关键字。 auto关键字的意思是“看我的宽度或高度属性”(这是临时由main-size关键字完成,直到被弃用)。 content 关键字的意思是“根据item的内容来确定它的大小” - 这个关键字还没有得到很好的支持,所以很难去测试,也很难知道它的 max-content, min-content, and fit-content 是什么。

flex

这是 flex-grow, flex-shrink and flex-basis 集合. 第二个和第三个 (flex-shrinkand flex-basis) 可选的,默认值是 0 1 auto.

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

简易你设置这个属性而不是单独对各个属性进行设置。

align-self

对某个item在纵轴方向上进行单独定义

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

img

注意

float, clear and vertical-align 在item上没有效果.

五、实例

Example 1

我们来开始一个简单的实例,解决一个日常的问题,居中,如果用flexbox就再简单不过了

.parent {
  display: flex;
  height: 300px; /* Or whatever */
}

.child {
  width: 100px;  /* Or whatever */
  height: 100px; /* Or whatever */
  margin: auto;  /* Magic! */
}

依赖一个事实就是, margin设置为 auto 在 container吸纳额外空间. 所以设置垂直居中为 auto 将会使item在两个轴上都完美居中.

看看其他属性. 考虑如果列出 6 items, 因为美观,这6个item都有固定尺寸,但是都可以自动调整大小.当我们调整浏览器大小时,我们需要它们在水平方向上均匀且完美地分布

.flex-container {
  /* 我们首先定义一个 flex layout 的上下文 */
  display: flex;
  
  /* 我们来定义一个流动方向
   * 与相同:
   * flex-direction: row;
   * flex-wrap: wrap;
   */
  flex-flow: row wrap;
  
  /* 再定义看看怎么进行分布剩余空间 */
  justify-content: space-around;
}

完整代码如下:

html

<ul class="flex-container">
  <li class="flex-item">1</li>
  <li class="flex-item">2</li>
  <li class="flex-item">3</li>
  <li class="flex-item">4</li>
  <li class="flex-item">5</li>
  <li class="flex-item">6</li>
</ul>

Css

@import "compass/css3";

.flex-container {
  padding: 0;
  margin: 0;
  list-style: none;
  
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  
  -webkit-flex-flow: row wrap;
  justify-content: space-around;
}

.flex-item {
  background: tomato;
  padding: 5px;
  width: 200px;
  height: 150px;
  margin-top: 10px;
  
  line-height: 150px;
  color: white;
  font-weight: bold;
  font-size: 3em;
  text-align: center;
}

img

Example 2 不同屏幕下的导航栏效果

img

img

img

/* 大屏 */
.navigation {
  display: flex;
  flex-flow: row wrap;
  /* This aligns items to the end line on main-axis */
  justify-content: flex-end;
}

/* 中屏 */
@media all and (max-width: 800px) {
  .navigation {
    /* When on medium sized screens, we center it by evenly distributing empty space around items */
    justify-content: space-around;
  }
}

/* 小屏 */
@media all and (max-width: 500px) {
  .navigation {
    /* On small screens, we are no longer using row direction but column */
    flex-direction: column;
  }
}

完整代码

Html:

<ul class="navigation">
  <li><a href="#">Home</a></li>
  <li><a href="#">About</a></li>
  <li><a href="#">Products</a></li>
  <li><a href="#">Contact</a></li>
</ul>

Css:

@import "compass/css3";

.navigation {
  list-style: none;
  margin: 0; 
  
  background: deepskyblue;
  
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  
  -webkit-flex-flow: row wrap;
  justify-content: flex-end;
}

.navigation a {
  text-decoration: none;
  display: block;
  padding: 1em;
  color: white;
}

.navigation a:hover {
  background: darken(deepskyblue, 2%);
}

@media all and (max-width: 800px) {
  .navigation {
    justify-content: space-around;
  }
}

@media all and (max-width: 600px) {
  .navigation {
    -webkit-flex-flow: column wrap;
    flex-flow: column wrap;
    padding: 0;
  }
  
  .navigation a { 
    text-align: center; 
    padding: 10px;
    border-top: 1px solid rgba(255,255,255,0.3); 
    border-bottom: 1px solid rgba(0,0,0,0.1); 
  }

  
  .navigation li:last-of-type a {
    border-bottom: none;
  }
}

Example 3 不同屏幕下的布局栏效果

img

img

img

完整代码

html:

<div class="wrapper">
  <header class="header">Header</header>
  <article class="main">
    <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>  
  </article>
  <aside class="aside aside-1">Aside 1</aside>
  <aside class="aside aside-2">Aside 2</aside>
  <footer class="footer">Footer</footer>
</div>

Css:

.wrapper {
  display: flex;  
  flex-flow: row wrap;
  font-weight: bold;
  text-align: center;
}

.wrapper > * {
  padding: 10px;
  flex: 1 100%;
}

.header {
  background: tomato;
}

.footer {
  background: lightgreen;
}

.main {
  text-align: left;
  background: deepskyblue;
}

.aside-1 {
  background: gold;
}

.aside-2 {
  background: hotpink;
}

@media all and (min-width: 600px) {
  .aside { flex: 1 auto; }
}

@media all and (min-width: 800px) {
  .main    { flex: 3 0px; }
  .aside-1 { order: 1; } 
  .main    { order: 2; }
  .aside-2 { order: 3; }
  .footer  { order: 4; }
}

body {
  padding: 2em; 
}