day3:前端面試題(html+css)

選擇器的權重和優先順序

CSS

選擇器有很多,不同的選擇器的權重和優先順序不一樣,對於一個元素,如果存在多個選擇器,那麼就需要根據權重來計算其優先順序。

權重分為四級,分別是:

代表內聯樣式,如

style=“xxx”

,權值為 1000;

代表 ID 選擇器,如

#content

,權值為 100;

代表類、偽類和屬性選擇器,如

。content

:hover

[attribute]

,權值為 10;

代表元素選擇器和偽元素選擇器,如

div

p

,權值為 1。

需要注意的是:通用選擇器(\*)、子選擇器(>)和相鄰同胞選擇器(+)並不在這四個等級中,所以他們的權值都為 0

。 權重值大的選擇器其優先順序也高,相同權重的優先順序又遵循後定義覆蓋前面定義的情況。

#盒模型

1. 什麼是“盒子”

初學

CSS 的朋友,一開始學 CSS 基礎知識的時候一定學過

padding

border

margin

,即內邊距、邊框和外邊距。它們三者就構成了一個“盒子”。就像我們收到的快遞,本來買了一部小小的手機,收到的卻是那麼大一個盒子。因為手機白色的包裝盒和手機機器之間有間隔層(內邊距),手機白色盒子有厚度,雖然很薄(邊框),盒子和快遞箱子之間還有一層泡沫板(外邊距)。這就是一個典型的盒子。

day3:前端面試題(html+css)

如上圖,真正的內容就是這些文字,文字外圍有 10px 的內邊距,5px 的邊框,10px 的外邊距。看到盒子了吧?

題目:盒子模型的寬度如何計算

2. 固定寬度的盒子

文章言簡意賅的介紹的瀏覽器的工作過程,web前端

day3:前端面試題(html+css)

如上圖,得到網頁效果之後,我們可以用截圖工具來量一下文字內容的寬度。發現,文字內容的寬度剛好是 300px,也就是我們設定的寬度。

因此,

在盒子模型中,我們設定的寬度都是內容寬度,不是整個盒子的寬度。而整個盒子的寬度是:(內容寬度 + border寬度 + padding寬度 + margin寬度)之和

。這樣我們改四個中的其中一個,都會導致盒子寬度的改變。這對我們來說不友好。

沒關係,這個東西不友好早就有人發現了,而且已經解決,下文再說。

3. 充滿父容器的盒子

預設情況下,

div

display:block

,寬度會充滿整個父容器。如下圖:

之前看過一篇文章,叫做《瀏覽器工作原理:新式網路瀏覽器幕後揭秘》, 文章言簡意賅的介紹的瀏覽器的工作過程,web前端 之前看過一篇文章,叫做《瀏覽器工作原理:新式網路瀏覽器幕後揭秘》, 文章言簡意賅的介紹的瀏覽器的工作過程,web前端

day3:前端面試題(html+css)

但是別忘記,這個 div 是個盒子模型,它的整個寬度包括(內容寬度 +

border

寬度 +

padding

寬度 +

margin

寬度),整個的寬度充滿父容器。

問題就在這裡。如果父容器寬度不變,我們手動增大

margin

border

padding

其中一項的寬度值,都會導致內容寬度的減少。極端情況下,如果內容的寬度壓縮到不能再壓縮了(例如一個字的寬度),那麼瀏覽器會強迫增加父容器的寬度。這可不是我們想要看到的。

4. 包裹內容的盒子

這種情況下比較簡單,內容的寬度按照內容計算,盒子的寬度將在內容寬度的基礎上再增加(

padding

寬度 +

border

寬度 +

margin

寬度)之和。

之前看過一篇文章,叫做《瀏覽器工作原理:新式網路瀏覽器幕後揭秘》

day3:前端面試題(html+css)

5. box-sizing:border-box

前面提到,為盒子模型設定寬度,結果只是設定了內容的寬度,這個不合理。如何解決這一問題?答案就是為盒子指定樣式:

box-sizing:border-box

之前看過一篇文章,叫做《瀏覽器工作原理:新式網路瀏覽器幕後揭秘》

day3:前端面試題(html+css)

上圖中,為

div

設定了

box-sizing:border-box

之後,300px 的

寬度是內容 + padding + 邊框的寬度(不包括margin)

,這樣就比較符合我們的實際要求了。建議大家在為系統寫 CSS 時候,第一個樣式是:

* { box-sizing:border-box;}

大名鼎鼎的 Bootstrap 也把

box-sizing:border-box

加入到它的

