到底該不該用 CSS reset?
小弟接觸css也有些時日,初學的時候發現瀏覽器間初始化有點不同,搜索得知css reset 可以重置,從那時起不論寫什麼css,都會前面加一段 css reset,偶有一次看到一篇反對css reset的文章,講得也頗有道理,確實自己經常濫用,但不用的話,又好像怕會出現什麼問題,特此請教下各位高手,如何解決,用還是不用,用怎麼用?不用有什麼其他解決辦法?或者摺合兩者的辦法?望指點!
感謝 @賀師俊 老師和 @sapjax 兩位的討論,沒想到這麼熱鬧:) 綜合起來我的目前觀點是:用不用CSS reset,取決於「是否需要依賴瀏覽器默認樣式」。
另外,決策此事似乎並不需要顧慮性能(詳見下文)。=====================我給 @賀師俊 的回答點了贊,但我認為其中提到的CSS reset會導致問題的情況都是有前提的。1. 不當的破壞了所有瀏覽器的基本樣式。最典型的混蛋做法就是將所有元素的margin/padding設為0,及去掉ol/ul的列表樣式,去掉h1~h6的字體大小樣式。這導致blockquote、ol、ul、hn等語義元素在沒有賦以其他合理的樣式時(常常如此),缺乏恰當的樣式展現。
這種情況導致問題的前提是,頁面設計師沒有對頁面可能出現的每一個元素進行設計,導致部分元素直接依賴於瀏覽器默認樣式。
---------2014.12.4 補充---------&<賀老師提到1. 設計師可能對所有元素設置樣式嗎?
對很多項目來說,用戶的輸入是受限的,頁面上的元素也是有限的,所以設計師完全可能對所有可能出現的元素設置樣式。
如果他都設置了,那麼你就根本不需要css reset了——我的第4點寫著:可能某條reset規則中的所有屬性設置實際上並沒有在任何元素上生效(因為全部被更specific的規則給覆蓋了)。
我覺得CSS reset除了省心外,始終有兩個用處:
- 方便設計師/程序員發揮「白紙」的感覺確實好。各種margin padding border為0,折騰起來會有指哪兒打哪兒的快感~ 像我這樣喜歡直接在瀏覽器里設計的傢伙就更別說了。
- 便於發現前端代碼的遺漏用了reset後,如果「blockquote、ol、ul、hn等語義元素在沒有賦以其他合理的樣式」,會非常扎眼(任何人都看得出來),開發者第一反應會是「卧槽忘了寫」並迅速補救。但如果沒reset,瀏覽器會提供「勉強可以」的默認樣式,很多人可能就發現不了或者會想「可能就這麼設計的吧」,開發者即使意識到因為遺漏導致和設計稿不一致,出於人性弱點也可能會想「還要趕下一個項目呢先這麼湊合著吧」。——由於破窗效應,這可能會導致越來越多的「湊合著吧」……
&>---------
在寫前端的時候不把各種元素都處理一遍,等到用戶數據出來之後才發現問題——這種項目,顯然是屬於允許出現一些「隨意設計」,「信任瀏覽器默認樣式也沒問題「的項目。或者說,是對視覺效果要求不高的項目。
而因為視覺上無法區分,這進一步導致許多開發人員忽視或誤用這些語義元素,並嚴重破壞團隊內其他希望使用語義元素的開發人員的工作流程。
前端工程師沒有「視覺區分」就不知道按語義使用元素……聽上去好像很不合格呀。
---------2014.12.4 補充---------&<@賀師俊 老師提到「而因為視覺上無法區分,這進一步導致許多開發人員忽視或誤用這些語義元素」。看到「進一步導致」這幾個字嗎?看到「開發人員」這個稱謂嗎?我為什麼不寫「前端工程師」或者「合格的前端工程師」?有人是天生合格的嗎?合格的工程師就不寫爛代碼了嗎?寫出爛代碼一定是他不合格嗎?
我認為「依賴視覺區分而不是本身的語義識別元素」這樣的錯誤不同於寫「爛代碼」,這是方法論層面的原則性錯誤,無論是新手還是老手都不應該,喝醉酒了也不應該。試想如果一個靠HTML吃飯的人認為address可以替代i,原因是他發現address會帶來斜體,你是把他開了呢還是把他開了呢?而且有基本技術素養的開發者也不至於被這種低級錯誤帶著跑。
&>---------2. 瀏覽器為配合控制項風格,或出於可用性和無障礙性考慮,會有一些特定的默認樣式。如一些瀏覽器對於 input[type=radio] 默認有 margin,以確保單選框的外觀比較協調。粗暴的reset導致控制項外觀可能在特定瀏覽器下失調。又如大部分交互控制項在獲得焦點時有虛線outline。去掉這樣式而又不提供其他對於焦點的視覺反饋機制(常常如此)可能導致可用性和無障礙性問題。
同上,如果依賴瀏覽器自己提供的input的margin ~~虛線outline~~(2014.12.4 補充:謝謝 @sapjax 提醒,Eric版本的reset里要求控制虛線outline確實太龜毛了,input margin舉例比較合適),如何保證是自己想要的視覺效果?說明還是要求不高。
3. 某些use case中,網頁中有有一些較高獨立性的部分,比如內嵌編輯器、widget、第三方內容等,CSS reset導致這部分的樣式常需要完全重新覆寫,而這種覆寫本來可能大部分是不必要的,令人煩躁且可能遺漏。參考此問答:怎樣不讓 CSS reset 樣式覆蓋掉編輯器內的文章樣式?
這說明「內嵌編輯器、widget、第三方內容」有可能並不完整定義樣式,而依賴瀏覽器默認樣式。這樣的項目應該是在一個比較複雜的生態中。
4. ……極端情況下,可能某條reset規則中的所有屬性設置實際上並沒有在任何元素上生效(因為全部被更specific的規則給覆蓋了),所有針對此規則的級聯計算全都是浪費。
~~這個的前提是CSS reset 樣式計算的成本值得一care(那應該是大鱷型產品了)。~~
---------2014.12.4 補充---------&<針對我的說法,賀老師提到非也,性能是否成為問題取決於頁面dom的規模,很簡單的產品也可能有很大量的dom節點,特別是包含用戶數據的。比如最簡單的列表頁,列表也可能長達上萬項。
這一點贊同,受教。不過為了分析CSS reset對性能的影響,我做了一些研究,發現CSS reset對性能的影響也許真的可以忽略。
我用YUI的reset寫了一個小測試頁面(大概有一萬多node)在本地進行測試,發現CSS對性能的影響微乎其微。甚至注釋掉CSS reset反倒讓頁面慢了20多毫秒(大概是因為頁面變長了~呃):CSS reset測試頁面 我這個測試估計沒啥可靠度,不過參考下面幾位對CSS性能影響的測試,個人感覺大概率是不需要考慮性能問題的,求指正: CSS Tip: Star Selector Not That BadPerformance Impact of CSS Selectors另外賀老師提到文末這段我再貼一遍:除了非常明確的使用 normalize.css 之類的既定方案的情況,許多團隊常見自行 customize 一個 reset.css 或混合了 reset 的 base.css。這種情況下,隨著時間流逝最可能出現的情形就是此 css 會逐漸混入了更多的全局性的樣式(因為合格的程序員都有增強復用性的衝動),從而陷入之前說的那些問題。因此,未雨綢繆的做法,就是一開始就避免使用 CSS reset,或嚴格明確和限定其作用(如 normalize 的方式)。
這和是否使用CSS reset,應該是兩個問題。隨便定義全局樣式這種習慣,似乎不能賴在reset上;沒有reset,開發者仍然可能隨便定義全局樣式(其實似乎normalize才可能「誘使」開發者寫全局樣式)。
&>---------而如果一個團隊有巨細靡遺的設計師,基本合格的前端工程師,較少使用或者嚴格限制使用第三方內容,在幾毫秒的性能差異可以忽略的情況下——如果需要省心省力快速開發,同時對視覺效果要求嚴格,那CSS reset仍然是不二之選(mixin的方式省心程度仍然不如reset,而且會增加CSS文件大小)。
換句話說,如果項目特別注重性能,工程師時間足(有空去關注不同瀏覽器默認樣式或者normalize的各種細節),或設計師資源薄弱,不用reset;反之,reset依然是個能讓人「迅速獲得一張白紙」的好東西。
---------2014.12.4 補充---------&<我認為CSS reset適用的場景還是很常見的,比如:- 各種以展示為主的頁面。本來就應該對頁面每一個元素進行設計,又沒啥用戶輸入,即便為了頁面邊距問題import一個reset.css,也算省了腦筋。
- Basecamp這樣對用戶界面要求精細的項目。本來就不可能讓瀏覽器默認樣式發揮作用;在功能密集開發的時期(需要省心),引入reset能讓大家都爽一點,從工程式控制制的角度還能進一步避免漏寫樣式,確保質量;若是考慮避免了mixin方式引入局部reset(這種事情在工程角度就更不可控了,容易濫用)導致的CSS文件大小增加,甚至可以說有助於性能。
&>---------
=======================================值得一提的是,賀老師談到:導致這些問題共通的本質性因素是:CSS reset 的作用是全局性的(即缺乏選擇器限定範圍)。所有合格的程序員都知道避免濫用全局變數,但是在 CSS 上他們就忘記了這一點。」
這段話我認為是不成立的。這裡面的「全局變數」並沒有可能避免使用,要麼在reset中定義(只有一個,變數可控),要麼放任瀏覽器自己定義(多個瀏覽器,而且各種升級,變數不可控)。從這個角度來說,反而應該支持使用CSS reset才對。
---------2014.12.4 補充---------&<賀老師提到瀏覽器的默認樣式不是全局變數而是相當於常量。我開篇就講「現代瀏覽器差異已經很小,所以 CSS reset 的必要性就不那麼高了」。
個人認為既然是「很小」而不是「沒有」,而且隨著版本升級還不一定就不變化,就不能算「常量」。即使是常量,正如 @sapjax 說的,是不是所有開發者都有必要耗費寶貴的生命,去記憶這些常量呢?CSS reset相比瀏覽器默認樣式的最大優勢,就是「好記」啊。
&>---------最初出現 CSS reset 的目的是解決瀏覽器在默認樣式上的諸多差異和問題。而現代瀏覽器在這方面的差異已經小了很多,所以 CSS reset 的必要性就不那麼高了。
另一方面,濫用 CSS reset 導致一些問題:
1. 不當的破壞了所有瀏覽器的基本樣式。最典型的混蛋做法就是將所有元素的margin/padding設為0,及去掉ol/ul的列表樣式,去掉h1~h6的字體大小樣式。這導致blockquote、ol、ul、hn等語義元素在沒有賦以其他合理的樣式時(常常如此),缺乏恰當的樣式展現。而因為視覺上無法區分,這進一步導致許多開發人員忽視或誤用這些語義元素,並嚴重破壞團隊內其他希望使用語義元素的開發人員的工作流程。
2. 瀏覽器為配合控制項風格,或出於可用性和無障礙性考慮,會有一些特定的默認樣式。如一些瀏覽器對於 input[type=radio] 默認有 margin,以確保單選框的外觀比較協調。粗暴的reset導致控制項外觀可能在特定瀏覽器下失調。又如大部分交互控制項在獲得焦點時有虛線outline。去掉這樣式而又不提供其他對於焦點的視覺反饋機制(常常如此)可能導致可用性和無障礙性問題。
3. 某些use case中,網頁中有有一些較高獨立性的部分,比如內嵌編輯器、widget、第三方內容等,CSS reset導致這部分的樣式常需要完全重新覆寫,而這種覆寫本來可能大部分是不必要的,令人煩躁且可能遺漏。參考此問答:怎樣不讓 CSS reset 樣式覆蓋掉編輯器內的文章樣式?
4. CSS reset 通常會增加瀏覽器進行樣式計算的成本(即有一定的性能負擔),因為它引入了許多的針對元素的全局規則,網頁中幾乎所有元素都會匹配一條乃至幾條的reset規則,且往往規則中的屬性設定其實會被更specific的規則所覆蓋(比如padding和margin)。極端情況下,可能某條reset規則中的所有屬性設置實際上並沒有在任何元素上生效(因為全部被更specific的規則給覆蓋了),所有針對此規則的級聯計算全都是浪費。
注意一點,導致這些問題共通的本質性因素是:CSS reset 的作用是全局性的(即缺乏選擇器限定範圍)。所有合格的程序員都知道避免濫用全局變數,但是在 CSS 上他們就忘記了這一點。
因此,除了上述4點所提到的問題,從可維護性上來看,所有全局變數可能導致的維護性噩夢也會以類似的方式發生在 CSS reset 上。比如一旦引入了 CSS reset,當項目規模大到一定程度,要再想把 CSS reset 從項目中去掉,就十分困難。
解決方法:
1. 不使用 CSS reset,或使用那些謹慎的,只是用來消除瀏覽器默認樣式不一致的真正的 CSS reset(更準確的稱謂或許是 CSS normalize,參考此問答:Normalize.css 與傳統的 CSS Reset 有哪些區別?)。
2. 對於特定的reset需求,只在真正需要的時候,單獨設置。若要提高代碼復用程度,可以引入CSS預處理,以mixin來做。例子:@mixin reset-box() {
list-style: none
padding: 0
margin: 0
}
@mixin reset-font() {
font-size: 1em
font-weight: normal
font-style: normal
}
//真正用的場景
html#示例網站 {
nav#全站導航條 ul {
border: 1px solid
+reset-box()
}
section.側欄模塊 {
border: 1px solid
h1 {
background: navy
color: white
border-bottom: 1px solid
+reset-box()
+reset-font()
}
}
}
(以上以偽代碼書寫,請自行腦補轉換為 SASS/Stylus/LESS 等。)
3. 對於已經使用 CSS reset 的同學,可以籍由支持局部 import 的 CSS 預處理器(比如 stylus)的幫助,從限定其在特定 selector 之下開始,逐步控制其影響範圍。如:
html#示例網站 {
... // 不依賴 CSS reset 的部分
.legacy-part { // 頁面中仍依賴 CSS reset 的部分
@import "reset.css"
}
}
最後順帶說下,CSS 3 已加入 unset 關鍵字和 all 快捷屬性(目前僅 Firefox 支持),可以更好的支持必要的 reset 需求。
以上。
補充:
有些同學認為「沒有那種很傻叉的重置的話,我覺得都算不上是濫用」。問題在於,怎麼樣算是「傻叉重置」?團隊里的每個人對此認識一致嗎?將來新人進入老人離開,還能保持對此認識一致嗎?
除了非常明確的使用 normalize.css 之類的既定方案的情況,許多團隊常見自行 customize 一個 reset.css 或混合了 reset 的 base.css。這種情況下,隨著時間流逝最可能出現的情形就是此 css 會逐漸混入了更多的全局性的樣式(因為合格的程序員都有增強復用性的衝動),從而陷入之前說的那些問題。因此,未雨綢繆的做法,就是一開始就避免使用 CSS reset,或嚴格明確和限定其作用(如 normalize 的方式)。首先要明確下面兩個概念:
- 傳統的CSS reset指的是把所有的瀏覽器默認樣式全部幹掉。
- Normalize.css:非常溫和的CSS reset替代方案,具體可以看normalize.css的作者Nicolas寫的一篇文章:About normalize.css(另外也可以參考我的譯文:Jerry的樂園 | 來,讓我們談一談 Normalize.css)
我覺得很多人都混淆了兩者的概念,所以用於重定義全站樣式更加貼切的說法是normalize,Normalize.css本身也提供了定製自己的網站所需要的一般化配置。
我覺得是這樣,要是只是學習呢,就不要用,但是作為網站開發,團隊合作確必不可少,因為大家時間都有限,沒工夫一個個css的去調
reset提供了很大的便利,但是濫用以後功能有些過分。
更迭快的產品以及需要多人合作的項目,還是很有必要的,可以避免很多的麻煩。如果配合比較規範的ui,可以發揮更大的作用。但是使用不當,上面的那些條件不怎麼附和的時候,也造成後續的一些工作量的增大。我覺得主要還是看和規範的聯繫緊密不緊密。對個人開發者沒必要。對團隊規範卻十分需要。
不寫頁面的人當然站著說話不腰疼了,現代瀏覽器之間差異現在仍然很大(這是事實),去看看那些國產瀏覽器廠商抄的內核版本是多少!如果你還在寫頁面,寫css,reset是必須的,因為你還在寫頁面,你還在寫css,所以你基本都搞不清楚那些是有用的,哪些是沒用的,所以全部幹掉是最好的方法,談哲學大家都很在行,多談點實用才是硬道理。
之前很經常用
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}body{background:#e8f0ff;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0 none;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}strong{font-weight:800;}ol,ul,li{list-style:none outside none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}一直調用,根本停不下來建議任何項目都用,並且要用廣為人知的那種,如 normalize.css。仔細讀懂每一行的作用,這樣有 bug 才能迅速做出反應。
瀏覽器差異慢慢會變得越來越小,但一定還是會有差異的。CSS reset 永遠都是必要的。推薦閱讀:
※line-height:normal是怎樣計算的?
※全局樣式加 float:left 導致 div{margin:0 auto;} 不起作用,為什麼?
※各大網站的 CSS 布局對行級元素是不是有些濫用?
※請問怎麼通俗的理解css中的行框和行內框?
※為什麼排版引擎解析 CSS 選擇器時一定要從右往左解析?