CSS 布局
zKing 2019-01-09 CSS
摘要
早期的布局以 table 为主,后来则使用技巧性布局,到如今使用 flexbox/grid 布局。另外,现在“响应式布局”为必备知识
# table 表格布局
- 2007 年之前用的较多,现在除了后台系统以及一些古老的网站还在用,基本已经没有使用了。所以不再过多介绍。
- 需要注意的是,CSS 中可以使用 display:table 来模拟 table 属性
# 盒模型
- 确定元素的显示类型 ,dispaly :block/inline/inline-block
- inline 不可以设置宽高
- 确定元素的位置,position:absolute/relative/static/fixed
- 默认是 static ,遵从文档流顺序,其他三种值可以设置 z-index 来定义层级
- relative 的偏移是相对元素本身的,不会改变本来占据的空间
- absolute 的直接脱离文档流,它是相对于最近的
postion:relative/absolute
的元素定位的,一直查询到 body 元素。可以看成是独立的存在 - fixed 也是脱离文档流,但是是相对于可视区域的
- 使用 margin/padding 来调整外间距和内间距
# float 浮动布局
- 特点
- 元素“浮动”。脱离文档流但不脱离文本流,float 本来就是用来做图片文字环绕效果的
- 对自身的影响:
- 形成块(BFC)
- 位置尽量靠上
- 尽量靠左(右),无法满足的情况只能往下移动
- 对兄弟元素的影响:
- 上面贴非 float 元素
- 旁边贴 float 元素
- 不影响其他块级元素位置
- 影响其他块级元素内部文本
- 对父级元素的影响:
- 从布局上“消失”
- 父级高度可能会塌陷。解决方法---
使用 float 来实现“响应式两栏布局”的例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.container {
width: 100%;
height: 200px;
}
.left {
background: red;
float: left;
width: 30%;
height: 100%;
}
.right {
background: black;
color: white;
height: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="left">左</div>
<div class="right">右</div>
</div>
</body>
</html>
使用 float 来实现“响应式三栏布局”的例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.container {
width: 100%;
height: 200px;
}
.left {
background: red;
float: left;
width: 10%;
height: 100%;
}
.right {
background: blue;
float: right;
width: 10%;
height: 100%;
}
.middle {
background: black;
color: white;
width: 78%;
height: 100%;
margin: auto;
}
</style>
</head>
<body>
<div class="container">
<div class="left">左1</div>
<div class="right">右2</div>
<div class="middle">中间3</div>
</div>
</body>
</html>
实现浮动布局“清除浮动”的例子,需要注意的是,这里是不给浮动的元素赋予高度的限制。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.container {
width: 400px;
margin: 20px;
}
.left {
background: red;
float: left;
width: 200px;
}
.right {
background: black;
float: left;
color: white;
width: 200px;
}
/* 关键代码,在父元素上使用伪元素来清除浮动 */
.container2::after {
content: "";
clear: both;
display: block;
}
</style>
</head>
<body>
<div class="container container2">
<div class="left">左</div>
<div class="right">右</div>
</div>
<div class="container" style="height: 200px; background: green;"></div>
</body>
</html>
# inline-block 布局
- 像文本一样排 block 元素
- 没有清除浮动等问题
- 需要处理间隙问题
- 可以通过设置父元素 font-size:0 ,然后各个子元素再设置 font-size 来解决
以下是具体的例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.container {
width: 800px;
height: 200px;
font-size: 0;
}
.left {
font-size: 14px;
background: red;
display: inline-block;
width: 200px;
height: 200px;
}
.right {
font-size: 14px;
background: blue;
display: inline-block;
width: 600px;
height: 200px;
}
</style>
</head>
<body>
<div class="container">
<div class="left">左</div>
<div class="right">右</div>
</div>
</body>
</html>
# flexbox 布局
- flexbox 为布局而生的属性,弹性盒子
- 盒子本来就是并列的
- 定义宽度就行
简单使用 flexbox 布局
- 设置
display: flex;
- 对每个子元素设置
flex:[number]
先写一个例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.container {
width: 800px;
height: 200px;
display: flex;
border: 1px solid black;
}
.flex {
background: red;
margin: 5px;
flex: 1; /* 表示只占一份*/
}
.flex2 {
background: red;
margin: 5px;
flex: 2;
}
</style>
</head>
<body>
<div class="container">
<div class="flex">flex1</div>
<div class="flex2">flex2</div>
<div class="flex">flex3</div>
<div class="flex">flex4</div>
<div class="flex">flex5</div>
</div>
</body>
</html>
再更深入地学习 flexbox 布局,还有以下的属性需要了解
flex-direction 用来设置排列方式
- row:默认的排列方式,横向从左到右排列(左对齐)。
- row-reverse:反转横向排列(右对齐,从后往前排,最后一项排在最前面。
- column:纵向排列。
- column-reverse:反转纵向排列,从后往前排,最后一项排在最上面。
justify-content 应用在弹性容器上,把弹性项沿着弹性容器的主轴线(main axis)对齐。
- flex-start:弹性项目向行头紧挨着填充。这个是默认值。
- flex-end:弹性项目向行尾紧挨着填充。
- center:弹性项目居中紧挨着填充。
- space-between:弹性项目平均分布在该行上。如果剩余空间为负或者只有一个弹性项,则该值等同于 flex-start。否则,第 1 个弹性项的外边距和行的 main-start 边线对齐,而最后 1 个弹性项的外边距和行的 main-end 边线对齐,然后剩余的弹性项分布在该行上,相邻项目的间隔相等。
- space-around:弹性项目平均分布在该行上,两边留有一半的间隔空间。如果剩余空间为负或者只有一个弹性项,则该值等同于 center。否则,弹性项目沿该行分布,且彼此间隔相等(比如是 20px),同时首尾两边和弹性容器之间留有一半的间隔(1/2*20px=10px)。
align-items 设置或检索弹性盒子元素在侧轴(纵轴)方向上的对齐方式。
- flex-start:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴起始边界。
- flex-end:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴结束边界。
- center:弹性盒子元素在该行的侧轴(纵轴)上居中放置。(如果该行的尺寸小于弹性盒子元素的尺寸,则会向两个方向溢出相同的长度)。
- baseline:如弹性盒子元素的行内轴与侧轴为同一条,则该值与'flex-start'等效。其它情况下,该值将参与基线对齐。
- stretch:如果指定侧轴大小的属性值为'auto',则其值会使项目的边距盒的尺寸尽可能接近所在行的尺寸,但同时会遵照'min/max-width/height'属性的限制。
flex-wrap 用于指定弹性盒子的子元素换行方式。
- nowrap - 默认, 弹性容器为单行。该情况下弹性子项可能会溢出容器。
- wrap - 弹性容器为多行。该情况下弹性子项溢出的部分会被放置到新行,子项内部会发生断行
- wrap-reverse -反转 wrap 排列。
以下是详细的例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title></title>
<style>
.flex-container {
display: flex;
flex-direction: row-reverse; /* 反方向放置 */
justify-content: flex-start; /* 紧挨最开始的元素 */
align-items: center; /* 垂直对齐 */
flex-wrap: nowrap; /* 单行排列,无论子元素的宽度多大,都会显示在同一行*/
width: 800px;
height: 600px;
background-color: cornflowerblue;
}
.flex-item1 {
width: 200px;
height: 200px;
background-color: antiquewhite;
margin: 10px;
}
.flex-item2 {
width: 200px;
height: 400px;
background-color: antiquewhite;
margin: 10px;
}
.flex-item3 {
width: 300px;
height: 200px;
background-color: antiquewhite;
margin: 10px;
}
</style>
</head>
<body>
<div class="flex-container">
<div class="flex-item1">flex-item-1</div>
<div class="flex-item2">flex-item-2</div>
<div class="flex-item3">flex-item-3</div>
</div>
</body>
</html>
# Grid 布局
Grid 布局是一种二维布局方法,能够在行和列中布置内容。因此在任何网格中都有两个轴,横轴。
Grid 布局使用方式:
- 需要给容器(container)定义:display:grid
- 设置列(grid-template-columns)的大小
- 设置行(grid-template-rows)的大小
- 用 grid-column 和 grid-row 定义容器子元素(grid-item 项目)的位置。
- 用 grid-gap 来为子元素增加边距
- 与 flexbox 布局类似
示例
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Document</title>
<style>
.container > div {
font-size: 35px;
font-weight: bold;
color: #fff;
text-align: center;
background: #5e5a5a;
}
.container > div:nth-child(3n) {
background: #4d41b8;
}
.container > div:nth-child(2n) {
background: #41b8b8;
}
.container > div:nth-child(4n) {
background: #ce5042;
}
.container {
display: grid;
grid-template-rows: 60px 60px 60px; /* 代表一行有 3 个元素 */
grid-template-columns: 120px 120px 120px; /* 代表一列有 3 个元素 */
grid-gap: 2px 4px; /* 为每个子元素增加边距 */
}
</style>
</head>
<body>
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div style="grid-row: 2;grid-column:2">9</div>
</div>
</body>
</html>
# 响应式设计和布局
为了在不同设备上正常使用网站,一般主要处理屏幕大小问题
主要方法
- 隐藏不必要的元素 + 折行 + 自适应空间
- rem / viewport / media query
以下是“响应式设计”的例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>responsive</title>
<style>
html {
font-size: 20px;
}
.container {
margin: 0 auto;
max-width: 800px;
border: 1px solid black;
}
.intro {
display: inline-block;
width: 9rem;
height: 9rem;
line-height: 9rem;
text-align: center;
border-radius: 4.5rem;
border: 1px solid red;
margin: 0.3rem;
}
/* 宽度 <= 820px 的 .intro 类的规则 */
@media (max-width: 820px) {
.intro {
margin: 0.3rem auto;
display: block;
}
html {
font-size: 30px;
}
}
@media (max-width: 375px) {
html {
font-size: 24px;
}
}
@media (max-width: 320px) {
html {
font-size: 20px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="intro">1</div>
<div class="intro">2</div>
<div class="intro">3</div>
<div class="intro">4</div>
</div>
</body>
</html>
- 使用 flexbox 布局和 grid 布局要考虑好兼容性的问题
- 使用 media query 需要把范围大的放在上面。更多响应式设计的内容,请点击 这里