CSS 布局与定位

577 阅读12分钟

flex布局(弹性布局)

采用 Flex 布局的父元素叫容器(container) ,它的所有顶层子元素称为项目(items)

image.png

首先,需要将容器元素(父元素)class="container",项目元素(子元素)class="item"。并设置容器元素:

.container {
  display: flex | inline-flex;  父元素是独占一行/行内排列
}

容器内存在两根轴:

  • 主轴:水平,默认从左到右,项目默认沿主轴排列。
  • 交叉轴:垂直,默认从上到下。

容器的属性

首先将container元素设置为flex布局

display: flex;

1. flex-direction 主轴方向

 flex-direction: row | row-reverse | column | column-reverse;
  • row(默认值):主轴为水平,从左到右。
  • row-reverse:主轴水平,从右往左。
  • column:主轴垂直,从上到下。
  • column-reverse:主轴垂直,从下到上。

2. flex-wrap:元素排不下,是否换行

flex-wrap: nowrap | wrap | wrap-reverse;
  • nowrap(默认):不换行,不断挤的更小,设置items的width也不好使了。
  • wrap:换行,第一行在上方。
  • wrap-reverse:换行,第一行在下方。

image.png

flex-flow :flex-direction 和 flex-wrap的合写,默认值为row nowrap

flex-flow: <flex-direction> || <flex-wrap>;

3. justify-content:items 在主轴对齐方式

justify-content: flex-start | flex-end | center | space-between | space-around;

下面假设主轴为从左到右:

  • flex-start(默认值):左对齐,向主轴开始对齐
  • flex-end:右对齐
  • center: 居中
  • space-between:两端对齐,项目之间的间隔都相等。
  • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

image.png

4. align-items:items 在交叉轴对齐方式

align-items: flex-start | flex-end | center | baseline | stretch;

下面假设交叉轴从上到下:

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • baseline: 项目的第一行文字的基线对齐。
  • stretch(默认值):如果项目未设置高度时,将占满整个容器的高度。

image.png

5. align-content:items太多一行放不下,出现多行多轴线的对齐

align-content: flex-start | flex-end | center | space-between | space-around | stretch;

image.png

  • flex-start:与交叉轴的起点对齐。
  • flex-end:与交叉轴的终点对齐。
  • center:与交叉轴的中点对齐。
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch(默认值):轴线占满整个交叉轴。

items 属性

单独选中某个item:

.item:first-child { }   /* 第一个item儿子 */
.item:nth-child(2) { }  /* 第二个item儿子  */
.item:nth-child(3) { }  /* 第三个item儿子 */
...
.item:last-child{ }    /* 最后一个item儿子 */

1. order:items 排列顺序

项目的排列顺序,数值越小,排列越靠前,默认为0。-99~-1,0,1~99

2. flex-grow:items放大比例

默认为0,即如果存在剩余空间,也不放大,能有多小有多小。

.item {
  flex-grow:1;  /* 所有item同宽度铺满整个container */
}

若container容器的宽度设置为400px,三个items的放大比例为 1:2:1,那么三个items的实际占据为:100px,200px,100px。

.item:first-child {
  width:100px;
  flex-grow:1; 
}
.item:nth-child(2) {
  width:50px;
  flex-grow:2; 
} 
.item:first-child {
  width:50px;
  flex-grow:1; 
}  

若三个items的放大比例为 1:1:1,那么三个items的实际占据比例为,设置的width+(400-100-50-50)/3

3. flex-shrink:items缩小比例

默认为1,(未设置宽度时)items会能缩多小缩多小。

.item {
  flex-shrink:1;  /* 当空间不足时,items 同比例缩小 */
}

如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

.item:first-child {
  flex-shrink:1; 
}
.item:nth-child(2) {
  flex-shrink:0; /* 不想变瘦 */
}
.item:first-child {
  flex-shrink:1;
}  

4. flex-basis:项目基准宽度

默认值为auto,即项目的本身设置的宽度。浏览器根据这个属性,计算主轴是否有多余空间。

一旦设定为某具体数值,项目的width属性失效。

.item1 {
  width:100px;  
  flex-basis:auto;   /* 项目宽度为设置的宽度100px */
}

.item2 {
  width:100px;       /*  失效  */
  flex-basis:300px;  /* 项目宽度为300px */
}