*

選擇器中,我們為什麼不這樣做呢?

6. 縱向 margin 重疊

這裡提到

margin

,就不得不提一下

margin

的這一特性——縱向重疊。如

的縱向 margin 是 16px,那麼兩個

之間縱向的距離是多少?—— 按常理來說應該是 16 + 16 = 32px,但是答案仍然是 16px。因為縱向的 margin 是會重疊的,如果兩者不一樣大的話,大的會把小的“吃掉”。

#浮動

float

float 用於網頁佈局比較多,使用起來也比較簡單,這裡總結了一些比較重要、需要注意的知識點,供大家參考。

1. 誤解和誤用

float 被設計出來的初衷是用於

文字環繞效果

,即一個圖片一段文字,圖片

float:left

之後,文字會環繞圖片。

day3:前端面試題(html+css) 一段文字一段文字一段文字一段文字一段文字一段文字一段文字一段文字一段文字

但是,後來大家發現結合

float + div

可以實現之前透過

table

實現的網頁佈局,因此就被“誤用”於網頁佈局了。

題目:為何 float 會導致父元素塌陷?

2. 破壞性

day3:前端面試題(html+css)

float

破壞性

—— float 破壞了父標籤的原本結構,使得父標籤出現了坍塌現象。導致這一現象的最根本原因在於:

被設定了 float 的元素會脫離文件流

。其根本原因在於 float 的設計初衷是解決文字環繞圖片的問題。大家要記住 float 的這個影響。

3. 包裹性

包裹性

也是

float

的一個非常重要的特性,大家用

float

時一定要熟知這一特性。咱們還是先從一個小例子看起:

day3:前端面試題(html+css)

如上圖,普通的 div 如果沒有設定寬度,它會撐滿整個螢幕,在之前的盒子模型那一節也講到過。而如果給 div 增加

float:left

之後,它突然變得緊湊了,寬度發生了變化,把內容中的三個字包裹了——這就是包裹性。為 div 設定了 float 之後,其寬度會自動調整為包裹住內容寬度,而不是撐滿整個父容器。

注意,此時

div

雖然體現了包裹性,但是它的

display

樣式是沒有變化的,還是

display: block

float

為什麼要具有包裹性?其實答案還是得從

float

的設計初衷來尋找,float 是被設計用於實現文字環繞效果的。文字環繞圖片比較好理解,但是如果想要讓文字環繞一個 div 呢?此時 div 不被“包裹”起來的話,就無法實現環繞效果了。

4. 清空格

float 還有一個大家可能不是很熟悉的特性——清空格。按照慣例,咱還是先舉例子說明。

day3:前端面試題(html+css) day3:前端面試題(html+css) day3:前端面試題(html+css) day3:前端面試題(html+css)

day3:前端面試題(html+css)

加上

float:left

之後:

day3:前端面試題(html+css)

上面第一張圖中,正常的 img 中間是會有空格的,因為多個 img 標籤會有換行,而瀏覽器識別換行為空格,這也是很正常的。第二張圖中,為 img 增加了

float:left

的樣式,這就使得 img 之間沒有了空格,4 個 img 緊緊挨著。

如果大家之前沒注意,現在想想之前寫過的程式,是不是有這個特性。為什麼 float 適合用於網頁排版(俗稱“砌磚頭”)?就是因為 float 排版出來的網頁嚴絲合縫,中間連個蒼蠅都飛不進去。

“清空格”這一特性的根本原因是 float 會導致節點脫離文件流結構。它都不屬於文件流結構了,那麼它身邊的什麼換行、空格就都和它沒了關係,它就儘量往一邊靠攏,能靠多近就靠多近,這就是清空格的本質。

題目:手寫 clearfix

5. clearfix

清除浮動的影響,一般使用的樣式如下,統稱

clearfix

程式碼。所有 float 元素的父容器,一般情況下都應該加

clearfix

這個 class。

。clearfix:after { content: ‘’; display: table; clear: both;}。clearfix { *zoom: 1; /* 相容 IE 低版本 */}

day3:前端面試題(html+css) day3:前端面試題(html+css)

6. 小結

float 的設計初衷是解決文字環繞圖片的問題,後來誤打誤撞用於做佈局,因此有許多不合適或者需要注意的地方,上文基本都講到了需要的知識點。如果是剛開始接觸 float 的同學,學完上面的基礎知識之後,還應該做一些練習實戰一下 —— 經典的“聖盃佈局”和“雙飛翼佈局”。這裡就不再展開講了,網上資料非常多,例如淺談面試中常考的兩種經典佈局——聖盃與雙飛翼(此文的最後兩張圖清晰地展示了這兩種佈局)。

