一、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>選單1</li>
<li>選單2</li>
<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想深入瞭解可以看看張鑫旭老師的部落格,關注奇舞週刊~