flex:是flex-grow, flex-shrinkflex-basis的合写,默认值为0 1 auto。后两个属性可选。

.item {
  flex: 0 1 auto;  /* 等同于写 flex:0; */
}

5. align-self :让单个项目有特殊的对齐方式

可覆盖align-items属性。默认值为auto,其余与align-items属性值一致。

align-self: auto | flex-start | flex-end | center | baseline | stretch(默认);

image.png

flex:1 与 flex:auto

  • flex: 1 代表 flex:1 1 0% 基准宽度为0,items设置的width失效,items能够实现真正的均分
  • flex: auto代表flex: 1 1 auto 此时如果设置了items的width,items有可能不等分:宽度一部分要考虑设置width的宽度,还要考虑将多余的均分

左右两边固定距离,中间自适应的方法:两边元素设置固定宽度,中间元素flex-grow: 1

总结

  • 布局:display: flex
  • 流动方向:flex-direction: row / column
  • 是否换行:flex-wrap: wrap
  • 主轴如何对齐:justify-content: center / space-between
  • 纵轴如何对齐:align-items: center

Grid布局——网格布局

flex需要按照横竖轴线来设置每个项目对齐方式,可以看作是一维布局。grid功能更加强大,将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局,首先明确以下概念:

  • 容器:最外层的父元素。
  • 项目:容器的顶层子元素,gird只对项目生效。
  • 单元格cell:n行和m列会产生n x m个单元格。
  • 网格线grid line:n行有n + 1根水平网格线,m列有m + 1根垂直网格线。

容器的属性

首先,设置容器元素为grid布局:

.container {
  display: grid | inline-grid;  父元素是独占一行/行内排列
}

容器内存在两根轴:

grid-template-columns 列宽, grid-template-rows 行高

指定了一个三行三列的网格

grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;

或者使用百分比、repeat、fr份数、auto

grid-template-columns: 33.33% 33.33% 33.33%;
grid-template-rows: 33.33% 33.33% 33.33%;
​
grid-template-columns: repeat(3, 33.33%);
grid-template-columns: repeat(3, 100px 20px 80px); /* 6列,第一列和第四列的宽度为100px */
grid-template-columns: 1fr 1fr 1fr; /* 三等分 */
grid-template-columns: 150px 1fr 2fr;/* fr与绝对长度的单位结合使用,第一列的宽度为150像素,第二列的宽度是第三列的一半 */
grid-template-columns: 100px auto 100px; /*第二列的宽度,基本上等于该列单元格的最大宽度  */

grid-row-gap 行间距, grid-column-gap 列间距, grid-gap 合写

grid-row-gap: 20px;
grid-column-gap: 40px;
grid-gap: 20px 40px; /*先行后列 */

grid-template-areas 划分区域

划分出9个单元格,然后将其定名为ai的九个区域:

grid-template-areas: 'a b c'
                     'd e f'
                     'g h i';

多个单元格合并成一个区域,将9个单元格分成header页眉、aside侧边、main主要内容、footer页脚四个区域:

grid-template-areas: "header header header"
                     "aside  main   aside"
                     "footer footer footer";

item属性

grid-column/row-start/end 指定项目所在网格

指定1号项目从左边第1根垂直网格线开始,右边第3根垂直网格线结束。

.item:first-child {
  grid-column-start: 1;
  grid-column-end: 3; 
  grid-row-start: 2;  
  grid-row-end: 4;
}

以上内容可合写成:

grid-column: 1 / 3;
grid-row: 2 / 4;

可再次合写成:

 grid-area: 2 / 4 / 1 / 3;

image.png

也可用grid-area来指定1号项目位于main区域

.item:first-child {
  grid-area: main;
}

定位

定位:快速精准地在脱离文档流束缚的情况下将元素放在你想放置的位置。就跟精确制导定位系统一样,输入坐标就可以轻松搞定。

定位分类

定位模式是否脱标占有位置是否可以使用边偏移移动位置基准
静态定位static不脱标,正常模式×默认值
相对定位relative脱标,占有位置相对自己原来位置移动
绝对定位absolute完全脱标,不占有位置相对于相对定位父级移动位置
固定定位fixed完全脱标,不占有位置相对于视口viewport移动位置