#定位 position

position

用於網頁元素的定位,可設定

static/relative/absolute/fixed

這些值,其中

static

是預設值,不用介紹。

題目:relative 和 absolute 有何區別?

1. relative

相對定位 relative 可以用一個例子很輕鬆地演示出來。例如我們寫 4 個

,出來的樣子大家不用看也能知道。

第一段文字

第二段文字

第三段文字

第四段文字

day3:前端面試題(html+css)

然後我們在第三個

上面,加上

position:relative

並且設定

left

top

值,看這個

有什麼變化。

第一段文字

第二段文字

第三段文字

第四段文字

day3:前端面試題(html+css)

上圖中,大家應該要識別出兩個資訊(相信大部分人會忽略第二個資訊)

第三個

發生了位置變化,分別向右向下移動了10px;

其他的三個

位置沒有發生變化,這一點也很重要。

可見,

relative 會導致自身位置的相對變化,而不會影響其他元素的位置、大小

。這是 relative 的要點之一。還有第二個要點,就是 relative 產生一個新的定位上下文。下文有關於定位上下文的詳細介紹,這裡可以先透過一個例子來展示一下區別:

day3:前端面試題(html+css)

注意看這兩圖的區別,下文將有解釋。

2. absolute

還是先寫一個基本的 demo。

第一段文字

第二段文字

第三段文字

第四段文字

day3:前端面試題(html+css)

然後,我們把第三個

改為

position:absolute;

,看看會發生什麼變化。

day3:前端面試題(html+css)

從上面的結果中,我們能看出幾點資訊:

absolute

元素脫離了文件結構。和

relative

不同,其他三個元素的位置重新排列了。只要元素會脫離文件結構,它就會產生破壞性,導致父元素坍塌。(此時你應該能立刻想起來,

float

元素也會脫離文件結構。)

absolute

元素具有“包裹性”。之前

的寬度是撐滿整個螢幕的,而此時

的寬度剛好是內容的寬度。

absolute

元素具有“跟隨性”。雖然

absolute

元素脫離了文件結構,但是它的位置並沒有發生變化,還是老老實實地呆在它原本的位置,因為我們此時沒有設定 top、left 的值。

absolute

元素會懸浮在頁面上方,會遮擋住下方的頁面內容。

最後,透過給 absolute元素設定 top、left 值,可自定義其內容,這個都是平時比較常用的了。這裡需要注意的是,設定了 top、left 值時,元素是相對於最近的定位上下文來定位的,而不是相對於瀏覽器定位。

3. fixed

其實

fixed

absolute

是一樣的,唯一的區別在於:

absolute

元素是根據最近的定位上下文確定位置,而

fixed

根據

window

(或者

iframe

)確定位置。

題目:

relative

absolute

fixed

分別依據誰來定位?

4. 定位上下文

relative

元素的定位永遠是相對於元素自身位置的,和其他元素沒關係,也不會影響其他元素。

day3:前端面試題(html+css)

fixed

元素的定位是相對於

window

(或者

iframe

)邊界的,和其他元素沒有關係。但是它具有破壞性,會導致其他元素位置的變化。

day3:前端面試題(html+css)

absolute

的定位相對於前兩者要複雜許多。如果為

absolute

設定了

top

left

,瀏覽器會根據什麼去確定它的縱向和橫向的偏移量呢?答案是瀏覽器會遞迴查詢該元素的所有父元素,如果找到一個設定了

position:relative/absolute/fixed

的元素,就以該元素為基準定位,如果沒找到,就以瀏覽器邊界定位。如下兩個圖所示:

day3:前端面試題(html+css)

day3:前端面試題(html+css)

#flex佈局

佈局的傳統解決方案基於盒子模型,依賴

display

屬性 +

position

屬性 +

float

屬性。它對於那些特殊佈局非常不方便,比如,垂直居中(下文會專門講解)就不容易實現。在目前主流的移動端頁面中,使用 flex 佈局能更好地完成需求,因此 flex 佈局的知識是必須要掌握的。

1. 基本使用

任何一個容器都可以使用 flex 佈局,程式碼也很簡單。

aaa
bbb
ccc
ddd

day3:前端面試題(html+css)

注意,第三個

flex: 2

,其他的

flex: 1

,這樣第二個

的寬度就是其他的

的兩倍。

2. 設計原理

設定了

display: flex

