本章節(jié)是前端開發(fā)者面試問題 - CSS 部分的參考答案。 歡迎提出 PR 進行建議和指正!
CSS 選擇器的優(yōu)先級是如何計算的?
重置(resetting)CSS 和 標準化(normalizing)CSS 的區(qū)別是什么?你會選擇哪種方式,為什么?
請闡述
Float定位的工作原理。請闡述
z-index屬性,并說明如何形成層疊上下文(stacking context)。請闡述塊格式化上下文(Block Formatting Context)及其工作原理。
有哪些清除浮動的技術,都適用哪些情況?
請解釋什么是雪碧圖(css sprites),以及如何實現?
如何解決不同瀏覽器的樣式兼容性問題?
如何為功能受限的瀏覽器提供頁面? 使用什么樣的技術和流程?
有什么不同的方式可以隱藏內容(使其僅適用于屏幕閱讀器)?
你使用過柵格系統(tǒng)嗎?偏愛哪一個?
你是否使用過媒體查詢或移動優(yōu)先的布局?
你熟悉制作 SVG 嗎?
除了
screen,你還能說出一個 @media 屬性的例子嗎?編寫高效的 CSS 應該注意什么?
使用 CSS 預處理的優(yōu)缺點分別是什么?
對于你使用過的 CSS 預處理,說說喜歡和不喜歡的地方?
如何實現一個使用非標準字體的網頁設計?
解釋瀏覽器如何確定哪些元素與 CSS 選擇器匹配。
描述偽元素及其用途。
說說你對盒模型的理解,以及如何告知瀏覽器使用不同的盒模型渲染布局。
* { box-sizing: border-box; }會產生怎樣的效果?display的屬性值都有哪些?inline和inline-block有什么區(qū)別?relative、fixed、absolute和static四種定位有什么區(qū)別?你使用過哪些現有的 CSS 框架?你是如何改進它們的?
你了解 CSS Flexbox 和 Grid 嗎?
請解釋在編寫網站時,響應式與移動優(yōu)先的區(qū)別。
響應式設計與自適應設計有何不同?
你有沒有使用過視網膜分辨率的圖形?當中使用什么技術?
什么情況下,用
translate()而不用絕對定位?什么時候,情況相反。
CSS 選擇器的優(yōu)先級是如何計算的?
瀏覽器通過優(yōu)先級規(guī)則,判斷元素展示哪些樣式。優(yōu)先級通過 4 個維度指標確定,我們假定以a、b、c、d命名,分別代表以下含義:
a表示是否使用內聯樣式(inline style)。如果使用,a為 1,否則為 0。b表示 ID 選擇器的數量。c表示類選擇器、屬性選擇器和偽類選擇器數量之和。d表示標簽(類型)選擇器和偽元素選擇器之和。
優(yōu)先級的結果并非通過以上四個值生成一個得分,而是每個值分開比較。a、b、c、d權重從左到右,依次減小。判斷優(yōu)先級時,從左到右,一一比較,直到比較出最大值,即可停止。所以,如果b的值不同,那么c和d不管多大,都不會對結果產生影響。比如0,1,0,0的優(yōu)先級高于0,0,10,10。
當出現優(yōu)先級相等的情況時,最晚出現的樣式規(guī)則會被采納。如果你在樣式表里寫了相同的規(guī)則(無論是在該文件內部還是其它樣式文件中),那么最后出現的(在文件底部的)樣式優(yōu)先級更高,因此會被采納。
在寫樣式時,我會使用較低的優(yōu)先級,這樣這些樣式可以輕易地覆蓋掉。尤其對寫 UI 組件的時候更為重要,這樣使用者就不需要通過非常復雜的優(yōu)先級規(guī)則或使用!important的方式,去覆蓋組件的樣式了。
參考
重置(resetting)CSS 和 標準化(normalizing)CSS 的區(qū)別是什么?你會選擇哪種方式,為什么?
重置(Resetting): 重置意味著除去所有的瀏覽器默認樣式。對于頁面所有的元素,像
margin、padding、font-size這些樣式全部置成一樣。你將必須重新定義各種元素的樣式。標準化(Normalizing): 標準化沒有去掉所有的默認樣式,而是保留了有用的一部分,同時還糾正了一些常見錯誤。
當需要實現非常個性化的網頁設計時,我會選擇重置的方式,因為我要寫很多自定義的樣式以滿足設計需求,這時候就不再需要標準化的默認樣式了。
參考
請闡述Float定位的工作原理。
浮動(float)是 CSS 定位屬性。浮動元素從網頁的正常流動中移出,但是保持了部分的流動性,會影響其他元素的定位(比如文字會圍繞著浮動元素)。這一點與絕對定位不同,絕對定位的元素完全從文檔流中脫離。
CSS 的clear屬性通過使用left、right、both,讓該元素向下移動(清除浮動)到浮動元素下面。
如果父元素只包含浮動元素,那么該父元素的高度將塌縮為 0。我們可以通過清除(clear)從浮動元素后到父元素關閉前之間的浮動來修復這個問題。
有一種 hack 的方法,是自定義一個.clearfix類,利用偽元素選擇器::after清除浮動。另外還有一些方法,比如添加空的<div></div>和設置浮動元素父元素的overflow屬性。與這些方法不同的是,clearfix方法,只需要給父元素添加一個類,定義如下:
<pre style="font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; margin: 0px; padding: 0px; caret-color: rgb(34, 34, 34); color: rgb(34, 34, 34); font-size: 14px; box-sizing: border-box;">.clearfix::after { content: ""; display: block; clear: both; }</pre>
值得一提的是,把父元素屬性設置為overflow: auto或overflow: hidden,會使其內部的子元素形成塊格式化上下文(Block Formatting Context),并且父元素會擴張自己,使其能夠包圍它的子元素。
參考
請闡述z-index屬性,并說明如何形成層疊上下文(stacking context)。
CSS 中的z-index屬性控制重疊元素的垂直疊加順序。z-index只能影響position值不是static的元素。
沒有定義z-index的值時,元素按照它們出現在 DOM 中的順序堆疊(層級越低,出現位置越靠上)。非靜態(tài)定位的元素(及其子元素)將始終覆蓋靜態(tài)定位(static)的元素,而不管 HTML 層次結構如何。
層疊上下文是包含一組圖層的元素。 在一組層疊上下文中,其子元素的z-index值是相對于該父元素而不是document root 設置的。每個層疊上下文完全獨立于它的兄弟元素。如果元素 B 位于元素 A 之上,則即使元素 A 的子元素 C 具有比元素 B 更高的z-index值,元素 C 也永遠不會在元素 B 之上.
每個層疊上下文是自包含的:當元素的內容發(fā)生層疊后,整個該元素將會在父層疊上下文中按順序進行層疊。少數CSS 屬性會觸發(fā)一個新的層疊上下文,例如opacity小于 1,filter不是none,transform不是none。
參考
請闡述塊格式化上下文(Block Formatting Context)及其工作原理。
塊格式上下文(BFC)是 Web 頁面的可視化 CSS 渲染的部分,是塊級盒布局發(fā)生的區(qū)域,也是浮動元素與其他元素交互的區(qū)域。
一個 HTML 盒(Box)滿足以下任意一條,會創(chuàng)建塊格式化上下文:
float的值不是none.position的值不是static或relative.display的值是table-cell、table-caption、inline-block、flex、或inline-flex。overflow的值不是visible。
在 BFC 中,每個盒的左外邊緣都與其包含的塊的左邊緣相接。
兩個相鄰的塊級盒在垂直方向上的邊距會發(fā)生合并(collapse)。更多內容請參考邊距合并(margin collapsing)。
參考
https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context
https://www.sitepoint.com/understanding-block-formatting-contexts-in-css/
有哪些清除浮動的技術,都適用哪些情況?
空
div方法:<div style="clear:both;"></div>。Clearfix 方法:上文使用
.clearfix類已經提到。overflow: auto或overflow: hidden方法:上文已經提到。
在大型項目中,我會使用 Clearfix 方法,在需要的地方使用.clearfix。設置overflow: hidden的方法可能使其子元素顯示不完整,當子元素的高度大于父元素時。
請解釋什么是雪碧圖(css sprites),以及如何實現?
雪碧圖是把多張圖片整合到一張上的圖片。它被運用在眾多使用了很多小圖標的網站上(Gmail 在使用)。實現方法:
使用生成器將多張圖片打包成一張雪碧圖,并為其生成合適的 CSS。
每張圖片都有相應的 CSS 類,該類定義了
background-image、background-position和background-size屬性。使用圖片時,將相應的類添加到你的元素中。
好處:
減少加載多張圖片的 HTTP 請求數(一張雪碧圖只需要一個請求)。但是對于 HTTP2 而言,加載多張圖片不再是問題。
提前加載資源,防止在需要時才在開始下載引發(fā)的問題,比如只出現在
:hover偽類中的圖片,不會出現閃爍。
參考
如何解決不同瀏覽器的樣式兼容性問題?
在確定問題原因和有問題的瀏覽器后,使用單獨的樣式表,僅供出現問題的瀏覽器加載。這種方法需要使用服務器端渲染。
使用已經處理好此類問題的庫,比如 Bootstrap。
使用
autoprefixer自動生成 CSS 屬性前綴。使用 Reset CSS 或 Normalize.css。
如何為功能受限的瀏覽器提供頁面? 使用什么樣的技術和流程?
優(yōu)雅的降級:為現代瀏覽器構建應用,同時確保它在舊版瀏覽器中正常運行。
Progressive enhancement - The practice of building an application for a base level of user experience, butadding functional enhancements when a browser supports it.
漸進式增強:構建基于用戶體驗的應用,但在瀏覽器支持時添加新增功能。
利用 caniuse.com 檢查特性支持。
使用
autoprefixer自動生成 CSS 屬性前綴。使用 Modernizr進行特性檢測。
有什么不同的方式可以隱藏內容(使其僅適用于屏幕閱讀器)?
這些方法與可訪問性(a11y)有關。
visibility: hidden:元素仍然在頁面流中,并占用空間。width: 0; height: 0:使元素不占用屏幕上的任何空間,導致不顯示它。position: absolute; left: -99999px: 將它置于屏幕之外。text-indent: -9999px:這只適用于block元素中的文本。Metadata: 例如通過使用 Schema.org,RDF 和 JSON-LD。
WAI-ARIA:如何增加網頁可訪問性的 W3C 技術規(guī)范。
即使 WAI-ARIA 是理想的解決方案,我也會采用絕對定位方法,因為它具有最少的注意事項,適用于大多數元素,而且使用起來非常簡單。
參考
你使用過柵格系統(tǒng)嗎?偏愛哪一個?
我使用 float-based 柵格系統(tǒng),因為它相比 flex、grid 系統(tǒng),擁有更多瀏覽器的支持。它已經在 Bootstrap 中使用多年,并且已經被證明是可行的。
你是否使用過媒體查詢或移動優(yōu)先的布局?
是的,一個例子就是根據窗口的尺寸改變導航的樣式。
你熟悉制作 SVG 嗎?
不好意思,不熟悉。
除了screen,你還能說出一個 @media 屬性的例子嗎?
TODO
編寫高效的 CSS 應該注意什么?
首先,瀏覽器從最右邊的選擇器,即關鍵選擇器(key selector),向左依次匹配。根據關鍵選擇器,瀏覽器從 DOM中篩選出元素,然后向上遍歷被選元素的父元素,判斷是否匹配。選擇器匹配語句鏈越短,瀏覽器的匹配速度越快。避免使用標簽和通用選擇器作為關鍵選擇器,因為它們會匹配大量的元素,瀏覽器必須要進行大量的工作,去判斷這些元素的父元素們是否匹配。
BEM (Block Element Modifier) methodology recommends that everything has a single class, and, where you needhierarchy, that gets baked into the name of the class as well, this naturally makes the selector efficient and easy tooverride. BEM (Block Element Modifier)原則上建議為獨立的 CSS 類命名,并且在需要層級關系時,將關系也體現在命名中,這自然會使選擇器高效且易于覆蓋。
搞清楚哪些 CSS 屬性會觸發(fā)重新布局(reflow)、重繪(repaint)和合成(compositing)。在寫樣式時,避免觸發(fā)重新布局的可能。
參考
使用 CSS 預處理的優(yōu)缺點分別是什么?
優(yōu)點:
提高 CSS 可維護性。
易于編寫嵌套選擇器。
引入變量,增添主題功能??梢栽诓煌捻椖恐泄蚕碇黝}文件。
通過混合(Mixins)生成重復的 CSS。
Splitting your code into multiple files. CSS files can be split up too but doing so will require a HTTP request todownload each CSS file.
將代碼分割成多個文件。不進行預處理的 CSS,雖然也可以分割成多個文件,但需要建立多個 HTTP 請求加載這些文件。
缺點:
需要預處理工具。
重新編譯的時間可能會很慢。
對于你使用過的 CSS 預處理,說說喜歡和不喜歡的地方?
喜歡:
絕大部分優(yōu)點上題以及提過。
Less 用 JavaScript 實現,與 NodeJS 高度結合。
Dislikes:
我通過
node-sass使用 Sass,它用 C ++ 編寫的 LibSass 綁定。在 Node 版本切換時,我必須經常重新編譯。Less 中,變量名稱以
@作為前綴,容易與 CSS 關鍵字混淆,如@media、@import和@font-face。
如何實現一個使用非標準字體的網頁設計?
使用@font-face并為不同的font-weight定義font-family。
解釋瀏覽器如何確定哪些元素與 CSS 選擇器匹配。
這部分與上面關于編寫高效的 CSS 有關。瀏覽器從最右邊的選擇器(關鍵選擇器)根據關鍵選擇器,瀏覽器從 DOM中篩選出元素,然后向上遍歷被選元素的父元素,判斷是否匹配。選擇器匹配語句鏈越短,瀏覽器的匹配速度越快。
例如,對于形如p span的選擇器,瀏覽器首先找到所有<span>元素,并遍歷它的父元素直到根元素以找到<p>元素。對于特定的<span>,只要找到一個<p>,就知道'`已經匹配并停止繼續(xù)匹配。
參考
描述偽元素及其用途。
CSS 偽元素是添加到選擇器的關鍵字,去選擇元素的特定部分。它們可以用于裝飾(:first-line,:first-letter)或將元素添加到標記中(與 content:...組合),而不必修改標記(:before,:after)。
:first-line和:first-letter可以用來修飾文字。上面提到的
.clearfix方法中,使用clear: both來添加不占空間的元素。使用
:before和after展示提示中的三角箭頭。鼓勵關注點分離,因為三角被視為樣式的一部分,而不是真正的DOM。如果不使用額外的HTML元素,只用CSS樣式繪制三角形是不太可能的。
參考
說說你對盒模型的理解,以及如何告知瀏覽器使用不同的盒模型渲染布局。
CSS盒模型描述了以文檔樹中的元素而生成的矩形框,并根據排版模式進行布局。每個盒子都有一個內容區(qū)域(例如文本,圖像等)以及周圍可選的padding、border和margin區(qū)域。
CSS盒模型負責計算:
塊級元素占用多少空間。
邊框是否重疊,邊距是否合并。
盒子的尺寸。
盒模型有以下規(guī)則:
塊級元素的大小由
width、height、padding、border和margin決定。如果沒有指定
height,則塊級元素的高度等于其包含子元素的內容高度加上padding(除非有浮動元素,請參閱下文)。如果沒有指定
width,則非浮動塊級元素的寬度等于其父元素的寬度減去父元素的padding。元素的
height是由內容的height來計算的。元素的
width是由內容的width來計算的。默認情況下,
padding和border不是元素width和height的組成部分。
參考
* { box-sizing: border-box; }會產生怎樣的效果?
元素默認應用了
box-sizing: content-box,元素的寬高只會決定內容(content)的大小。box-sizing: border-box改變計算元素width和height的方式,border和padding的大小也將計算在內。元素的
height= 內容(content)的高度 + 垂直方向的padding+ 垂直方向border的寬度元素的
width= 內容(content)的寬度 + 水平方向的padding+ 水平方向border的寬度
display的屬性值都有哪些?
-
none,block,inline,inline-block,table,table-row,table-cell,list-item.
TODO
inline和inline-block有什么區(qū)別?
我把block也加入其中,為了獲得更好的比較。
relative、fixed、absolute和static四種定位有什么區(qū)別?
經過定位的元素,其position屬性值必然是relative、absolute、fixed或sticky。
static:默認定位屬性值。該關鍵字指定元素使用正常的布局行為,即元素在文檔常規(guī)流中當前的布局位置。此時 top, right, bottom, left 和 z-index 屬性無效。relative:該關鍵字下,元素先放置在未添加定位時的位置,再在不改變頁面布局的前提下調整元素位置(因此會在此元素未添加定位時所在位置留下空白)。absolute:不為元素預留空間,通過指定元素相對于最近的非 static 定位祖先元素的偏移,來確定元素位置。絕對定位的元素可以設置外邊距(margins),且不會與其他邊距合并。fixed:不為元素預留空間,而是通過指定元素相對于屏幕視口(viewport)的位置來指定元素位置。元素的位置在屏幕滾動時不會改變。打印時,元素會出現在的每頁的固定位置。fixed 屬性會創(chuàng)建新的層疊上下文。當元素祖先的 transform 屬性非 none 時,容器由視口改為該祖先。sticky:盒位置根據正常流計算(這稱為正常流動中的位置),然后相對于該元素在流中的 flow root(BFC)和containing block(最近的塊級祖先元素)定位。在所有情況下(即便被定位元素為table時),該元素定位均不對后續(xù)元素造成影響。當元素 B 被粘性定位時,后續(xù)元素的位置仍按照 B 未定位時的位置來確定。position:sticky對table元素的效果與position: relative相同。
參考
你使用過哪些現有的 CSS 框架?你是如何改進它們的?
Bootstrap: 更新周期緩慢。Bootstrap 4 已經處于 alpha 版本將近兩年了。添加了在頁面中廣泛使用的微調按鈕組件。
Semantic UI:源代碼結構使得自定義主題很難理解。非常規(guī)主題系統(tǒng)的使用體驗很差。外部庫的路徑需要硬編碼(hard code)配置。變量重新賦值沒有 Bootstrap 設計得好。
Bulma: 需要很多非語義的類和標記,顯得很多余。不向后兼容,以至于升級版本后,會破壞應用的正常運行。
你了解 CSS Flexbox 和 Grid 嗎?
了解。Flexbox 主要用于一維布局,而 Grid 則用于二維布局。
Flexbox 解決了 CSS 中的許多常見問題,例如容器中元素的垂直居中,粘性定位(sticky)的頁腳等。Bootstrap 和Bulma 基于 Flexbox,這是創(chuàng)建布局的推薦方式。我之前曾使用過 Flexbox,但在使用flex-grow時遇到了一些瀏覽器不兼容問題(Safari),我必須使用inline-blocks和手動計算百分比寬度,來重寫我的代碼,這種體驗不是很好。
Grid 創(chuàng)建基于柵格的布局,是迄今為止最直觀的方法(最好是?。?,但目前瀏覽器支持并不廣泛。
參考
請解釋在編寫網站時,響應式與移動優(yōu)先的區(qū)別。
TODO
響應式設計與自適應設計有何不同?
響應式設計和自適應設計都以提高不同設備間的用戶體驗為目標,根據視窗大小、分辨率、使用環(huán)境和控制方式等參數進行優(yōu)化調整。
響應式設計的適應性原則:網站應該憑借一份代碼,在各種設備上都有良好的顯示和使用效果。響應式網站通過使用媒體查詢,自適應柵格和響應式圖片,基于多種因素進行變化,創(chuàng)造出優(yōu)良的用戶體驗。就像一個球通過膨脹和收縮,來適應不同大小的籃圈。
自適應設計更像是漸進式增強的現代解釋。與響應式設計單一地去適配不同,自適應設計通過檢測設備和其他特征,從早已定義好的一系列視窗大小和其他特性中,選出最恰當的功能和布局。與使用一個球去穿過各種的籃筐不同,自適應設計允許使用多個球,然后根據不同的籃筐大小,去選擇最合適的一個。
參考
你有沒有使用過視網膜分辨率的圖形?當中使用什么技術?
我傾向于使用更高分辨率的圖形(顯示尺寸的兩倍)來處理視網膜顯示。更好的方法是使用媒體查詢,像@mediaonly screen and (min-device-pixel-ratio: 2) { ... },然后改變background-image。
對于圖標類的圖形,我會盡可能使用 svg 和圖標字體,因為它們在任何分辨率下,都能被渲染得十分清晰。
還有一種方法是,在檢查了window.devicePixelRatio的值后,利用 JavaScript 將<img>的src屬性修改,用更高分辨率的版本進行替換。
參考
什么情況下,用translate()而不用絕對定位?什么時候,情況相反。
translate()是transform的一個值。改變transform或opacity不會觸發(fā)瀏覽器重新布局(reflow)或重繪(repaint),只會觸發(fā)復合(compositions)。而改變絕對定位會觸發(fā)重新布局,進而觸發(fā)重繪和復合。transform使瀏覽器為元素創(chuàng)建一個 GPU 圖層,但改變絕對定位會使用到 CPU。 因此translate()更高效,可以縮短平滑動畫的繪制時間。
當使用translate()時,元素仍然占據其原始空間(有點像position:relative),這與改變絕對定位不同。