注意

  • 绝对定位是相对于相对定位父级,也就是从该元素向上找离的最近的一个position不为static的祖先,如果没有则相对于 viewport 定位。

sticky 粘性定位

基于滚动后的位置来定位。在 position:relative 与 position:fixed 定位之间切换,用作导航。

#one { 
  position: sticky; 
  top: 10px; 
}
  • 在 viewport 视口滚动到元素 top 距离小于 10px 之前,元素为相对定位。
  • 而当页面滚动,使得viewport超出目标区域时,元素为固定定位,不再随着滚动条滚动,直到 viewport视口回滚到阈值以下。
  • 指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生效,否则其行为与相对定位相同。

层叠上下文——一个的小世界

image-20211127094739036.png 在被一个父元素包裹着的层叠上下文中,俯视由上到下依次可以看见的是:

内联子元素 > 浮动元素 > 块级子元素 > 边框 > 背景

  • 元素的z-index属性,默认为auto,计算出来的值约等于0。将定位元素(position不为static的元素)的z-index=1/2/....999就超越了最顶层的文字,z-index=-1/-2/...就落到了背景下面,只有这两种选择,不会在中间那些区域做夹层。 image-20211127102427529.png

z-index作用域

每个处于自己的小世界里的z-index才有可比性:

  • 如果a2、b2的z-index分别是10、5,那么a2盖住b2,因为他们同在container为祖先的小世界里。
  • 如果给a的z-index是1,这时a与b2在container小世界里比较,1<5,所以b2盖住a2
<div class=container>
    <div class="a">
        <div class="a2">10</div>
    </div>
    <div class="b">
        <div class="b2">5</div>
    </div>
</div>

总结:有哪些属性可以创建层叠上下文?(z-index默认值是auto 不会创建层叠上下文的)

  • 根元素(HTML)
  • z-index值不为"auto",且:
    • position值为absolute绝对定位relative相对定位的元素
    • flex的子元素
    • grid的子元素
  • position值为fixedsticky的元素,z-index可为auto
  • opacity属性值小于1的元素
  • transform属性值不为"none"的元素

两栏布局

⼀般两栏布局指的是左边⼀栏宽度固定,右边⼀栏宽度自适应

<body>
  <div class="container">
    <div class="left"></div>
    <div class="right"></div>
  </div>
</body>

1 利用左浮动+右margin-left

左边元素宽度设置为200px,并且设置向左浮动。将右边元素的margin-left设置为200px,宽度设置为auto(默认为auto,撑满整个父元素)。

.container {
  width:100%;
  height:500px;
  border:1px solid black;
}
.left {  
  width: 200px; 
  height:100%;
  float:left;
  background: tomato; 
}
.right { 
  width: auto; 
  height:100%;
  background: gold; 
  margin-left: 200px; 
}

jsbin.com/xemiqejayu/…

2 利用左浮动+右overflow:hidden

左边设置浮动,右边设置overflow:hidden就触发了BFC,BFC的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠。

.left {  
  width: 200px; 
  height:100%;
  float:left;
  background: tomato; 
}
.right { 
  width: auto; 
  height:100%;
  background: gold; 
  overflow:hidden;
}

jsbin.com/newomiyuce/…

3 利用flex布局

将左边元素设置为固定宽度200px,将右边的元素设置为flex:1。

.container {
  width:100%;
  height:500px;
  border:1px solid black;
  display:flex;
}
.left {  
  width: 200px; 
  height:100%;
  background: tomato; 
}
.right {  
  height:100%;
  background: gold; 
  flex:1; 
}

jsbin.com/xowejawabe/…

4 左绝对定位+右margin-left

将⽗级元素设置为相对定位。左边元素设置为absolute定位。将右边元素的margin-left的值设置为200px。

.container {
  width:100%;
  height:500px;
  border:1px solid black;
  position:relative;
}
.left {  
  width: 200px; 
  height:100%;
  background: tomato;
  position:absolute;
  top:0;
  left:0;
}
.right {  
  height:100%;
  background: gold; 
  margin-left:200px; 
}

jsbin.com/bejufufaza/…

5 右绝对定位

.container {
  width:100%;
  height:500px;
  border:1px solid black;
  position:relative;
}
.left {  
  width: 200px; 
  height:100%;
  background: tomato;
}
.right {  
  height:100%;
  background: gold; 
  position:absolute;
  top:0;
  left:200px;
  right:0;
  bottom:0;
}