的元素,我們稱為“容器”(flex container),其所有的子節點我們稱為“成員”(flex item)。容器預設存在兩根軸:水平的主軸(main axis)和垂直的交叉軸(cross axis)。主軸的開始位置(與邊框的交叉點)叫做 main start,結束位置叫做 main end;交叉軸的開始位置叫做 cross start,結束位置叫做cross end。專案預設沿主軸排列。單個專案佔據的主軸空間叫做 main size,佔據的交叉軸空間叫做 cross size。

day3:前端面試題(html+css)

將以上文字和圖片結合起來,再詳細看一遍,這樣就能理解 flex 的設計原理,才能更好地實際使用。

3. 設定主軸的方向

flex-direction

可決定主軸的方向,有四個可選值:

row

(預設值):主軸為水平方向,起點在左端。

row-reverse

:主軸為水平方向,起點在右端。

column

:主軸為垂直方向,起點在上沿。

column-reverse

:主軸為垂直方向,起點在下沿。

。box { flex-direction: column-reverse| column | row | row-reverse;}

以上程式碼設定的主軸方向,將依次對應下圖:

day3:前端面試題(html+css)

4. 設定主軸的對齊方式

justify-content

屬性定義了專案在主軸上的對齊方式,值如下:

flex-start

(預設值):向主軸開始方向對齊。

flex-end

:向主軸結束方向對齊。

center

: 居中。

space-between

:兩端對齊,專案之間的間隔都相等。

space-around

:每個專案兩側的間隔相等。所以,專案之間的間隔比專案與邊框的間隔大一倍。

。box { justify-content: flex-start | flex-end | center | space-between | space-around;}

day3:前端面試題(html+css)

5. 交叉軸的對齊方式

align-items

屬性定義專案在交叉軸上如何對齊,值如下:

flex-start

:交叉軸的起點對齊。

flex-end

:交叉軸的終點對齊。

center

:交叉軸的中點對齊。

baseline

: 專案的第一行文字的基線對齊。

stretch

(預設值):如果專案未設定高度或設為 auto,將佔滿整個容器的高度。

。box { align-items: flex-start | flex-end | center | baseline | stretch;}

day3:前端面試題(html+css)

#如何實現居中對齊?

題目:如何實現水平居中?

1. 水平居中

inline

元素用

text-align: center;

即可,如下:

。container { text-align: center;}

block

元素可使用

margin: auto;

,PC 時代的很多網站都這麼搞。

。container { text-align: center; }。item { width: 1000px; margin: auto; }

絕對定位元素可結合

left

margin

實現,但是必須知道寬度。

。container { position: relative; width: 500px;}。item { width: 300px; height: 100px; position: absolute; left: 50%; margin: -150px;}

題目:如何實現垂直居中?

2. 垂直居中

inline

元素可設定

line-height

的值等於

height

值,如單行文字垂直居中:

。container { height: 50px; line-height: 50px;}

絕對定位元素,可結合

left

margin

實現,但是必須知道尺寸。

優點:相容性好

缺點:需要提前知道尺寸

。container { position: relative; height: 200px;}。item { width: 80px; height: 40px; position: absolute; left: 50%; top: 50%; margin-top: -20px; margin-left: -40px;}

絕對定位可結合

transform

實現居中。

優點:不需要提前知道尺寸

缺點:相容性不好

。container { position: relative; height: 200px;}。item { width: 80px; height: 40px; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); background: blue;}

絕對定位結合

margin: auto

,不需要提前知道尺寸,相容性好。

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

其他的解決方案還有,不過沒必要掌握太多,能說出上文的這幾個解決方案即可。

#理解語義化

題目:如何理解 HTML 語義化?

所謂“語義”就是為了更易讀懂,這要分兩部分:

讓人(寫程式、讀程式)更易讀懂

讓機器(瀏覽器、搜尋引擎)更易讀懂

1. 讓人更易讀懂

對於人來說,程式碼可讀性、語義化就是一個非常廣泛的概念了,例如定義 JS 變數的時候使用更易讀懂的名稱,定義 CSS class 的時候也一樣,例如

length

list

等,而不是使用

a

b

這種誰都看不懂的名稱。

不過我們平常考查的“語義化”並不會考查這麼廣義、這麼泛的問題,而是考查 HTML 的語義化,是為了更好地讓機器讀懂 HTML。

2. 讓機器更易讀懂

HTML 符合 XML 標準,但又和 XML 不一樣 —— HTML 不允許像 XML 那樣自定義標籤名稱,HTML 有自己規定的標籤名稱。問題就在這裡 —— HTML 為何要自己規定那麼多標籤名稱呢,例如

