内容简介:快速简介:在我的理想世界里,CSS Grid 和 Flexbox 应当作为一个整体一起出现,才能组成完整的网页布局系统。然而,我们先有了 Flexbox 属性,因为它比浮动(floats)更适合用来做网格布局,所以出现了很多以 Flexbox 为基础的网格布局系统。事实上,很多人觉得 Flexbox 弹性布局令人困扰或者难以理解,都是因为尝试把它作为网格布局的方法。在接下来的一系列文章里面,我会花一点时间来详细讲解 Flexbox 弹性布局 —— 以之前我用来理解 grid 属性的方式。我们一起看看 Fl
快速简介:在我的理想世界里,CSS Grid 和 Flexbox 应当作为一个整体一起出现,才能组成完整的网页布局系统。然而,我们先有了 Flexbox 属性,因为它比浮动(floats)更适合用来做网格布局,所以出现了很多以 Flexbox 为基础的网格布局系统。事实上,很多人觉得 Flexbox 弹性布局令人困扰或者难以理解,都是因为尝试把它作为网格布局的方法。
在接下来的一系列文章里面,我会花一点时间来详细讲解 Flexbox 弹性布局 —— 以之前我用来理解 grid 属性的方式。我们一起看看 Flexbox 设计是为了什么,它擅长处理什么,以及我们为什么不选择它作为布局的方法。在这篇文章中,我们会详细看一下,当你在样式表添加 display: flex
的时候,究竟会发生什么。
一个 Flex 容器,拜托了!
为了使用 Flexbox 布局,你需要一个元素作为 flex 容器,在 CSS 中,使用 display: flex
:
HTML:
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> 复制代码
CSS:
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: flex; flex-direction: row-reverse; } .item { width: 100px; height: 100px; padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); } 复制代码
请看 Rachel Andrew(@rachelandrew)在CodePen 上的这个例子: Smashing Flexbox Series 1: display: flex; 。
让我们花一点点时间来思考一下到底 display: flex
意味着什么。在 Display Module Level 3 中,display 的每一个值都由两个部分构成:内部显示模式和外部显示模式。当我们使用 display: flex
时,我们其实定义的是 display: block flex
。flex 容器的外部显示模式是 block
,它在文档流中显示为正常的块级元素。内部显示模式是 flex
,所以在容器内部的直接子元素按照弹性布局来排列。
可能你之前没仔细想过,但其实已经知道了。flex 容器在页面中和其他块级元素的表现一样。如果你在 flex 容器后面紧跟一个段落,它们两个都会表现为正常的块级元素。
我们也可以把容器的属性设置为 inline-flex
,就和设置成 display:inline flex
一样。比如说有一个行内级别的 flex 容器,容器里还有一些参与 flex 布局的子元素。这个 flex 容器内的子元素的表现就和块级 flex 容器内的子元素表现一样,不同之处就在于容器本身在整体布局中的表现。
HTML:
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> <em>这个 flex 容器是行内元素,所以另一个行内元素会紧跟它后面显示。</em> 复制代码
CSS:
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: inline-flex; } .item { width: 100px; height: 100px; padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); } 复制代码
请看 Rachel Andrew(@rachelandrew)在CodePen 上的这个例子: Smashing Flexbox Series 1: display: inline-flex; 。
元素的外部显示模式决定了它作为盒模型在页面中怎样显示,同时与内部显示模式一起,决定了其子元素的行为。这是一个很有用的思想。你可以把这种思想应用于任何 CSS 定义的盒模型。这个元素将会如何表现?它的子元素又会怎样表现?这些问题的答案就与它们的内部显示模式和外部显示模式有关。
行或者列?
一旦我们定义了 flex 容器之后,一些默认值就开始发挥作用了。在我们没有添加任何其他属性的情况下,flex 子项目(flex item)会按照行来排列。这是因为 flex-direction
属性的默认值就是 row
。如果你不对它进行设置,它就会按照行的方向来显示。 flex-direction
属性是用来设置主轴(main axis)的排列方向,这个属性还有其他的值:
column row-reverse column-reverse
当子项目排成一行的时候,子项目会按照在文档中的顺序,从行内维度的起始边缘依次排列。在规范中,这个边缘就被叫做 main-start
。
main-start
是行内维度的起始位置(Large preview)。
如果我们使用 column
,子项目从块级维度的起始边缘开始排列,因此构成一列。
main-start
是块级维度的起始位置(Large preview)。
当我们使用 row-reverse
时, main-start
和 main-end
的位置互换了,因此,子项目也会相应的按照相反的顺序来排列。
main-start
在内联维度的末尾(Large preview)。
column-reverse
也具有一样的效果。另外还有一点很重要,那就是这些值并不会“改变子项目的顺序”,尽管它们看起来是这样的效果,它们改变的是这些子项目开始排列的位置:通过改变 main-start
来达到目的。所以我们的子项目会按照相反的方向来排列,这仅仅是因为它是从容器的结束位置开始排列的。
另外还有一件很重要的事情要记住,当排列顺序发生改变时,这仅仅是视觉上的,因为我们要求子项目从结束位置开始排列。它们在文档中仍然是原来的顺序,当你使用屏幕阅读器的时候仍然是按照源文档的顺序进行索引。如果你真的想要改变子元素的顺序,不应该使用 row-reverse
,而是直接在文档源中去改变子项目的顺序。
Flexbox 的两条轴线
我们已经讲解了 flexbox 的一个重要特性:能够将主轴(main axis)的方向从行切换为列。这种轴的方向切换,就是为什么我常常认为网格布局中的对齐更容易理解的原因。因为在网格布局中,在两个方向上你都可以采用几乎相同的方式来实现对齐。而对于弹性布局来说会更麻烦点,因为在主轴(main axis)和交叉轴(cross axis)上,子项目的表现是不太相同的。
我们已经了解了主轴(main axis),即你用 flex-direction
属性的值来定义的那根轴线。交叉轴(cross axis)则在另一个方向上。如果你设置 flex-direction: row
,那么你的主轴(main axis)是沿着行的方向,你的交叉轴(cross axis)是沿着列的方向。如果设置 flex-direction: column
,主轴(main axis)是沿着列的方向,交叉轴(cross axis)是沿着行的方向。在这里我们就需要讨论 flexbox 的另外一个重要特点,那就是它与屏幕的物理方向无关。我们不讨论从左到右方向的行,或从上到下方向的列,因为情况并非总是如此。
书写模式
当我在上文中描述行和列的时候,我提到了块级和行内的维度 dimensions 。这篇文章是用英文写的,它是水平的书写模式。这就意味着当你要 Flexbox 显示一行时,子项目会水平的展示。在这个例子中, main-start
位于左边 —— 也就是英文书写模式中中句子开始的位置。
如果我使用的是从右到左书写的语言,比如阿拉伯语的话,起始位置就会位于右边:
HTML:
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> 复制代码
CSS:
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: flex; flex-direction: row; direction: rtl; } .item { width: 100px; height: 100px; padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); } 复制代码
请看 Rachel Andrew(@rachelandrew)在CodePen 上的这个例子: Smashing Flexbox Series 1: row with rtl text 。
flexbox 的初始值意味着,如果我所做的只是创建一个 flex 容器,我的子项目将会从右侧开始显示,并且向左排列。 内联方向的起始位置是你正在使用的书写模式中句子开始的位置 。
如果你使用垂直书写模式并且使用的默认排列方向(这里指 flex-direction: row),此时的行就会是垂直方向的,因为这就是垂直书写方式语言排列行的方式。你可以尝试为 flex 容器设置 writing-mode
属性,把值设置为 vertical-lr
。现在,你再把 flex-direction
设置为 row
,子项目就会排成垂直的一列了。
HTML:
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> 复制代码
CSS:
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: flex; flex-direction: row; writing-mode: vertical-lr; } .item { width: 100px; height: 100px; padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); } 复制代码
请看 Rachel Andrew(@rachelandrew)在CodePen 上的这个例子: Smashing Flexbox Series 1: row with a vertical writing mode 。
所以,一行可以水平的排列, main-start
位于左侧或者右侧,也可以垂直排列, main-start
位于顶部。即使我们的思维习惯了横向排列的文本,很难想象一行垂直排列的文本,但它的 flex-direction
属性的值仍然是 row
!
为了让子项目按照块级维度进行排列,我们可以把 flex-direction
的值设置成 column
或者 column-reverse
。在英语(或者阿拉伯语)这样的水平书写模式里,子项目会从容器顶部开始按照垂直方向排列。
在垂直书写模式中,块级方向横跨整个页面,这也是这种书写模式下块级元素的排列方向。如果你将一列设置为为 vertical-lr
,那么这些块级元素会从左到右进行排列(内部的文本方向仍为垂直排列)。
HTML:
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> 复制代码
CSS:
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: flex; flex-direction: column; writing-mode: vertical-lr; } .item { width: 100px; height: 100px; padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); } 复制代码
请看 Rachel Andrew(@rachelandrew)在CodePen 上的这个例子: Smashing Flexbox Series 1: column in vertical-lr writing mode 。
但是,无论块级元素怎么显示,只要你使用的是 column
方向,那么元素始终处在块级维度之中。
了解一行或者一列能够在不同的物理方向上运行,有助于我们理解网格布局和弹性布局中的一些术语。在网格布局和弹性布局中,并不会使用『左和右』、『上和下』这样的方向,因为我们并不会指定文档的书写模式。现在所有的 CSS 都变的更注重书写模式了。如果你对其他已经支持这种方向差异的 CSS 属性和值有兴趣的话,可以读一下我的这篇文章 Logical Properties and Values 。
总结一下,记住:
-
flex-direction: row
main-start
-
flex-direction: column
main-start
默认对齐方式
当我们设置 display: flex
时,还会发生一些事情,默认的对齐方式会发挥作用。在该系列的其他文章中,我们会好好地了解一下对齐方式。但是,我们现在在探索 display: flex
的时候,也应该看一下这些发挥作用的默认值。
注意: 值得注意的是,尽管这些对齐属性始于 Flexbox 规范,但 Box Alignment(盒模型对齐)会最终覆盖 Flexbox 规范的相关内容,如flexbox 规范中所述。
主轴对齐方式
justify-content
属性的默认值是 flex-start
,就像我们的 CSS 写的那样:
.container { display: flex; justify-content: flex-start; } 复制代码
这就是我们的 flex 子项目(flex item)从 flex 容器的起始边缘开始排列的原因。同样也是当我们设置 row-reverse
时,它们变为从结束边缘开始排列的原因,因为那个边缘变成了主轴(main axis)的起点。
当你看见对齐属性以 justify-
开头时,这个属性就是作用于主轴(main axis)的。也就是说 justify-content
属性规定主轴(main axis)的对齐方式,并将子项目从起始边缘对齐。
justify-content
还有其他的值:
flex-end center space-around space-between space-evenly
这些值用来处理 flex 容器中剩余空间的分布。这就是子项目间会发生移动或者说相互分隔的原因了。如果你添加属性 justify-content: space-between
,剩余空间被平均分配给子项目。当然,这只有在容器有剩余空间的情况下才会发生。如果你的 flex 容器被全部充满了(子项目排列完后,没有任何剩余空间),那么设置 justify-content
属性不会产生任何效果。
你可以把 flex-direction
设置成 column
。因为 flex 容器在没有高度的情况下不会有剩余空间,所以设置 justify-content: space-between
不会发生变化。如果你把容器设置成比展示所需要的高度更高的话,那么这个属性就会发挥作用了:
HTML:
<div class="container"> <div class="item">1</div> <div class="item">2</div> <div class="item">3</div> </div> 复制代码
CSS:
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: flex; flex-direction: column; justify-content: space-between; height: 500px; } .item { width: 100px; height: 100px; padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); } 复制代码
请看 Rachel Andrew(@rachelandrew)在CodePen 上的这个例子: Smashing Flexbox Series 1: column with a height 。
交叉轴的对齐方式
子项目在单一交叉轴的 flex 容器中也会沿着这根交叉轴对齐。这里执行的对齐是子项目沿着交叉轴相互对齐。在接下来的这个例子中,有一个子项目比其他项占据更高的空间,然后其他的子项目会按照某种规范来拉伸到与它相同的高度,这个规范就是 align-items
属性,因为它的初始值就是 stretch
:
HTML:
<div class="container"> <div class="item">One</div> <div class="item">Two</div> <div class="item"> <ul> <li>Three: a</li> <li>Three: b</li> <li>Three: c</li> </ul> </div> </div> 复制代码
CSS:
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: flex; } .item { padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); } .item ul { margin: 0; padding: 0; list-style: none; } 复制代码
请看 Rachel Andrew(@rachelandrew)在CodePen 上的这个例子: Smashing Guide to Layout: clearfix 。
当你在 flex 布局中看到有一个属性是以 align-
开头的,那个就是交叉轴的对齐方式, align-items
属性规定子项目在沿着交叉轴方向上的对齐方式,这个属性的其他的值包括:
flex-start flex-end center baseline
如果你不想其他的子项目跟拉伸到跟最高的那一项一样高的话,设置 align-items: flex-start
,它会把子项目都沿着交叉轴的起始位置对齐。
HTML:
<div class="container"> <div class="item">One</div> <div class="item">Two</div> <div class="item"> <ul> <li>Three: a</li> <li>Three: b</li> <li>Three: c</li> </ul> </div> </div> 复制代码
CSS:
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: flex; align-items: flex-start; } .item { padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); } .item ul { margin: 0; padding: 0; list-style: none; } 复制代码
请看 Rachel Andrew(@rachelandrew)在CodePen 上的这个例子: Smashing Flexbox Series 1: align-items: flex-start 。
flex 子项目的初始值
终于说到这里了,flex 子项目(flex item)也是有初始值的,它们包括:
flex-grow: 0 flex-shrink: 1 flex-basis: auto
这意味我们的子项目(flex item)在默认情况下不会自动充满主轴上的剩余空间。如果 flex-grow
被设置成一个正数,才会导致子项目拉伸并占据剩余空间。
这些子项目(flex item)同样可以收缩。默认情况下, flex-shrink
的值被设置成了 1。这就意味着,如果我们的 flex 容器非常小,那么其中的子元素在溢出容器之前就会自动的缩小以适应容器大小。这是一个非常灵活的属性。总的来说就是,子项目在容器没有足够空间去排列的情况下依然能保持在容器之内,并且不会溢出。
为了在默认情况下获得最好的展示效果, flex-basis
属性的默认值被设置成 auto
,我们会在这个系列的其他文章中好好了解这代表什么。现在,你只需要将 auto
理解为『大到足够适应容器』就行了。在这种情况下,当 flex 容器中有一些子项目,其中的一个子项目相较于其他包含更多的内容,那么它会被分配更多的空间。
HTML:
<div class="container"> <div class="item">Two words</div> <div class="item">Now three words</div> <div class="item"> This flex item has a lot of content and so it is going to need more space in the flex container. </div> </div> 复制代码
CSS:
body { padding: 20px; font: 1em Helvetica Neue, Helvetica, Arial, sans-serif; } * {box-sizing: border-box;} p { margin: 0 0 1em 0; } .container { border: 5px solid rgb(111,41,97); border-radius: .5em; padding: 10px; display: flex; width: 400px; } .item { padding: 10px; background-color: rgba(111,41,97,.3); border: 2px solid rgba(111,41,97,.5); } 复制代码
请看 Rachel Andrew(@rachelandrew)在CodePen 上的这个例子: Smashing Flexbox Series 1: initial values of flex items 。
上面这个例子就是弹性布局灵活性的体现。在 flex-basis
属性的默认值是 auto
,并且子项目(flex item)没有设置尺寸的情况下,它就会有一个 max-content
的基础尺寸。这就是它根据内容自动延伸之后没有经过任何其他包装的尺寸。然后,子项目按照比例来占据剩余空间,详见以下flexbox 规范中的说明。
『注意:分配收缩空间时,是根据基本尺寸乘以弹性收缩系数(flex shrink factor)。收缩空间的大小与子项目设置的 flex-shrink
的大小成比例。比如说有一个较小的子项目,在其他较大的子项目明显收缩之前,是不会被收缩到没有空间的。』
也就是说较大的子项目收缩的空间更多,那么现在我们得到了最终的布局结果。你可以比较一下下面两个截图,都是使用上面的例子,不同的是在第一个截图中,第三个盒子内容较少占据的空间较小,因此相对的每一列的占据的空间更均匀一些。
其他项为了给较大的一项提供空间而自动收缩(Large preview)。
弹性布局会试图帮助我们获得一个合理的最终显示结果,而不需要写 CSS 的人来定义。它不会平均的减少每行的宽度,从而形成一个每行只有几个单词的很高的子项目,而是会给该子项目分配更多的空间用以展示其内容。这种表现正是如何正确弹性布局的关键。它最适用于用于沿着一条轴线排列的元素,以一种灵活和感知内容的方式。这里我简单介绍了一点细节,但在接下来的系列文章中我们会更加深入的了解这些算法。
总结
在这篇文章中,我用弹性布局的属性的一些默认值来介绍当你设置 display: flex
的时候,究竟发生了什么。令人惊讶的是,当你逐步分解之后,发现它原来有这么多内容,并且这些内容就包含了弹性布局的核心特点。
弹性布局是非常灵活的:它会根据你的内容自动地做出不错的选择 —— 通过收缩和拉伸达到最好的展示效果。弹性布局还能感知书写模式:布局中行和列的方向跟书写模式有关。弹性布局通过分配空间,允许子项目在主轴(main axis)上以整体的的方式来对齐。它还允许子项目按照交叉轴来对齐,使得交叉轴上的项目相互关联。更重要的是,弹性布局知道你的内容有多大,并且尽量采用更好的方式来展示你的内容。在接下来的文章中,我们会更加深入的探索,思考我们什么时候以及为什么要用弹性布局。
如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为掘金 上的英文分享文章。内容覆盖 Android 、 iOS 、 前端 、 后端 、 区块链 、 产品 、 设计 、 人工智能 等领域,想要查看更多优质译文请持续关注 掘金翻译计划 、官方微博、 知乎专栏 。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- ios – 在哪里为子类的uitableviewcell创建自动布局约束?
- 学习如何用CSS变量创建网页响应布局 — css var()
- css经典布局系列三——三列布局(圣杯布局、双飞翼布局)
- 四种方法实现──三栏布局(圣杯布局、双飞翼布局)
- 浅谈CSS三栏布局(包括双飞翼布局和圣杯布局)
- css经典布局——圣杯布局
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
iBATIS实战
(加)Clinton Begin、(加)Brandon Goodin、(加)Larry Meadors / 叶俊 / 人民邮电出版社 / 2008-5 / 45.00元
《图灵程序设计丛书•Java系列•iBATIS in Action iBATIS实战》是讲述iBATIS框架的权威著作。书中既详实地介绍了iBATIS的设计理念和基础知识,也讨论了动态SQL、高速缓存、DAD框架等高级主题,还讲解了iBATIS在实际开发中的应用。《图灵程序设计丛书•Java系列•iBATIS in Action iBATIS实战》的最后给出了一个设计优雅、层次清晰的示例程序JGa......一起来看看 《iBATIS实战》 这本书的介绍吧!