一、CSS排版原理
box-sizing
- 改变盒模型计算方式
- 取值:border-box | content-box
- 初始值:content-box
举个例子:
<div class="box a">Box A</div>
<div class="box b">Box B</div>
<style>
.box {
width: 100px;
height: 100px;
padding: 10px;
border: 10px solid #f66;
background: #f99;
margin: 1em;
}
.b {
box-sizing: border-box;
}
</style>
演示结果:
二、一些容易被忽视的小细节
2.1 下面代码,p标签的高度是多少?
<p>Some text</p>
<style>
p {
height: 100%;
background: red;
}
</style>
解析:默认情况下body是没有高度只有宽度。所以p
标签的父级是body默认高度为0,所以p
的高度也是0。
解决办法:可以设置height: 100vh
,使用一些屏幕的单位如vh
vw
,一个屏幕的高度是100vh
。
2.2 下面代码中padding-top值多少?
<div> </div>
<style>
div {
background: red;
padding-top: 100%;
}
</style>
以上代码padding-top等于父容器body的宽度,实现了一个响应式的正方形
解析:padding
不管是padding-top
还是padding-left
,它的百分比都是根据父容器的‘宽度‘来决定的。
使用场景:可以利用padding的百分比来做出一些固定宽高比的盒子。
2.3 Margin Collapse 合并
<div class="a"></div>
<div class="b"></div>
<style>
.a{
background: lightblue;
height: 100px;
margin-bottom: 100px;
}
.b {
background: coral;
height: 100px;
margin-top: 100px;
}
</style>
- 以前是为了让报纸、排版而设定的
- a与b之间的高度还是100px,这就是margin合并。
2.4 利用border可以制作任意角度的三角形
<div class="box"></div>
<style>
.box {
border-width: 50px;
border-style: solid;
border-color: #f35 #269 #649 #fa0;
width: 0px;
height: 0px;
margin: 1em auto;
}
</style>
通过给border的其他的三条边设置透明色,就可以制作任意角度的三角形。
思考题:这个图标怎么做?
方法1:使用border构造相间的三角形,然后使用overflow-hidden
和border-radius
剪裁成圆。另外注意水平、垂直居中的实现方式。
<div id="warning">
<div class="bg"></div>
<div class="bg"></div>
<div class="bg"></div>
</div>
<style>
#warning {
position: relative;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
overflow: hidden;
border-radius: 50%;
}
#warning .bg {
position: absolute;
width: 0;
height: 0;
top: -73.2px;
left: 0px;
border-top: solid 173.2px rgb(246, 226, 54);
border-left: solid 100px transparent;
border-bottom: solid 173.2px black;
border-right: solid 100px transparent;
}
#warning .bg:nth-child(1) {
transform: rotate(0deg);
}
#warning .bg:nth-child(2) {
transform: rotate(120deg);
}
#warning .bg:nth-child(3) {
transform: rotate(240deg);
}
</style>
方法2:利用svg的虚线来做,这个方法比较灵巧,不容易理解,请多次调试stroke和stroke-dasharray的值加深理解。
<svg viewBox="0 0 64 64" class="warning">
<circle r="25%" cx="50%" cy="50%"/>
</svg>
<style>
.warning {
width: 300px;
background: black;
border-radius: 50%;
}
.warning circle {
fill: none;
stroke: yellow;
stroke-width: 32;
stroke-dasharray: 26%;
}
</style>
方法3:利用css3新特性:锥形渐变。
<div></div>
<style>
div {
padding-top: 100%;
background: repeating-conic-gradient(black 0 60deg, yellow 0 120deg);
border-radius: 50%;
}
</style>
方法4:也可以使用canvas和js等等。
三、视觉格式化模型
- 视口(viewport): 浏览器的可视区域
-
块级元素
- 会被格式化成块状的元素
- 例如
p
div
section
- 将
display
设置为block
、list-item
、table
将元素变为块级
-
行级元素
- 不会为其内容生成块级框
- 让其内容分布在多行中
- display设置为
inline
、inline-block
、inline-table
使元素变为行级
-
盒子的生成
- 每个块级元素生成一个主块级盒,用它来包含子级盒
- 每个行级元素生成一个行级盒,行级盒分布于多行
-
块级盒子中的子盒子的生成
- 块级盒子中可以包含多个子块级盒子
- 也可以包含多个行级盒子
- 不在行级元素里面的文字,会生成匿名行级盒。比如
<p>Some <em>Text</em></p>
,some在块级盒子里,并且没有被行级元素包裹,所以会生成匿名的行级盒子。 - 块级盒子中不能同时包含块级和行级盒子。遇到这种情况时,会生成匿名块级盒来包含行级盒。比如
<div><h1>标题</h1><span>2018-5-12</span></div>
-
行级盒子内的子盒子的生成
- 行级盒子内可以包含行级盒子
- 行级盒子包含一个块级盒子时,会被块级盒子拆成两个行级盒子,这两个盒子又分别被匿名块级盒包含。
举个栗子??:
<span>
aaaaa
<div>
bbb
</div>
ccc
</span>
行级盒子span
被div
分割成两个行级盒子aaa,bbb,这两个行级盒子又被匿名块级盒子包含,所以呈三个块级元素布局。
-
display属性
- block 生成块级盒
- inline 生成行级盒
- inline-block 生成行级盒,里面内容可以是块级盒
- none 在排版时将元素忽略
-
通过css生成盒子
-
::before
在元素内部的前面添加一个行盒 -
::after
在元素内部的后面添加一个行盒 -
display:list-item
这个就是列表前方的小圆点,就是给li前面添加一个行盒,生成小圆点。
-
举个栗子??
<p><span>Learn to Code HTML & CSS is a simple and comprehensive
guide dedicated to helping beginners learn HTML and CSS.
Outlining the fundamentals, this guide works through all common
elements of front-end design and development.</span></p>
<style>
p {
line-height: 2;
padding: 1em;
border: 2px solid #00f;
background: #ccf;
}
span {
background: #fcc;
border: 2px solid #f00;
}
</style>
块级盒子可以包含多个行级盒子,行级盒子可以分布多行。
四、定位模式
- 常规流
- 浮动
- 绝对定位
4.1 常规流
- 除根元素、浮动元素和绝对定位元素外,其它元素都在常规流之内(in-flow)
- 而根元素、 浮动和绝对定位的元素会脱离常规流(out of flow)
- 常规流中的盒子,属于块级格式化上下文或行级格式化上下文
4.2 块级格式化上下文
- Block Formatting Contex (BFC)
- 盒子在容器(包含块)内从上到下一个接一个地放置
- 两个兄弟盒之间的竖直距离由 margin 属性决定
- 同一个 BFC 内垂直 margin 会合并
- 盒子的左外边缘挨着容器(包含块)的左边
4.3 行级格式化上下文
- Inline Formatting Context (IFC)
- 盒子一个接一个水平放置
- 盒之间的水平
margin
,border
和padding
都有效 - 同一行的盒子所在的矩形区域叫行盒(Line box)
- 当一个行盒放不下上下文内所有盒子时,会被分到多个垂直堆叠的行盒里
- 行盒内的水平分布由
text-align
属性决定 - 如果一个行级块无法分割(单词、
inline-block
),该元素会被作为一个整体决定分布在哪一个行盒
4.4 float
- 浮动元素从常规流中脱离,被漂浮在容器(包含块)左边或右边
- 浮动盒会一直漂到其外边缘挨到容器边缘或另外的浮动盒
- 浮动元素不会影响其后面的流内块级盒
- 但是浮动元素后面的行级盒子会变短以避开浮动元素
总结一下:浮动元素后面的块级元素不会‘发现’浮动元素,而行级盒子会避开前面的浮动元素。
举个栗子??:
<section>
<img src="http://p0.qhimg.com/t0117c2689d8703d551.jpg"
width="120" alt="house">
<p><span>莫哈韦沙漠不仅纬度较高,而且温度要稍微低些,是命名该公园的
短叶丝兰——约书亚树的特殊栖息地。约书亚树以从茂密的森林到远远
间隔的实例等各种形式出现。除了约书亚树森林之外,该公园的西部包
括加州沙漠里发现的最有趣的地质外观。</span></p>
</section>
<style>
img {
float: left;
}
p {
font-size: 14px;
line-height: 1.8;
border: 1px solid;
}
</style>
代码演示
解释一下:
上述代码中,<p>
没有因为<img>
的而影响定位,<p>
并没有‘发现’<img>
图片,而<span>
里的文字‘避开’了<img>
利用float可以做图文混排效果
4.5 clear
- 指定元素哪一边不能与之前的浮动框相邻
- 取值: left | right | both
4.6 清除浮动
- 最常用的清除浮动的方法 clearfix
/* 凡是遇到清除浮动,就这么写 */
.clearfix::after {
content: ‘ ‘;
display: block;
clear: both;
height:0;
overflow: hidden;
}
-
下面这些属性会触发bfc,bfc里面的浮动不会溢出影响外部的盒子的排版,这样与清除浮动的效果是一样的。
overflow: hidden/auto
display: inline-block
float: left/right
4.7 块级格式化上下文(BFC) 的特性
- BFC 内的浮动不会影响到BFC外部的元素
- BFC 的高度会包含其内的浮动元素
- BFC 不会和浮动元素重叠
- BFC 可以通过
overflow:hidden
等方法创建
4.8 BFC 的创建
- 浮动框
- 绝对定位框
- 非块级的块容器
inline-block
-
overflow
属性非visible
的块框
4.9 BFC的作用
bfc就是为了把自己里面的东西‘封闭’起来,不与外界做过多的‘干扰’。
- 清除浮动
- 防止
margin
折叠 - 两栏布局
五、定位和堆叠
-
position
- static 非定位,默认值
- relative 相对定位(相对自己)
- absolute 绝对定位,相对非 static 祖先元素定位
- fixed 相对于视口绝对定位
-
z-index 堆叠层次
- 为定位元素指定其在 z 轴的上下等级
- 用一个整数表示,数值越大,越靠近用户
- 初始值为 auto,可以为负数、0、正数
5.1 思考一个问题:是不是z-index越大,就越在上面呢?
来看下面一坨代码,重点看有z-index
的元素
<nav>
<ul>
<li>z-index: 2</li>
</ul>
</nav>
<div id="dialog">
z-index: 1
</div>
<style>
nav {
position: fixed;
top: 0;
}
nav ul {
position: absolute;
z-index: 2;
top: 0;
left: 0;
background: red;
padding: 1em;
width: 10em;
}
#dialog {
position: absolute;
z-index: 1;
top: 5em;
left: 5em;
background: blue;
height: 10em;
width: 10em;
}
body {
color: #fff;
}
li {
margin: 1em 0;
list-style:none;
}
#dialog {
padding: 1em;
}
ul {
padding: 1em;
}
</style>
5.2 结果为什么是z-index: 1在上面呢?
- 在排版的时候,浏览器不只是比较z-index的值,是比较同一个堆叠上下文的z-index的值的大小。
- 上述例子中,应该是
<nav>
与div#dialog
比较,<nav>
中的z-index
是默认值auto
,div#dialog
中的z-index
是1
,所以蓝色框在上面。nav
里面的元素的z-index
再大也不能排在上面,因为他的父级‘不行’????。 - 但是如果把nav里的
position
设置为absolute
呢?你可以试试改一下上面的代码,得出结果是不是大吃一惊呢?为什么红色就上去了呢?
- 因为
position
为fixed
或sticky
的元素不用z-index
就会创建堆叠上下文,这样<div>
和<nav>
进行z-index
比较。 -
positiong:absolute
的元素需要同时设定z-index
才会创建堆叠上下文,nav
中没有设置z-index
,所以不会创建堆叠上下文,而<nav>
里面的<ul>
既包含了定位与z-index
属性,所以div
就会和<nav>
里面的<ul>
作比较,这样红色框会在蓝色框上面。
5.3 创建堆叠上下文
- Root 元素
- relative 或 absolute 且 z-index 不是 auto 的元素
- position 为 fixed 或 sticky 的元素
- 设置了某些 CSS3 属性的元素,比如 opacity、transform、animation、will-change 等
- flexbox 的子元素且 z-index 不是 auto
有以上特点的都会创建堆叠上下文
5.4 绘制层级
在每一个堆叠上下文中,从下到上:
- 形成该上下文的元素的 border 和 background
- z-index 为负值的子堆叠上下文
- 常规流内的块级元素非浮动子元素
- 非定位的浮动元素
- 常规流内非定位行级元素
- z-index 为 0 的子元素或子堆叠上下文
- z-index 为正数的子堆叠上下文
六、行内排版
6.1 所有的文字都是基于baseline来排版的。
6.2 line-height
6.3 line-box中盒子摆放
- 对于图片、不同的文字都是基于同一个baseline来布局
- 图片的baseline是图片的底边
- 对于inline-block的盒子,他是基于文字的最后一行的baseline来摆放
如果想改变对齐方式怎么办呢?
6.4 vertical-align 垂直对齐关系
- 定义盒子所处的行盒(line box)的垂直对齐关系
- 取值:
baseline
|sub
|super
|top
|text-top
|middle
|bottom
|text-bottom
|<percentage>
|<length>
- 百分比相对于元素自身的行高
- 初始值 baseline
由上图举例说明:
- 首先给这些元素画一个baseline(基线),baseline的确定是按照父级盒子的字体的大小来确定的。
- 如果给文字设置成
vertical-align
为middle
,middle这根线的位置是x-height的一半(x-height在font-metrics图片中有定义)。 - 如果行盒Text设置成
vertical-align
设置为text-top
,那么它的上边缘与text-top这条线对齐。 - 其他同理。
6.5 举个栗子??
<p>
<img
src="https://p5.ssl.qhimg.com/t013753a42172e3170a.jpg"
alt="car"
width="400"
/>
</p>
<style>
p {
padding: 0;
background: red;
}
</style>
代码演示:
可以看出img图片是基于p标签中的文字基线来排版的,那么如何让图片下面这段红线去掉呢?
- 可以将
img
设置成block
,这样块级与块级就不会涉及(行内排版)这种情况。 - 可以给
p
设置vertical-align
设置middle
属性,这样img
的中线与p
的中线对齐,就不会出现这种问题
七、水平方向的对齐方式
text-align
- 定义文本在容器内的对齐方式
- 取值:
left
|right
|center
|justify
(两端对齐) - 初始值由 HTML 的 dir 属性决定,可继承
7.1 看一下这坨代码中text-align: justify
生效了么?
<nav>
<a href="#">Home</a>
<a href="#">Products</a>
<a href="#">Contact</a>
<a href="#">Help</a>
</nav>
<style>
nav {
text-align: justify;
background: #dcc
}
nav a {
display: inline-block;
line-height: 3;
}
</style>
答案是并没有,这是因为什么呢?因为nav中的文字仅仅只有一行,它是第一行也是最后一行,text-align:justify
不会对最后一行起作用。
css为什么要这样设置呢?
我们可以想一下,如果我们有多行文字,最后结尾的文字大多数都是少于一行的,如果css对于最后一行文字也进行两端对齐的话,岂不是很丑。。。
像这样:
所以css不给最后一行文字进行两段对齐。
7.2 如果我们要强制让最后一行两端对齐呢?
可以使用text-align-last:justify
, 可以给最后一行文字设置两端对齐。
八、最后
如果对你有所帮助,请点个赞呀~~
如果想对css想深入了解可以看看张鑫旭老师的博客,关注奇舞周刊~