在CSS中,布局的常用技术有以下几种:
- 浮动
- 定位
- CSS表格
- 弹性盒子(flexbox)
- 网格
布局技术会使用各种CSS属性来操作HTML元素,使其相对于正常布局流、父容器、周围元素而变动。正常布局流是指在不对页面进行任何布局控制时,浏览器默认的HTML布局方式。
例如上面提到的浮动、定位之类的布局技术,就是主要利用float、position、display这几个CSS属性来操作布局的,而在正常布局流中,position默认是static、float默认是none、display默认是block或inline,通过修改这几个属性来达到改变布局的目的。
下面将记录这几种布局的概念和具体用法:
浮动
浮动技术允许元素浮动到另外一个元素的左侧或右侧,而不是默认的一个堆叠另一个,它使用float这个属性来设置不同的浮动效果,float 的主要用途是布置出多个列并且浮动文字以环绕图片:
向左浮动的图片
利用浮动设置多列布局
设置浮动会使元素脱离于正常文档流,并使所有代码后方的元素围绕浮动元素流动,并填充其左侧或者右侧(float值实际上要么是left要么是right)。
float 属性有四个可能的值:
-
left
— 将元素浮动到左侧。 -
right
— 将元素浮动到右侧。 -
none
— 默认值, 不浮动。 -
inherit — 继承父元素的浮动属性。
另外对于浮动来说,有一个方法来可以使后面的布局流元素不受浮动影响(围绕浮动元素流动),那就是清除浮动的属性clear,它可以设置left、right、both三个值,分别代表取消左边、右边、左右两边元素的浮动效果。
如果没有合适的元素来使用clear,可以放置一个clearfix块在最后一个浮动元素的下方:
<div class="clearfix"></div>
.clearfix {
clear: both;
}
clearfix块本身不可见,只是用来“阻止继续浮动”,正好之后可以在clearfix块下方放置后面的内容了。
定位
定位技术,可以让一个HTML元素从它原来的位置移动到另一个位置。
有四种定位技术:
-
静态定位(Static positioning)是每个元素默认的属性——它表示“将元素放在文档布局流的默认位置——没有什么特殊的地方”。
-
相对定位(Relative positioning)允许我们相对元素在正常的文档流中的位置移动它——包括将两个元素叠放在页面上。这对于微调和精准设计(design pinpointing)非常有用。
-
绝对定位(Absolute positioning)将元素完全从页面的正常布局流中移出,类似将它单独放在一个图层中. 我们可以将元素相对于页面的
<html>
元素边缘固定,或者相对于离元素最近的被定位的祖先元素(ancestor element)。绝对定位在创建复杂布局效果时非常有用,例如通过标签显示和隐藏的内容面板或者通过按钮控制滑动到屏幕中的信息面板. -
固定定位(Fixed positioning)与绝对定位非常类似,除了它是将一个元素相对浏览器视口固定,而不是相对另外一个元素。 在创建类似页面滚动总是处于页面上方的导航菜单时非常有用。
这里各种定位技术,通过设置position属性来设置,它主要可以设置为以下值:
- static
- relative
- absolute
- fixed
由于元素默认是静态定位的,因此只说明相对、绝对和固定定位。
相对定位
通过设置position为relative,这个设置动作本身不会移动元素,但是会把它设置为“已定位的元素”,这与绝对定位有一定关系,后面会提到。
OK,现在设置了相对定位元素,对于移动到相对于“目前位置”的目标位置,需要设置top、right、bottom、left属性,例如:
.positioned {
position: relative;
top: 30px;
left: 30px;
}
按照上面这样设置,应该是移动到相对于“目前位置”的右方30px、下方30px的目标位置,可以理解为从上方边界开始推这个盒子30px,再从左方边界开始推这个盒子30px,那就是向右下方移动了30px。
绝对定位
通过设置position为absolute,这个设置动作会使元素瞬间脱离了正常文档流,原来位置的空间被正常文档流元素所占据,有点像浮动起来,它会相对于最近的“已定位的元素”去进行定位,默认这个元素是<html>,但是我们可以通过设置一个元素为相对定位(不设置top、right、bottom、left属性)来作为一个绝对定位元素的定位标准(定位上下文)。
同样的,绝对定位也是用top、right、bottom、left属性来进行定位,不过它不同于相对定位的使用方式,而是距离这些边界的距离,例如:
.positioned {
position: absolute;
top: 100px;
right: 50px;
}
这里是将元素定位到距离上边界的100px、右边界的50px的位置上。
固定定位
这是一个绝对定位的特例,上面描述了绝对定位需要相对于一个“已定位元素”作为定位标准,固定定位的这个定位标准是浏览器视口,也就是浏览器的整个显示区域,通过设置position为fixed,然后设定top、right、bottom、left属性来定位即可,这样无论网页如何滚动,这个固定定位元素都显示在那个浏览器显示区的固定位置上,这种技术一般用来做固定的导航菜单、浮动的导航按钮(跳至顶部)等。
CSS表格
CSS表格就是利用CSS的display属性来设置一个元素像表格的方式那样去布局,下面是一个例子:
<form>
<p>First of all, tell us your name and age.</p>
<div>
<label for="fname">First name:</label>
<input type="text" id="fname">
</div>
<div>
<label for="lname">Last name:</label>
<input type="text" id="lname">
</div>
<div>
<label for="age">Age:</label>
<input type="text" id="age">
</div>
</form>
html {
font-family: sans-serif;
}
form {
display: table;
margin: 0 auto;
}
form div {
display: table-row;
}
form label, form input {
display: table-cell;
margin-bottom: 10px;
}
form label {
width: 200px;
padding-right: 5%;
text-align: right;
}
form input {
width: 300px;
}
form p {
display: table-caption;
caption-side: bottom;
width: 300px;
color: #999;
font-style: italic;
}
显示效果如下:
可以看到,通过将表格<form>的display属性设置为table即可,然后里面的行元素设置为table-row、单元格元素设置为table-cell、标题元素设置为table-caption。
弹性盒子
弹性盒子(flexible box)顾名思义,是灵活的盒子工具,比起float和position可以进行更加灵活的布局,它可以用来快速创建一些CSS难以实现的效果,例如在父容器中垂直据中央一个块内容、使容器的所有子项占用等量的可用宽度/高度,而不管有多少宽度/高度可用、使多列布局中的所有列采用相同的高度,即使它们包含的内容量不同。
这里采用MDN中的例子来说明:
下面是一段简单的源码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Flexbox 0 — starting code</title>
<style>
html {
font-family: sans-serif;
}
body {
margin: 0;
}
header {
background: purple;
height: 100px;
}
h1 {
text-align: center;
color: white;
line-height: 100px;
margin: 0;
}
article {
padding: 10px;
margin: 10px;
background: aqua;
}
/* Add your flexbox CSS below here */
</style>
</head>
<body>
<header>
<h1>Sample flexbox example</h1>
</header>
<section>
<article>
<h2>First article</h2>
<p>Tacos actually microdosing, pour-over semiotics banjo chicharrones retro fanny pack portland everyday carry vinyl typewriter. Tacos PBR&B pork belly, everyday carry ennui pickled sriracha normcore hashtag polaroid single-origin coffee cold-pressed. PBR&B tattooed trust fund twee, leggings salvia iPhone photo booth health goth gastropub hammock.</p>
</article>
<article>
<h2>Second article</h2>
<p>Tacos actually microdosing, pour-over semiotics banjo chicharrones retro fanny pack portland everyday carry vinyl typewriter. Tacos PBR&B pork belly, everyday carry ennui pickled sriracha normcore hashtag polaroid single-origin coffee cold-pressed. PBR&B tattooed trust fund twee, leggings salvia iPhone photo booth health goth gastropub hammock.</p>
</article>
<article>
<h2>Third article</h2>
<p>Tacos actually microdosing, pour-over semiotics banjo chicharrones retro fanny pack portland everyday carry vinyl typewriter. Tacos PBR&B pork belly, everyday carry ennui pickled sriracha normcore hashtag polaroid single-origin coffee cold-pressed. PBR&B tattooed trust fund twee, leggings salvia iPhone photo booth health goth gastropub hammock.</p>
<p>Cray food truck brunch, XOXO +1 keffiyeh pickled chambray waistcoat ennui. Organic small batch paleo 8-bit. Intelligentsia umami wayfarers pickled, asymmetrical kombucha letterpress kitsch leggings cold-pressed squid chartreuse put a bird on it. Listicle pickled man bun cornhole heirloom art party.</p>
</article>
</section>
</body>
</html>
HTML中主要的内容是一个标题<header>和包含有三个<article>的<section>。
它的效果图如下:
现在我希望这里这三段文字能够水平排布,那么可以直接将包含有三个<article>的<section>设置为弹性盒子即可。
在CSS中添加这段代码:
section {
display:flex
}
将获得以下效果:
可以看到,三段文字都以希望的方式排布,那么原理是什么呢?
flex盒子模型
当元素的display被设置为flex后,它会沿着两条轴来布局:
-
主轴(main axis)是沿着 flex 元素放置的方向延伸的轴(比如页面上的横向的行、纵向的列)。该轴的开始和结束被称为 main start 和 main end。
-
交叉轴(cross axis)是垂直于 flex 元素放置方向的轴。该轴的开始和结束被称为 cross start 和 cross end。
-
设置了
display: flex
的父元素(在本例中是<section>
)被称之为 flex 容器(flex container)。 -
在 flex 容器中表现为弹性盒子的元素被称之为 flex 项(flex item)(本例中是<article>元素。)。
另外,如果flex盒子默认是按row的方式作为主轴方向去排列,如果打算把元素按垂直方向排列,可以这样设置:
section {
display:flex;
flex-direction: column;
}
溢出后换行
当弹性盒子中的flex项太多导致溢出后,不会自动换行,怎么办?
很简单,这里设置flex-wrap属性即可:
section {
display:flex;
flex-wrap: wrap;
}
article {
flex: 200px;
}
得到效果图:
同时设置了<article>的flex属性值为200px,意味着每个flex项至少有200px的宽度。
动态尺寸
回到一开始只设置了display:flex的例子,如果想要第三列是前面两列的2倍长度,应该怎么设置
article {
flex: 1;
}
article:nth-of-type(3) {
flex: 2;
}
这里flex的属性值只是一个无单位的比例值,占用是通过去掉padding和margin之后剩余的空间来算的,通过这种方式可以动态设置每列的比例,同时还可以设置每列最小值:
article {
flex: 1 200px;
}
article:nth-of-type(3) {
flex: 2 200px;
}
这样设置后刷新页面,会先分配每列200px,然后剩余的空间才进行1:1:2的方式分配给这三列。
另外还有用于水平或垂直对齐flex项的属性:align-items、
justify-content
网格
目前关于CSS布局最具前沿性的应该是原生网格布局特性,也就是display:grid,由于目前这个网格规范还在起草阶段,现阶段各大浏览器的支持力度还不大,所以可以适当学习了解一下即可,可以参考这里。