p

div

h1

ul

等 —— 就是為了語義化。其實,如果你精通 CSS 的話,你完全可以全部用

標籤來實現所有的網頁效果,其他的

p

h1

ul

等標籤可以一個都不用。但是我們不推薦這麼做,這樣做就失去了 HTML 語義化的意義。

拿搜尋引擎來說,爬蟲下載到我們網頁的 HTML 程式碼,它如何更好地去理解網頁的內容呢?—— 就是根據 HTML 既定的標籤。

h1

標籤就代表是標題;

p

裡面的就是段落詳細內容,權重肯定沒有標題高;

ul

裡面就是列表;

strong

就是加粗的強調的內容 …… 如果我們不按照 HTML 語義化來寫,全部都用

標籤,那搜尋引擎將很難理解我們網頁的內容。

為了加強 HTML 語義化,HTML5 標準中又增加了

header

section

article

等標籤。因此,書寫 HTML 時,語義化是非常重要的,否則 W3C 也沒必要辛辛苦苦制定出這些標準來。

#CSS3 動畫

CSS3 可以實現動畫,代替原來的 Flash 和 JavaScript 方案。

首先,使用

@keyframes

定義一個動畫,名稱為

testAnimation

,如下程式碼,透過百分比來設定不同的 CSS 樣式,規定動畫的變化。所有的動畫變化都可以這麼定義出來。

@keyframes testAnimation{ 0% {background: red; left:0; top:0;} 25% {background: yellow; left:200px; top:0;} 50% {background: blue; left:200px; top:200px;} 75% {background: green; left:0; top:200px;} 100% {background: red; left:0; top:0;}}

後,針對一個 CSS 選擇器來設定動畫,例如針對

div

元素設定動畫,如下:

div { width: 100px; height: 50px; position: absolute; animation-name: myfirst; animation-duration: 5s;}

animation-name

對應到動畫名稱,

animation-duration

是動畫時長,還有其他屬性:

animation-timing-function

:規定動畫的速度曲線。預設是

ease

animation-delay

:規定動畫何時開始。預設是 0

animation-iteration-count

:規定動畫被播放的次數。預設是 1

animation-direction

:規定動畫是否在下一週期逆向地播放。預設是

normal

animation-play-state

:規定動畫是否正在執行或暫停。預設是

running

animation-fill-mode

:規定動畫執行之前和之後如何給動畫的目標應用,預設是

none

,保留在最後一幀可以用

forwards

題目:CSS 的

transition

animation

有何區別?

首先

transition

animation

都可以做動效,從語義上來理解,

transition

是過渡,由一個狀態過渡到另一個狀態,比如高度

100px

過渡到

200px

;而

animation

是動畫,即更專業做動效的,

animation

有幀的概念,可以設定關鍵幀

keyframe

,一個動畫可以由多個關鍵幀多個狀態過渡組成,另外

animation

也包含上面提到的多個屬性。

#重繪和迴流

重繪和迴流是面試題經常考的題目,也是效能最佳化當中應該注意的點,下面筆者簡單介紹下。

重繪

:指的是當頁面中的元素不脫離文件流,而簡單地進行樣式的變化,比如修改顏色、背景等,瀏覽器重新繪製樣式

迴流

:指的是處於文件流中 DOM 的尺寸大小、位置或者某些屬性發生變化時,導致瀏覽器重新渲染部分或全部文件的情況

相比之下,

迴流要比重繪消耗效能開支更大

。另外,一些屬性的讀取也會引起迴流,比如讀取某個 DOM 的高度和寬度,或者使用

getComputedStyle

方法。在寫程式碼的時候要避免迴流和重繪。比如在筆試中可能會遇見下面的題目:

題目:找出下面程式碼的最佳化點,並且最佳化它

var data = [‘string1’, ‘string2’, ‘string3’];for(var i = 0; i < data。length; i++){ var dom = document。getElementById(‘list’); dom。innerHTML += ‘

  • ’ + data[i] + ‘
  • ’;}

    上面的程式碼在迴圈中每次都獲取

    dom

    ,然後對其內部的 HTML 進行累加

    li

    ,每次都會操作 DOM 結構,可以改成使用

    documentFragment

    或者先遍歷組成 HTML 的字串,最後操作一次

    innerHTML

    #小結

    本小節總結了 CSS 和 HTML 常考的知識點,包括 CSS 中比較重要的定位、佈局的知識,也介紹了一些 CSS3 的知識點概念和題目,以及 HTML 的語義化。