jsbin.com/qobeteyaji/…

三栏布局

指的是页面中⼀共有三栏,左右两栏宽度固定,中间自适应的布局。

<body>
  <div class="container">
    <div class="left">左边</div>
    <div class="main">中间</div>
    <div class="right">哈哈</div>
  </div>
</body>

1 flex布局

父元素设置display:flex;左右两侧固定宽度,中间flex:1

.container {
  width:100%;
  height:500px;
  border:1px solid black;
  display:flex;
}
.left {  
  width: 100px; 
  height:100%;
  background: tomato;
}
.right {  
  width:100px;
  height:100%;
  background: gold;  
}
.main {  
  height:100%;
  background: orange; 
  flex:1;   
}

jsbin.com/wopiquqoxi/…

2 左右绝对定位+中间margin-left/right

父元素设置为相对定位,左右两边设置为绝对定位,中间使用margin-left

.container {
  width:100%;
  height:500px;
  border:1px solid black;
  position:relative;
}
.left {  
  width: 100px; 
  height:100%;
  background: tomato;
  position:absolute;
}
.right {  
  width:100px;
  height:100%;
  background: gold;  
  position:absolute;
  top:0;
  right:0;
}
.main {  
  height:100%;
  background: orange; 
  margin-left:100px;   
}

jsbin.com/fukereyeru/…

水平垂直居中

让一个子元素在父元素内水平垂直居中

<body>
  <div class="container">
    <div class="item"></div>
  </div>
</body>

1 flex布局

设置父元素的justify-content:centeralign-items:center,去设置主轴/交叉轴的对齐方式

.container {
  width:100%;
  height:400px;
  border:1px solid black;
  display:flex;
  justify-content:center;
  align-items:center;
}
.item {
   width:100px;
   height:100px;
   background:orange; 
}

jsbin.com/?html,css,o…

2 绝对定位+四马分尸+margin:auto

.container {
  position:relative;
}
.item {
   width:100px;
   height:100px;
   position:absolute;
   top:0;
   left:0;
   right:0;
   bottom:0;
   margin:auto;  
}

jsbin.com/kegixamona/…

3 绝对定位+margin-top/left:-50%

.container {
  width:100%;
  height:400px;
  border:1px solid black;
  position:relative;
}
.item {
   width:100px;
   height:100px;
   background:orange;
   position:absolute;
   top:50%;
   left:50%;
   margin-top:-50px;
   margin-left:-50px;
}

jsbin.com/gazetedafu/…

4 绝对定位+translate

.container {
  position:relative;
}
​
.item {
   width:100px;
   height:100px;
   position:absolute;
   top:50%;
   left:50%;
   transform:translate(-50%,-50%);
}

jsbin.com/himusoloto/…

外边距合并问题

1 父子上下外边距合并

在父div里面有子元素div1时,若父元素div在没有设置overflow:hidden或者是border属性,则父元素的margin-top = max(父元素设置的margin-top,子元素设置的margin-top)

body {
  background:pink;
}
.parent {
  width:200px;
  height:200px;
  background:red;
  margin-top:50px;
}
.son {
  width:100px;
  height:100px;
  background:yellow;
  margin-top:50px; 
}

解决办法:

  • 设置父元素的overflow属性为hidden。
  • 设置父元素的border属性,如:border:1px solid red;

jsbin.com/posocizava/…

2 兄弟上下外边距合并

兄弟元素,不设置float和position:absolute时,上面兄弟的margin-bottom和下面兄弟的margin-top会合并为两者中的最大值。

<div class="parent">
  <div class="son1_bfc">
    <div class="son1"></div>
  </div>
  <div class="son2"></div>
</div>
.parent {
  width:200px;
  height:200px;
  background:pink;
}
.son1 {
  width:50px;
  height:50px;
  background:yellow;
  margin-bottom:25px;
}
.son2 {
  width:50px;
  height:50px;
  background:green;
  margin-top:25px;
}

image.png

解决办法:给任何一个元素套一个父元素,触发bfc

.son1 {
  float:left;
}
.son1_bfc {
  overflow:hidden;
}

image.png

jsbin.com/xeyobumibo/…