Open suhao opened 3 years ago
前端开发,使用CSS进行布局是工作的核心。在做ReactNativeDesktop的实践中,逐步学习了CSS的布局方式。本文将汇总相关的基础知识,以供回顾和总结。
传统的布局方式是通过盒模型,使用display(文档流布局)+position(定位布局)+float(浮动布局)来控制。
按照文档的顺序一个个显示,块元素独占一行,行内元素共享一行。
使元素脱离文档流,浮动起来。
通过position属性来定位。
通过上述盒模型的三种布局方式有一些缺陷,比如我们不能只使用一个属性来实现垂直居中布局,所以就产生了第四种布局方式:flex 布局。可以简便、完整、响应式地实现各种页面布局,Flex即Flexible Box的缩写,意为弹性布局,为盒模型提供最大的灵活性。任何一个容器都可以指定为flex布局,行内元素也可以通过inline-flex属性值来使用flex布局。inline-flex 和 inline-block 一样,对设置了该属性值的元素的子元素来说是个 display:flex 的容器,对外部元素来说是个 inline 的块。
在 flex 中,最核心的概念就是容器和轴,所有的属性都是围绕容器和轴设置的。其中,容器分为父容器和子容器。轴分为主轴和交叉轴(主轴默认为水平方向,方向向右,交叉轴为主轴顺时针旋转 90°)
在使用 flex 的元素中,默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis),主轴开始的位置称为 main start,主轴结束的位置称为 main end。同理,交叉轴开始的位置称为 cross start,交叉轴结束的位置称为 cross end。在使用 flex 的子元素中,占据的主轴空间叫做 main size,占据的交叉轴空间叫做 cross size。
这里需要强调,不能先入为主认为宽度就是 main size,高度就是 cross size,这个还要取决于你主轴的方向,如果你垂直方向是主轴,那么项目的高度就是 main size。
实现 flex 布局需要先指定一个容器,任何一个容器都可以被置顶为 flex 布局,这样容器内部的元素就可以使用 flex 来进行布局。简单说来,如果你使用块元素如 div,你就可以使用 flex,而如果你使用行内元素,你可以使用 inline-flex。
需要注意的是:当时设置 flex 布局之后,子元素的 float、clear、vertical-align 的属性将会失效。
设置了 flex 属性的容器可以通过设置其属性值来设置容器的子元素的排列规则:
flex-direction:设置子元素的排列方向,row(默认值,主轴为水平方向,起点为左端)、row-reverse(主轴为水平方向,起点为右端)、colum(主轴为垂直方向,起点在上沿)、colum-reverse(主轴为垂直方向,起点在下沿)
flex-wrap:设置是否换行,让弹性盒子元素必要时换行显示,不设置默认为不换行(如果容器装不下子元素会相应的收缩);nowrap(默认不换行)、wrap(换行第一行在上)、wrap-reverse(换行第一行在下)
flex-flow:flex-direction 和 flex-wrap 属性的复合属性;默认为row nowrap
justify-content:设置子元素在横轴上的排列对齐方式;flex-start(默认值,左对齐)、flex-end(右对齐)、center(居中)、space-between(两端对齐,子元素间隔相等)
align-items:设置子元素在纵轴上的排列,flex-start(交叉轴的起点对齐)、flex-end(交叉轴的终点对齐)、center(交叉轴的中心点对齐)、baseline(子元素的第一行文字的基线对齐)、stretch(默认值;子元素未设置高度height或设置为auto将占满整个容器高度;如果设置则此属性值无效)
align-content:当有多行子元素时每行子元素之间的排列方式;当只有一行子元素时即flex-wrap属性值为no-wrap时,该属性没有效果;stretch(默认值;子元素默认排列,相当于只设置了flex-wrap: wrap,每行子元素间有一定的间隔)、flex-start(子元素从纵轴的起点开始排列,且行间没有间距)、flex-end(与纵轴的终点对齐,且行间没有间距)、center(与纵轴的中点对齐,行间无间距)、space-between(与纵轴两端对齐,轴线之间的间隔平均分布)、space-around(每行子元素的间隔都相等,且每行子元素之间的间隔比子元素到父元素的距离大一倍)
order:设置某个子元素的排序先后顺序,数值越小,排列越靠前,默认为0
flex-grow:设置子元素的放大比例,默认为0;0时即使存在剩余空间也不放大;1时等分剩余空间;即按照所有子元素的值求和后等分,然后乘以各自的系数值
flex-shrink:子元素缩小比例,默认为1;1时即默认是如果父元素装不下子元素,如果不换行的话那么子元素都按照一样的比例缩小;该属性取负值无效;如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小;如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小
flex-basis:子元素的理想宽度,即子容器在不伸缩情况下的原始尺寸,主轴为横向时代表宽度,主轴为纵向时代表高度;默认值为auto即子元素的本来大小;跟长度width差不多意义,可以设为一个长度值,定义了子元素初始占据的宽度;设置子元素在被放进一个flex容器之前的大小,也就是子元素理想或假设的大小,但是flex-basis并不能保证其实际呈现的大小;但当父元素装不下子元素时,子元素会按照flex-shrink来进行相应比例的缩小,如果没有设置flex-shrink默认情况下每个子元素的压缩率都是一样的;当父元素有空余空间时,设置了flex-basis的子元素并不会自动扩大,而是保持flex-basis的属性值设置的大小
flex:flex-grow、flex-shrink和flex-basis的组合;默认值为0 1 auto;有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)
aligin-self:设置单个子元素的纵轴排列方式;允许单个项目有与其他项目不一样的纵轴排列方式,可覆盖align-items属性;默认值为auto,即跟父元素设置的 align-items 的值指定的纵轴排列方式一样;可能取6个值,设置的值可覆盖掉父元素设置的align-items指定的排列方式;
网格布局,实现二维布局方式。可以让我们摆脱现在布局中存在的文档流限制,换句话说,你的结构不需要根据设计稿从上往上布置了。这也意味着您可以自由地更改页面元素位置。这最适合你在不同的断点位置实现你最需要的布局,而不再需要为响应你的设计而担心HTML结构的问题。
和 table 布局不同的是,grid 布局不需要在 HTML 中使用特定的标签布局,所有的布局都是在 CSS 中完成的,你可以随意定义你的 grid 网格。
没有 HTML 结构的网格布局有助于使用流体、调整顺序等技术管理或更改布局。通过结合 CSS 的媒体查询属性,可以控制网格布局容器和他们的子元素,使用页面的布局根据不同的设备和可用空间调整元素的显示风格与定位,而不需要去改变文档结构的本质内容。
网格线组成了网格,他是网格的水平和垂直的分界线。一个网格线存在行或列的两侧。我们可以引用它的数目或者定义的网格线名称。
网格轨道是就是相邻两条网格线之间的空间,就好比表格中行或列。在网格中其分为grid column和grid row。每个网格轨道可以设置一个大小,用来控制宽度或高度。
网格单元格是指四条网格线之间的空间。所以它是最小的单位,就像表格中的单元格。
网格区域是由任意四条网格线组成的空间,所以他可能包含一个或多个单元格。相当于表格中的合并单元格之后的区域。
使用 grid 布局很简单,通过display属性设置属性值为 grid 或 inline-grid 或者是 subgrid(该元素父元素为网格,继承父元素的行和列的大小) 就可以了。
网格容器中的所有子元素就会自动变成网格项目(grid item),然后设置列(grid-template-columns)和 行(grid-template-rows)的大小,设置 grid-template-columns 有多少个参数生成的 grid 列表就有多少个列。
注:当元素设置了网格布局,column、float、clear、vertical-align属性无效。
如果没有设置 grid-template-columns,那么默认只有一列,宽度为父元素的 100%。设置了 grid-template-columns 的话,设置了几个参数,就有几列(不超过 grid item 的个数),然后设置的 grid-template-row 参数就是每一列的高度(超出列数的高度无效)。
例如:grid-template-columns: 1fr 1fr 2fr; 生成3列
css fr 单位是一个自适应单位,fr单位被用于在一系列长度值中分配剩余空间,如果多个已指定了多个部分,则剩下的空间根据各自的数字按比例分配。fr 是基于网格容器可用空间来计算的(flex 也是一样),所以我们可以和其他单位混合使用,如果需要的话。
例如:grid-template-rows: minmax(100px,200px) minmax(50px,200px),将第一行的高度设置为 minmax(100px,200px),第二行的高度设置为minmax(50px,200px)
如果容器总高度设置为 300px,这时每一列的高度要怎么算呢?总高度是小于第一列高度的最大值和第二列高度的最大值之和的,这样就是先用 总高度 300px - 第一列最小高度 100px - 第二列最小高度 50px = 150px。第一列高度:第一列最小高度 100px + 150px/2 = 175px;第二列高度:第一列最小高度 50px + 150px/2 = 125px
重复行或者列:repeat() 可以创建重复的网格轨道。这个适用于创建相等尺寸的网格项目和多个网格项目。repeat接受两个参数:第一个参数定义网格轨道应该重复的次数,第二个参数定义每个轨道的尺寸。
间距:grid-column-gap创建列与列之间的距离;grid-row-gap创建行与行之间的距离;grid-gap 是 grid-row-gap 和 grid-column-gap两个属性的缩写
我们可以通过表格线行或者列来定位 grid item,grid-row 是 grid-row-start 和 grid-row-end 的简写。grid-column 是 grid-column-start 和 grid-column-end 的简写。如果只提供一个值,指定了 grid-row-start 和 grid-column-start 的值。如果提供两个值,第一个值是 grid-row-start 或者 grid-column-start 的值,第二个值是 grid-row-end 或者 grid-column-end 的值,两者之间必须要用/隔开。这四个值可以用 grid-area 缩写,分别对应 grid-row-start、grid-column-start、grid-row-end、grid-column-end。
和 excel 中的合并单元行/列是相同的(这个需要设置在 grid item 中),grid-column-start、grid-column-end、grid-row-start、grid-row-end,也可以使用 grid-row 和 grid-column 简写的形式,关键词 span 后面紧随数字,表示合并多少个列或行,/ 前面是从第几行/列开始。
在 grid 中,是可以自定义网格线的名称的,然后使用定义好的网格线来进行布局,[col1-start] 网格线名称一定要使用 [] 括住。
什么是网格区域? 网格区域(grid-area)是一个逻辑空间,主要用来放置一个或多个网格单元格(Grid Cell)。他是由四条网格线(Grid line),网格区域每边一条,四边相交组织的网格轨道(Grid Track)。简单点理解,网格区域是有四条网格线交织组成的网格空间,这个空间中可能是一个网格单元格,也可能是多个网格单元格。
定义网格区域 在CSS Grid Layout中定义网格区域有两种方式,一种是通过网格线来定义,另一种是通过grid-template-areas来定义。接下来看看两种定义网格区域的方法在具体使用过程中有何不同。
网格线定义网格区域:使用网格线定义网格区域的方法非常的简单,首先依赖于 grid-template-columns 和 grid-template-rows 显式定义网格线,甚至是由浏览器隐式创建网格线,然后通过 grid-area 属性通过取网格线,组成网格线交织区域,那么这个区域就是所讲的网格区域。在使用 grid-area 属性调用网格线,其遵循的规则是 grid-area: row-start/ column-start / row-end / column-end。
grid-template-areas 定义网格区域:在 CSS Grid Layout 中还可以通过 grid-template-areas 属性来定义网格区域的名称,然后需要放在对应网格区域的元素,可以通过 grid-area 属性来指定。而且重复区域可以使用同一个名称来实现跨区域。另外对于空的轨道区域,可以使用点号 . 来代表
垂直居中真的是已经被讲烂了,这个方式是有很多的,但就是看的太多会导致最后一个都没有记住,所以最好是每一种情况只记住一个最佳实践。
对于居中,不需要背什么“x 种方式实现 xx”这样的例子,我们只需要了解其原理即可写出符合要求的 css。
水平、垂直居中,比较喜欢用绝对定位的方法实现,其次就是使用 table 布局,因为自带垂直居中。如果是单行的行内元素使用 line-height 等于 height,对于多行元素的垂直居中,大部分都是使用 table 元素(求推荐更好的布局),当然还有 flex 和 grid 布局
一般水平居中还是比较容易的,一般都是先看子元素是固定宽度还是宽度未知;如果是固定宽度,这种方式是绝对定位居中,除了使用 margin,我们还可以使用 transform;宽度未知,将子元素设置为行内元素,然后父元素设置 text-align: center。
多个块状元素,上面的方式即使子元素不止一个也想实现水平居中也是有效的,(宽度固定不固定都可,不固定的话就不需要设置宽度,会被自动撑开,但是要考虑到撑爆的情况)。当然也可以使用我们刚刚介绍的 flex,我们只需要让子元素在主轴上的对齐方式设置为居中就可以。
单行行内元素,只需要将子元素的行高等于高度就可以了。多行的行内元素,因为给每一个子元素都设置了 line-height,但是试了很多方法,要不是没有效果,要不然就是又局限性,提到最多的是使用 table-cell 的方式(但是貌似这个方法也有一点弊端,那就是其子元素的表现形式和行内元素类似,子元素不能独占一行);还有一个方法是设置一个空的行内元素,使其 height:100%,display:inline-block,vertical-align: middle; 并且 font-size:0。但是这样方式的原理我还不是很清楚,只是知道要设置一个空元素,高度和父元素相等,并且设置垂直居中的属性。但是,这只是用与所有的行内元素的宽度和不超过父元素的宽度的情况。另一个一劳永逸的方法就是 flex。
经常有看到设计稿是图片和文字垂直居中的,那么怎么才能让图片和文字垂直居中呢?只需要给图片一个 vertical-align: middle; 属性就可以。
我们要实现水平或者垂直居中,应该从两方面下手:元素自带居中的效果或者强制让其显示在中间。
所以我们先考虑,哪些元素有自带的居中效果,最先想到的应该就是 text-align:center 了,但是这个只对行内元素有效,所以我们要使用 text-align:center 就必须将子元素设置为 display: inline; 或者 display: inline-block;;
接下来我们可能会想既然有 text-align 那么会不会对应也有自带垂直居中的呢,答案是有的 vertical-align:,我一直不是很喜欢使用这个属性,因为十次用,9.9 次都没有垂直居中,一度让我怀疑人生。现在貌似也搞得不是很清楚,看了 张鑫旭的文章 居然看得也不是很懂,笑哭。目前就在 table 中设置有效,因为 table 元素 的特性,打娘胎里面带的就是好用。还有一种可以有效的方式是前面提到的空元素的方式,不过感觉多设置一个元素还不如使用 table。
还有一只设置垂直居中的是将行内元素的 line-height 和 height 设置为相同(只适用于单行行内元素)
固定宽度或者固定高度的情况个人认为设置水平垂直居最简单,可以直接使用绝对定位。使用绝对定位就是子元素相对于父元素的位置,所以将父元素设置 position:reletive 对应的子元素要设置 position:absolute,然后使用 top:50%;left:50%,将子元素的左上角和父元素的中点对齐,之后再设置偏移 margin-top: 1/2 子元素高度;margin-left: 1/2 子元素宽度;。这种方式也很好理解。
上面的绝对定位方法只要将 margin 改为 transform 就可以实现宽度和高度未知的居中(兼容性啊兄弟们!(ಥ_ಥ))transformX:50%;transformY:50%;
其实我还真是第一次听说圣杯布局这种称呼,看了下这个名字的由来,貌似和布局并没有什么关系,圣杯布局倒是挺常见的三栏式布局。两边顶宽,中间自适应的三栏布局。
这个布局方式的关键是怎么样才能使得在伸缩浏览器窗口的时候让中间的子元素宽度改变。可以适应浏览器的宽度变化使用百分比设置宽度再合适不过,所以我们要将中间子元素的宽度设置为 100%,左边和右边的子元素设置为固定的宽度。
这里我们要注意的是,中间栏要在放在文档流前面以优先渲染。
将其三个元素的宽度和高度设置好,然后都设置为 float:left。
我们可以看出,现在三个子元素是在一排显示的,因为我们给中间的子元素设置的宽度是 100%,并且中间的子元素在文档流的最前面,最先被渲染。 那么我们要使得三个元素在同一排显示。接下来我们要将 .left 和 .right 向上提。实际上我们是使用 margin-left 为 负值来实现的,我们将 .left 的 margin-left 设置为 -100%(负的中间子元素的宽度),这样,左边的元素就会被“提升”到上一层。 然后就是右边子元素了,只需要设置 margin-left 设置为负的自身的宽度。
现在中间的子元素被遮挡了,只要使得中间的子元素显示的宽度刚好为左边元素和右边元素显示中间的宽度就可以。同时我们还必须保证是使用的半分比的布局方式。
这样的话有一种方式可以即使中间的宽度减少,又可以使中间的宽度仍然使用 100%,那就是设置父元素的 padding 值,将父元素的 padding-left 设置为左边子元素的宽度,将父元素的 padding-right 设置为右边子元素的宽度。
中间的子元素确实是在中间了,那么我们只需要设置相对位置,将左边的子元素和右边的子元素向两边移动就好。
双飞翼布局是为了解决圣杯布局的弊端提出的,如果你跟我一起将上面的圣杯布局的代码敲了一遍,你就会发现一个问题,当你将浏览器宽度缩短到一定程度的时候,会使得中间子元素的宽度比左右子元素宽度小的时候,这时候布局就会出现问题。所以首先,这提示了我们在使用圣杯布局的时候一定要设置整个容器的最小宽度。
圣杯布局和双飞翼布局解决问题的方案在前一半是相同的,也就是三栏全部float浮动,但左右两栏加上负margin让其跟中间栏div并排,以形成三栏布局。
不同在于解决”中间栏div内容不被遮挡“问题的思路不一样:圣杯布局,为了中间div内容不被遮挡,将中间div设置了左右padding-left和padding-right后,将左右两个div用相对布局position: relative并分别配合right和left属性,以便左右两栏div移动后不遮挡中间div。
双飞翼布局,为了中间div内容不被遮挡,直接在中间div内部创建子div用于放置内容,在该子div里用margin-left和margin-right为左右两栏div留出位置。
所以只是一个小小的改动,在我们将中间元素宽度调到比两边元素小的时候,也是可以正常显示,但是如果总宽度小于左边元素或者右边元素的时候,还是会有问题。
前端开发,使用CSS进行布局是工作的核心。在做ReactNativeDesktop的实践中,逐步学习了CSS的布局方式。本文将汇总相关的基础知识,以供回顾和总结。
一、盒模型布局方式
传统的布局方式是通过盒模型,使用display(文档流布局)+position(定位布局)+float(浮动布局)来控制。
1. 文档流布局
按照文档的顺序一个个显示,块元素独占一行,行内元素共享一行。
2. 浮动布局
使元素脱离文档流,浮动起来。
3. 定位布局
通过position属性来定位。
二、Flexbox布局
通过上述盒模型的三种布局方式有一些缺陷,比如我们不能只使用一个属性来实现垂直居中布局,所以就产生了第四种布局方式:flex 布局。可以简便、完整、响应式地实现各种页面布局,Flex即Flexible Box的缩写,意为弹性布局,为盒模型提供最大的灵活性。任何一个容器都可以指定为flex布局,行内元素也可以通过inline-flex属性值来使用flex布局。inline-flex 和 inline-block 一样,对设置了该属性值的元素的子元素来说是个 display:flex 的容器,对外部元素来说是个 inline 的块。
在使用 flex 的元素中,默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis),主轴开始的位置称为 main start,主轴结束的位置称为 main end。同理,交叉轴开始的位置称为 cross start,交叉轴结束的位置称为 cross end。在使用 flex 的子元素中,占据的主轴空间叫做 main size,占据的交叉轴空间叫做 cross size。
这里需要强调,不能先入为主认为宽度就是 main size,高度就是 cross size,这个还要取决于你主轴的方向,如果你垂直方向是主轴,那么项目的高度就是 main size。
实现 flex 布局需要先指定一个容器,任何一个容器都可以被置顶为 flex 布局,这样容器内部的元素就可以使用 flex 来进行布局。简单说来,如果你使用块元素如 div,你就可以使用 flex,而如果你使用行内元素,你可以使用 inline-flex。
需要注意的是:当时设置 flex 布局之后,子元素的 float、clear、vertical-align 的属性将会失效。
1. Flex容器
设置了 flex 属性的容器可以通过设置其属性值来设置容器的子元素的排列规则:
flex-direction:设置子元素的排列方向,row(默认值,主轴为水平方向,起点为左端)、row-reverse(主轴为水平方向,起点为右端)、colum(主轴为垂直方向,起点在上沿)、colum-reverse(主轴为垂直方向,起点在下沿)
flex-wrap:设置是否换行,让弹性盒子元素必要时换行显示,不设置默认为不换行(如果容器装不下子元素会相应的收缩);nowrap(默认不换行)、wrap(换行第一行在上)、wrap-reverse(换行第一行在下)
flex-flow:flex-direction 和 flex-wrap 属性的复合属性;默认为row nowrap
justify-content:设置子元素在横轴上的排列对齐方式;flex-start(默认值,左对齐)、flex-end(右对齐)、center(居中)、space-between(两端对齐,子元素间隔相等)
align-items:设置子元素在纵轴上的排列,flex-start(交叉轴的起点对齐)、flex-end(交叉轴的终点对齐)、center(交叉轴的中心点对齐)、baseline(子元素的第一行文字的基线对齐)、stretch(默认值;子元素未设置高度height或设置为auto将占满整个容器高度;如果设置则此属性值无效)
align-content:当有多行子元素时每行子元素之间的排列方式;当只有一行子元素时即flex-wrap属性值为no-wrap时,该属性没有效果;stretch(默认值;子元素默认排列,相当于只设置了flex-wrap: wrap,每行子元素间有一定的间隔)、flex-start(子元素从纵轴的起点开始排列,且行间没有间距)、flex-end(与纵轴的终点对齐,且行间没有间距)、center(与纵轴的中点对齐,行间无间距)、space-between(与纵轴两端对齐,轴线之间的间隔平均分布)、space-around(每行子元素的间隔都相等,且每行子元素之间的间隔比子元素到父元素的距离大一倍)
2. Flex子元素
order:设置某个子元素的排序先后顺序,数值越小,排列越靠前,默认为0
flex-grow:设置子元素的放大比例,默认为0;0时即使存在剩余空间也不放大;1时等分剩余空间;即按照所有子元素的值求和后等分,然后乘以各自的系数值
flex-shrink:子元素缩小比例,默认为1;1时即默认是如果父元素装不下子元素,如果不换行的话那么子元素都按照一样的比例缩小;该属性取负值无效;如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小;如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小
flex-basis:子元素的理想宽度,即子容器在不伸缩情况下的原始尺寸,主轴为横向时代表宽度,主轴为纵向时代表高度;默认值为auto即子元素的本来大小;跟长度width差不多意义,可以设为一个长度值,定义了子元素初始占据的宽度;设置子元素在被放进一个flex容器之前的大小,也就是子元素理想或假设的大小,但是flex-basis并不能保证其实际呈现的大小;但当父元素装不下子元素时,子元素会按照flex-shrink来进行相应比例的缩小,如果没有设置flex-shrink默认情况下每个子元素的压缩率都是一样的;当父元素有空余空间时,设置了flex-basis的子元素并不会自动扩大,而是保持flex-basis的属性值设置的大小
flex:flex-grow、flex-shrink和flex-basis的组合;默认值为0 1 auto;有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)
aligin-self:设置单个子元素的纵轴排列方式;允许单个项目有与其他项目不一样的纵轴排列方式,可覆盖align-items属性;默认值为auto,即跟父元素设置的 align-items 的值指定的纵轴排列方式一样;可能取6个值,设置的值可覆盖掉父元素设置的align-items指定的排列方式;
三、Grid布局
网格布局,实现二维布局方式。可以让我们摆脱现在布局中存在的文档流限制,换句话说,你的结构不需要根据设计稿从上往上布置了。这也意味着您可以自由地更改页面元素位置。这最适合你在不同的断点位置实现你最需要的布局,而不再需要为响应你的设计而担心HTML结构的问题。
和 table 布局不同的是,grid 布局不需要在 HTML 中使用特定的标签布局,所有的布局都是在 CSS 中完成的,你可以随意定义你的 grid 网格。
没有 HTML 结构的网格布局有助于使用流体、调整顺序等技术管理或更改布局。通过结合 CSS 的媒体查询属性,可以控制网格布局容器和他们的子元素,使用页面的布局根据不同的设备和可用空间调整元素的显示风格与定位,而不需要去改变文档结构的本质内容。
1. 网格线:Grid Lines
网格线组成了网格,他是网格的水平和垂直的分界线。一个网格线存在行或列的两侧。我们可以引用它的数目或者定义的网格线名称。
2. 网格轨道:Grid Track
网格轨道是就是相邻两条网格线之间的空间,就好比表格中行或列。在网格中其分为grid column和grid row。每个网格轨道可以设置一个大小,用来控制宽度或高度。
3. 网格单元格:Grid Cell
网格单元格是指四条网格线之间的空间。所以它是最小的单位,就像表格中的单元格。
4. 网格区域:Grid Area
网格区域是由任意四条网格线组成的空间,所以他可能包含一个或多个单元格。相当于表格中的合并单元格之后的区域。
5. Grid布局
使用 grid 布局很简单,通过display属性设置属性值为 grid 或 inline-grid 或者是 subgrid(该元素父元素为网格,继承父元素的行和列的大小) 就可以了。
网格容器中的所有子元素就会自动变成网格项目(grid item),然后设置列(grid-template-columns)和 行(grid-template-rows)的大小,设置 grid-template-columns 有多少个参数生成的 grid 列表就有多少个列。
注:当元素设置了网格布局,column、float、clear、vertical-align属性无效。
如果没有设置 grid-template-columns,那么默认只有一列,宽度为父元素的 100%。设置了 grid-template-columns 的话,设置了几个参数,就有几列(不超过 grid item 的个数),然后设置的 grid-template-row 参数就是每一列的高度(超出列数的高度无效)。
例如:grid-template-columns: 1fr 1fr 2fr; 生成3列
例如:grid-template-rows: minmax(100px,200px) minmax(50px,200px),将第一行的高度设置为 minmax(100px,200px),第二行的高度设置为minmax(50px,200px)
如果容器总高度设置为 300px,这时每一列的高度要怎么算呢?总高度是小于第一列高度的最大值和第二列高度的最大值之和的,这样就是先用 总高度 300px - 第一列最小高度 100px - 第二列最小高度 50px = 150px。第一列高度:第一列最小高度 100px + 150px/2 = 175px;第二列高度:第一列最小高度 50px + 150px/2 = 125px
重复行或者列:repeat() 可以创建重复的网格轨道。这个适用于创建相等尺寸的网格项目和多个网格项目。repeat接受两个参数:第一个参数定义网格轨道应该重复的次数,第二个参数定义每个轨道的尺寸。
间距:grid-column-gap创建列与列之间的距离;grid-row-gap创建行与行之间的距离;grid-gap 是 grid-row-gap 和 grid-column-gap两个属性的缩写
6. 通过网格线定位 grid item
我们可以通过表格线行或者列来定位 grid item,grid-row 是 grid-row-start 和 grid-row-end 的简写。grid-column 是 grid-column-start 和 grid-column-end 的简写。如果只提供一个值,指定了 grid-row-start 和 grid-column-start 的值。如果提供两个值,第一个值是 grid-row-start 或者 grid-column-start 的值,第二个值是 grid-row-end 或者 grid-column-end 的值,两者之间必须要用/隔开。这四个值可以用 grid-area 缩写,分别对应 grid-row-start、grid-column-start、grid-row-end、grid-column-end。
7. 合并单元行与合并单元列
和 excel 中的合并单元行/列是相同的(这个需要设置在 grid item 中),grid-column-start、grid-column-end、grid-row-start、grid-row-end,也可以使用 grid-row 和 grid-column 简写的形式,关键词 span 后面紧随数字,表示合并多少个列或行,/ 前面是从第几行/列开始。
8. 自定义网格线名称
在 grid 中,是可以自定义网格线的名称的,然后使用定义好的网格线来进行布局,[col1-start] 网格线名称一定要使用 [] 括住。
9. 通过网格区域命名和定位网格项目
什么是网格区域? 网格区域(grid-area)是一个逻辑空间,主要用来放置一个或多个网格单元格(Grid Cell)。他是由四条网格线(Grid line),网格区域每边一条,四边相交组织的网格轨道(Grid Track)。简单点理解,网格区域是有四条网格线交织组成的网格空间,这个空间中可能是一个网格单元格,也可能是多个网格单元格。
定义网格区域 在CSS Grid Layout中定义网格区域有两种方式,一种是通过网格线来定义,另一种是通过grid-template-areas来定义。接下来看看两种定义网格区域的方法在具体使用过程中有何不同。
网格线定义网格区域:使用网格线定义网格区域的方法非常的简单,首先依赖于 grid-template-columns 和 grid-template-rows 显式定义网格线,甚至是由浏览器隐式创建网格线,然后通过 grid-area 属性通过取网格线,组成网格线交织区域,那么这个区域就是所讲的网格区域。在使用 grid-area 属性调用网格线,其遵循的规则是 grid-area: row-start/ column-start / row-end / column-end。
grid-template-areas 定义网格区域:在 CSS Grid Layout 中还可以通过 grid-template-areas 属性来定义网格区域的名称,然后需要放在对应网格区域的元素,可以通过 grid-area 属性来指定。而且重复区域可以使用同一个名称来实现跨区域。另外对于空的轨道区域,可以使用点号 . 来代表
四、常用的CSS布局
1. 水平垂直居中
垂直居中真的是已经被讲烂了,这个方式是有很多的,但就是看的太多会导致最后一个都没有记住,所以最好是每一种情况只记住一个最佳实践。
对于居中,不需要背什么“x 种方式实现 xx”这样的例子,我们只需要了解其原理即可写出符合要求的 css。
水平、垂直居中,比较喜欢用绝对定位的方法实现,其次就是使用 table 布局,因为自带垂直居中。如果是单行的行内元素使用 line-height 等于 height,对于多行元素的垂直居中,大部分都是使用 table 元素(求推荐更好的布局),当然还有 flex 和 grid 布局
一般水平居中还是比较容易的,一般都是先看子元素是固定宽度还是宽度未知;如果是固定宽度,这种方式是绝对定位居中,除了使用 margin,我们还可以使用 transform;宽度未知,将子元素设置为行内元素,然后父元素设置 text-align: center。
多个块状元素,上面的方式即使子元素不止一个也想实现水平居中也是有效的,(宽度固定不固定都可,不固定的话就不需要设置宽度,会被自动撑开,但是要考虑到撑爆的情况)。当然也可以使用我们刚刚介绍的 flex,我们只需要让子元素在主轴上的对齐方式设置为居中就可以。
单行行内元素,只需要将子元素的行高等于高度就可以了。多行的行内元素,因为给每一个子元素都设置了 line-height,但是试了很多方法,要不是没有效果,要不然就是又局限性,提到最多的是使用 table-cell 的方式(但是貌似这个方法也有一点弊端,那就是其子元素的表现形式和行内元素类似,子元素不能独占一行);还有一个方法是设置一个空的行内元素,使其 height:100%,display:inline-block,vertical-align: middle; 并且 font-size:0。但是这样方式的原理我还不是很清楚,只是知道要设置一个空元素,高度和父元素相等,并且设置垂直居中的属性。但是,这只是用与所有的行内元素的宽度和不超过父元素的宽度的情况。另一个一劳永逸的方法就是 flex。
经常有看到设计稿是图片和文字垂直居中的,那么怎么才能让图片和文字垂直居中呢?只需要给图片一个 vertical-align: middle; 属性就可以。
我们要实现水平或者垂直居中,应该从两方面下手:元素自带居中的效果或者强制让其显示在中间。
所以我们先考虑,哪些元素有自带的居中效果,最先想到的应该就是 text-align:center 了,但是这个只对行内元素有效,所以我们要使用 text-align:center 就必须将子元素设置为 display: inline; 或者 display: inline-block;;
接下来我们可能会想既然有 text-align 那么会不会对应也有自带垂直居中的呢,答案是有的 vertical-align:,我一直不是很喜欢使用这个属性,因为十次用,9.9 次都没有垂直居中,一度让我怀疑人生。现在貌似也搞得不是很清楚,看了 张鑫旭的文章 居然看得也不是很懂,笑哭。目前就在 table 中设置有效,因为 table 元素 的特性,打娘胎里面带的就是好用。还有一种可以有效的方式是前面提到的空元素的方式,不过感觉多设置一个元素还不如使用 table。
还有一只设置垂直居中的是将行内元素的 line-height 和 height 设置为相同(只适用于单行行内元素)
固定宽度或者固定高度的情况个人认为设置水平垂直居最简单,可以直接使用绝对定位。使用绝对定位就是子元素相对于父元素的位置,所以将父元素设置 position:reletive 对应的子元素要设置 position:absolute,然后使用 top:50%;left:50%,将子元素的左上角和父元素的中点对齐,之后再设置偏移 margin-top: 1/2 子元素高度;margin-left: 1/2 子元素宽度;。这种方式也很好理解。
上面的绝对定位方法只要将 margin 改为 transform 就可以实现宽度和高度未知的居中(兼容性啊兄弟们!(ಥ_ಥ))transformX:50%;transformY:50%;
2. 圣杯布局
其实我还真是第一次听说圣杯布局这种称呼,看了下这个名字的由来,貌似和布局并没有什么关系,圣杯布局倒是挺常见的三栏式布局。两边顶宽,中间自适应的三栏布局。
这个布局方式的关键是怎么样才能使得在伸缩浏览器窗口的时候让中间的子元素宽度改变。可以适应浏览器的宽度变化使用百分比设置宽度再合适不过,所以我们要将中间子元素的宽度设置为 100%,左边和右边的子元素设置为固定的宽度。
这里我们要注意的是,中间栏要在放在文档流前面以优先渲染。
将其三个元素的宽度和高度设置好,然后都设置为 float:left。
我们可以看出,现在三个子元素是在一排显示的,因为我们给中间的子元素设置的宽度是 100%,并且中间的子元素在文档流的最前面,最先被渲染。 那么我们要使得三个元素在同一排显示。接下来我们要将 .left 和 .right 向上提。实际上我们是使用 margin-left 为 负值来实现的,我们将 .left 的 margin-left 设置为 -100%(负的中间子元素的宽度),这样,左边的元素就会被“提升”到上一层。 然后就是右边子元素了,只需要设置 margin-left 设置为负的自身的宽度。
现在中间的子元素被遮挡了,只要使得中间的子元素显示的宽度刚好为左边元素和右边元素显示中间的宽度就可以。同时我们还必须保证是使用的半分比的布局方式。
这样的话有一种方式可以即使中间的宽度减少,又可以使中间的宽度仍然使用 100%,那就是设置父元素的 padding 值,将父元素的 padding-left 设置为左边子元素的宽度,将父元素的 padding-right 设置为右边子元素的宽度。
中间的子元素确实是在中间了,那么我们只需要设置相对位置,将左边的子元素和右边的子元素向两边移动就好。
3. 双飞翼布局
双飞翼布局是为了解决圣杯布局的弊端提出的,如果你跟我一起将上面的圣杯布局的代码敲了一遍,你就会发现一个问题,当你将浏览器宽度缩短到一定程度的时候,会使得中间子元素的宽度比左右子元素宽度小的时候,这时候布局就会出现问题。所以首先,这提示了我们在使用圣杯布局的时候一定要设置整个容器的最小宽度。
圣杯布局和双飞翼布局解决问题的方案在前一半是相同的,也就是三栏全部float浮动,但左右两栏加上负margin让其跟中间栏div并排,以形成三栏布局。
不同在于解决”中间栏div内容不被遮挡“问题的思路不一样:圣杯布局,为了中间div内容不被遮挡,将中间div设置了左右padding-left和padding-right后,将左右两个div用相对布局position: relative并分别配合right和left属性,以便左右两栏div移动后不遮挡中间div。
双飞翼布局,为了中间div内容不被遮挡,直接在中间div内部创建子div用于放置内容,在该子div里用margin-left和margin-right为左右两栏div留出位置。
所以只是一个小小的改动,在我们将中间元素宽度调到比两边元素小的时候,也是可以正常显示,但是如果总宽度小于左边元素或者右边元素的时候,还是会有问题。
参考文档