您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(guān)如何深入解析自定義的CSS重置樣式,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
每當(dāng)我開始一個新項(xiàng)目時,首要的任務(wù)就是處理 CSS 語言中的那些邊邊角角的問題。為了解決這些問題,通常會使用自定義的一組基礎(chǔ)樣式。
在過去很長一段時間,我使用的是來自 Eric Meyer 那份著名的 CSS 重置樣式(CSS Reset)。作為一份古老且實(shí)用的 CSS 代碼,在過去十多年里它從未被更新過,而這期間很多東西都已經(jīng)發(fā)生了巨大的變化!
最近,我開始使用我自己定義的 CSS 重置樣式。它包含了我總結(jié)的諸多小技巧,既可以改善用戶體驗(yàn)又能提高 CSS 開發(fā)體驗(yàn)。我們將介紹這個自定義的 CSS 重置樣式。并深入研究其中的每一條規(guī)則,除了討論每條規(guī)則的作用之外,還將深入淺出的解析使用該規(guī)則的原因!
從歷史上看,CSS 重置樣式主要作用是清除了瀏覽器的默認(rèn)樣式,以此來保證瀏覽器之間樣式的一致性。而我的這份 CSS 重置樣式并不是為了解決這個問題。
如今,不同瀏覽器之間在布局或間距方面的差異已經(jīng)微乎其微??偟膩碚f,現(xiàn)代的瀏覽器,正如我們所期望的那樣,已經(jīng)忠實(shí)地實(shí)現(xiàn)了 CSS 規(guī)范。所以,對樣式一致性問題的處理已經(jīng)不是那么重要了。
而且,我從不認(rèn)為去掉瀏覽器所有的默認(rèn)樣式是必要的。例如,我會用 <em> 標(biāo)簽將字體樣式設(shè)置為斜體!雖然在不同的項(xiàng)目中可能要遵守不同的設(shè)計(jì)規(guī)范,但我認(rèn)為去除常識性的默認(rèn)設(shè)置是毫無意義的。
我的這份 CSS 重置樣式可能不符合 “CSS重置樣式” 的經(jīng)典定義,但從另外一個角度來說,這份 CSS 重置樣式也擁有了更多的創(chuàng)造性。
閑話少敘,直接上代碼:
/* 1. Use a more-intuitive box-sizing model. */ *, *::before, *::after { box-sizing: border-box; } /* 2. Remove default margin */ * { margin: 0; } /* 3. Allow percentage-based heights in the application */ html, body { height: 100%; } /* Typographic tweaks! 4. Add accessible line-height 5. Improve text rendering */ body { line-height: 1.5; -webkit-font-smoothing: antialiased; } /* 6. Improve media defaults */ img, picture, video, canvas, svg { display: block; max-width: 100%; } /* 7. Remove built-in form typography styles */ input, button, textarea, select { font: inherit; } /* 8. Avoid text overflows */ p, h2, h3, h4, h5, h6, h7 { overflow-wrap: break-word; } /* 9. Create a root stacking context */ #root, #__next { isolation: isolate; }
雖然代碼較短,但在這個小樣式表中包含了很多干貨。讓我們開始吧!
在開始之前,先回答一個問題!在沒有其他 CSS 樣式的情況下,下面代碼中的 .box
元素(粉紅色邊框的矩形區(qū)域)的寬度是多少?是 200px、240px、244px 還是 0px 呢?
<style> .parent { width: 200px; } .box { width: 100%; border: 2px solid hotpink; padding: 20px; } </style> <div class="parent"> <div class="box"></div> </div>
在 .box
元素的樣式中設(shè)置了 width: 100%
,由于它的父元素 .parent
的寬度是 200px,所以 這里的 100% 會被解析為 200px。
那么這 200px 的寬度會作用在哪里呢?默認(rèn)情況下,瀏覽器會將這個寬度應(yīng)用在內(nèi)容框上 (content box)。正如我們所熟知的那樣,這里所說的 “內(nèi)容框” 是盒模型里的盒子實(shí)際包含的內(nèi)容,它在 border 和 padding 內(nèi)部:
width: 100%
將 .box
盒模型的 content 部分設(shè)置為 200px;內(nèi)邊距 padding 會額外增加 40px 寬度(每邊各 20px);邊框 border 會增加 4px(每邊各 2px)。通過加法計(jì)算不難得出粉色邊框矩形的寬度為 244px。因此,上面提到的問題的答案是 244px。
當(dāng)我們試圖將一個 244px 的盒子塞進(jìn)一個 200px 寬的父容器時,它會發(fā)生溢出:
這種行為看起來很奇怪,我們可以通過以下設(shè)置來更改它:
*, *::before, *::after { box-sizing: border-box; }
應(yīng)用此規(guī)則后,寬度的百分比將基于 border-box 進(jìn)行解析。在上面的例子中,我們的粉色框是 200px,而內(nèi)部的 content-box 將縮小到 156px (200px - 40px - 4px)。
在我看來,這是一條必不可少的樣式的規(guī)則,因?yàn)樗鼤?CSS 更易于使用。我們用通配符選擇器(*
)將其應(yīng)用于所有元素和偽元素。與大眾認(rèn)知完全相左的是,這個樣式設(shè)置并不會導(dǎo)致性能變壞,具體可參考文章* { Box-sizing: Border-box } FTW。
Inheriting box-sizing
我在網(wǎng)上看到了另外一種樣式設(shè)置:
html { box-sizing: border-box; } *, *:before, *:after { box-sizing: inherit; }
如果您想在一個已存在的大型項(xiàng)目中遷移使用 border-box,那么這將是一個有用的策略。如果你從零開始一個全新的項(xiàng)目,這是沒有必要的。為了簡單起見,我在 CSS 重置樣式中省略了它。
首先,我們可以創(chuàng)建一個 “l(fā)egacy” 選擇器,將 box-sizing 的值繼續(xù)保留為 content-box
,這也是 box-sizing 屬性的默認(rèn)值:
.legacy { box-sizing: content-box; }
然后,當(dāng)應(yīng)用程序中存在尚未遷移使用 border-box 時,我們就可以將該類添加到對應(yīng)的位置,以保持原有樣式不被影響:
<body> <header class="legacy"> <nav> <!-- Legacy stuff here --> </nav> </header> <main> <section> <!-- Modern stuff here --> </section> <aside class="legacy"> <!-- Legacy stuff here --> </aside> </main> </body>
為什么要這樣做呢?現(xiàn)在,讓我們思考一下這個代碼段中的元素是如何計(jì)算的。
<header>
被賦予了 legacy
,因此它使用了 box-sizing: content-box
。
其子元素 <nav>
的樣式為 box-sizing: inherit
。由于其父元素設(shè)置為 content-box
,nav
也將設(shè)置為 content-box
。
<main>
標(biāo)簽沒有 legacy
,因此它從其父級 <body>
繼承;而 <body>
繼承自 <html>
;<html>
已經(jīng)被設(shè)置為 border-box
。
從本質(zhì)上講,每個元素都可以從其父元素獲得 box-sizing 屬性。如果它有一個設(shè)置了 legacy
的祖先,那么它的屬性值是 content-box
。否則,它將最終從 <html>
標(biāo)簽中繼承,其屬性值為 border-box
。
* { margin: 0; }
瀏覽器會對外邊距 (margin) 做出很多常識性假設(shè)。例如,h2
在默認(rèn)情況下要比段落的邊距更大。這些假設(shè)在那些做文字處理的文檔中是合理的,但對于現(xiàn)代 web 應(yīng)用程序來說可能并不準(zhǔn)確。
另外,外邊距會在你稍不留神的時候遭遇外邊距塌陷的問題,它可真是一個令人討厭的小機(jī)靈鬼呢。而且,我發(fā)現(xiàn)自己經(jīng)常希望元素在默認(rèn)情況下沒有任何外邊距。所以我決定把它全部去掉。
當(dāng)我確實(shí)希望向特定的標(biāo)簽添加外邊距時,我可以在項(xiàng)目中用自定義樣式中來實(shí)現(xiàn)。通配符選擇器(*
)的優(yōu)先級極低,這條規(guī)則很容易被覆蓋。
html, body { height: 100%; }復(fù)制代碼
我們在 CSS 中經(jīng)常會使用百分比來設(shè)置高度,很多時候卻發(fā)現(xiàn)它似乎并沒有效果。請看下面的示例:
雖然將 main
元素設(shè)置為 height: 100%
,但元素的高度根本沒有變化!
這里不起作用的原因是,在 CSS 流式布局(CSS 中的主要布局模式)中,height
和 width
的工作原理完全不同。元素的寬度是基于父元素計(jì)算的,元素的高度是根據(jù)其子元素計(jì)算的。這個話題說起來比較復(fù)雜,遠(yuǎn)遠(yuǎn)超出了本文的范圍,本文中不再展開討論。
在下面的代碼示例中,我們將上面的規(guī)則應(yīng)用到代碼中,會發(fā)現(xiàn) main
元素的高度變?yōu)榱?100%:
如果您使用的是像 React 這樣的 JavaScript 框架,那么您可能還需要在此規(guī)則中添加第三個選擇器:框架使用的根元素。
例如,在我的 Next.js 項(xiàng)目中,會將規(guī)則做如下更新:
html, body, #__next { height: 100%; }
為什么不使用 vh?
你可能會想:為什么非得使用百分比來設(shè)置高度呢?為什么不用 vh
替代呢?
問題是 vh
不能在移動設(shè)備上正常工作;在移動設(shè)備上瀏覽器 UI 在上下滑動的時候,視口的可見部分會進(jìn)行調(diào)整,這就導(dǎo)致 100vh
在瀏覽器中是不固定的,可能會超過屏幕實(shí)際的使用面積。
在未來,新的 CSS 單位將解決這個問題。在此之前,我繼續(xù)使用基于百分比的高度。
body { line-height: 1.5; }
行高 line-height
控制段落中每行文本之間的垂直間距。它的默認(rèn)值因?yàn)g覽器而異,但通常在 1.2 左右。這個沒有單位的數(shù)字是基于字體大小的比值。它的功能就像 em
一樣。line-height
為 1.2 時,每行的行高將比元素的字體大 20%。
這里帶來一個問題,對于那些有閱讀障礙的人來說,這些句子排得太近,使閱讀變得更困難。WCAG 標(biāo)準(zhǔn)規(guī)定,行高應(yīng)至少為 1.5。
現(xiàn)在,1.5 這個數(shù)字會影響標(biāo)題 (如 h2、h3 等標(biāo)簽) 和其他大字體元素,使它們產(chǎn)生了相當(dāng)大的行間距:
您可能直觀的想到,在標(biāo)題上重新設(shè)置行高。我的理解是,WCAG 標(biāo)準(zhǔn)是針對 “body” 文本,這里只對 body 設(shè)置了 1.5 倍行高。
使用 “calc” 靈活的設(shè)置 line-heights
我一直在嘗試著另一種設(shè)置行高的方法,如下所示:
* { line-height: calc(1em + 0.5rem); }
這是一個相當(dāng)高級的代碼片段,雖然它又超出了本文的范圍,這里還是會簡單做一下介紹。
這個方法并沒有用字體的大小值乘以 1.5 這樣的數(shù)字來計(jì)算行高,而是以字體大小作為基數(shù),并為每行添加固定的空間。對于 body 里面的文字段落((paragraphs),每行都將解析為 24px(假設(shè)使用的是瀏覽器的默認(rèn)字體大?。?。
不過,在較大的文本上,此聲明會產(chǎn)生更緊的行。下面的示例可以做出驗(yàn)證:
這個在使用時需謹(jǐn)慎,目前我還在試驗(yàn)中。
其中的一個缺點(diǎn)是,我們必須用 *
將其設(shè)置在所有元素上,而不是將其應(yīng)用于 body
。這是因?yàn)?em
單位不能被子元素很好地繼承;它不能使每個元素重新計(jì)>算 1em
所對應(yīng)的值。例如,在這個博客上,因?yàn)榈谌酱a假設(shè)行高是可繼承的,導(dǎo)致我的代碼被它破壞了。
有關(guān)這項(xiàng)技術(shù)的更多信息,請查看 Kitty Giraudel 的這篇很棒的博文:使用 calc 計(jì)算最佳行高。
body { -webkit-font-smoothing: antialiased; }
這個 CSS 設(shè)置存在一點(diǎn)爭議。
在 MacOS 計(jì)算機(jī)上,默認(rèn)情況下瀏覽器會使用 “亞像素抗鋸齒(subpixel antialiasing)”。這種技術(shù)可以利用每個像素內(nèi)的 R/G/B 燈光使文本更易于閱讀。
在過去,這個技術(shù)被認(rèn)為提高了可訪問性,因?yàn)樗纳屏宋谋緦Ρ榷?。你可能讀過一篇流行的博文,停止 “修復(fù)” 字體平滑,這篇文章并不提倡切換到 “抗鋸齒(antialiased)”。
問題是,這篇文章寫于 2012 年,那時高 DPI “視網(wǎng)膜(retina)” 顯示時代還未來臨。今天的像素更小,肉眼根本看不見。LED 像素的物理布局也發(fā)生了變化。如果你在顯微鏡下觀察現(xiàn)代顯示器,你已經(jīng)不會看到有序的 R/G/B 線網(wǎng)格了。
在 2018 年發(fā)布的 MacOS Mojave 中,蘋果公司在操作系統(tǒng)中禁用了亞像素抗鋸齒。我猜他們意識到,對現(xiàn)代硬件來說,這個技術(shù)的弊大于利。
令人困惑的是,像 Chrome 和 Safari 這樣的 MacOS 瀏覽器,在默認(rèn)情況下仍然使用亞像素抗鋸齒。因此,我們需要將 -webkit-font-smoothing
設(shè)置為 antialiased
來顯式關(guān)閉亞像素抗鋸齒。
這兩者的區(qū)別在于:
MacOS 是唯一使用亞像素抗鋸齒的操作系統(tǒng),因此這個 CSS 規(guī)則對 Windows、Linux 或移動設(shè)備沒有影響。如果您使用的是 MacOS 計(jì)算機(jī),則可以嘗試運(yùn)行一下下面的代碼示例:
img, picture, video, canvas, svg { display: block; max-width: 100%; }
在 CSS 中圖像被認(rèn)為是 “inline” 內(nèi)聯(lián)元素,也就意味著它們應(yīng)該像<em>
或 <strong>
那樣在段落中間使用。這與我們經(jīng)常使用圖像的方式是不符的。通常,我們使用圖片的方式與對待段落、標(biāo)題或邊欄的方式相同,這些都是布局元素。
但是,如果我們布局中試圖使用內(nèi)聯(lián)元素,就會碰到奇奇怪怪的事情。比如內(nèi)聯(lián)元素的 4px 空白間距問題,這個神奇的空白與 line-height
有關(guān)系。通過在所有圖像上設(shè)置 display:block
,我們避開了這一類問題。
我還設(shè)置了 max-width: 100%
,這樣做是為了防止大型圖像溢出,特別是它們被放在一個不夠?qū)挼娜萜髦小?/p>
大多數(shù)塊級元素將自動伸長/收縮以適應(yīng)其父元素,但像 <img>
這樣的媒體元素是特殊的:它們被稱為替換元素,并且它們也不遵循相同的規(guī)則。
如果圖像的 “自身的” 大小為 800 × 600,那么 <img>
元素的寬度也將為 800px,即使我們將其放入一個 500px 寬的父元素中。
這個規(guī)則將防止圖像超出其容器,我認(rèn)為這是一個比較明智的做法。
input, button, textarea, select { font: inherit; }
在默認(rèn)情況下,按鈕和輸入框不會從它們的父項(xiàng)繼承排版樣式。相反,他們有自己怪異的風(fēng)格。例如,<textarea>
將使用系統(tǒng)默認(rèn)的 Monospace 字體。文本輸入框?qū)⑹褂孟到y(tǒng)默認(rèn)的 sans-serif 字體。兩者都會選擇 microscopically-small 字體大小(Chrome 為 13.333px)。
正如您所想象的,在移動設(shè)備上閱讀 13px 的文本非常困難。當(dāng)我們聚焦設(shè)置了較小字體的輸入框時,瀏覽器會自動放大,這樣文本更容易閱讀。
不幸的是,這樣的用戶體驗(yàn)并不好:
如果要避免這種自動縮放行為,輸入的字體大小必須至少為 1rem/16px。有一種方法可以解決這個問題:
input, button, textarea, select { font-size: 1rem; }
這修正了自動縮放問題,但這只是一個權(quán)宜之計(jì)。讓我們從根本上來解決這個問題:表單輸入不應(yīng)該有自己的排版樣式!
input, button, textarea, select { font: inherit; }
font
是一種 CSS 設(shè)置字體的簡略寫法,它設(shè)置了一系列與字體相關(guān)的屬性,如 font-size
、font-weight
和 font-family
等。通過把它的值設(shè)置為 inherit
,可將這些元素與其周圍環(huán)境中的排版一致。
只要我們沒有在 body 中使用令人討厭的較小的字體,這就一次解決了我們所有的問題。
p, h2, h3, h4, h5, h6, h7 { overflow-wrap: break-word; }
在 CSS 中,如果沒有足夠的空間容納一行中的所有字符,文本將自動換行。
默認(rèn)情況下,算法將尋找 “軟換行” 機(jī)會;這些是算法可以對字符進(jìn)行拆分。在英語中,唯一軟換行的機(jī)會是空格和連字符,但這因語言而異。
如果一行沒有任何軟換行機(jī)會,并且不適合,則會導(dǎo)致文本溢出:
這可能會導(dǎo)致一些惱人的布局問題。在這里,它添加了一個水平滾動條。在其他情況下,它可能會導(dǎo)致文本與其他元素重疊,或滑到圖像/視頻后面。
overflow-wrap
屬性允許我們調(diào)整換行算法,并允許它在找不到軟換行機(jī)會時使用硬換行:
雖熱,這兩種解決方案都不是完美的,但至少硬換行不會破壞布局!
感謝 Sophie Alpert 提出了類似的規(guī)則!她建議將其應(yīng)用于所有元素,這可能是一個好主意,但不是我個人測試過的東西。
您還可以嘗試添加 hyphens
屬性:
p { overflow-wrap: break-word; hyphens: auto; }
hyphens: aut
:自動使用連字符(在支持它們的語言中)表示硬換行。這也使得硬換行更為常見。如果你有非常窄的文本欄,可以使用一下它。在我個人的 CSS 重置樣式中并為包含它,但它值得嘗試!
#root, #__next { isolation: isolate; }
最后一個是可選的。通常只有在使用 React 之類的 JavaScript 框架時才需要它。
正如我們在 滾蛋吧,z-index 中看到的那樣,isolation
屬性允許我們創(chuàng)建新的堆棧上下文,而無需設(shè)置 z-index
。
這是有益的,因?yàn)樗试S我們保證某些高優(yōu)先級元素(模態(tài)、下拉列表、工具提示)在應(yīng)用程序中始終顯示在其他元素之上。沒有奇怪的堆疊背景錯誤,沒有 層出不窮的 z-index。
為了匹配您使用的框架,您需要根據(jù)您的需要來調(diào)整選擇器。我們希望選擇在應(yīng)用程序中呈現(xiàn)的頂級元素。例如,在 create-react-app 使用的是<div id="root">
,因此正確的選擇器是 #root
。
以下是我的 CSS 重置樣式,采用了精簡的、可復(fù)制的、優(yōu)美的格式:
/* Josh's Custom CSS Reset https://www.joshwcomeau.com/css/custom-css-reset/ */ *, *::before, *::after { box-sizing: border-box; } * { margin: 0; } html, body { height: 100%; } body { line-height: 1.5; -webkit-font-smoothing: antialiased; } img, picture, video, canvas, svg { display: block; max-width: 100%; } input, button, textarea, select { font: inherit; } p, h2, h3, h4, h5, h6, h7 { overflow-wrap: break-word; } #root, #__next { isolation: isolate; }
請隨意復(fù)制/粘貼到您自己的項(xiàng)目中!它的發(fā)布沒有任何限制(不過如果你想保留這篇博文的鏈接,我將不勝感激?。?。
我沒有將這個 CSS 重置樣式作為 NPM 包發(fā)布,因?yàn)槲矣X得你應(yīng)該擁有自己的重置樣式。把它帶到你的項(xiàng)目中,隨著時間的推移,當(dāng)你學(xué)習(xí)新事物或發(fā)現(xiàn)新技巧時,可以對它進(jìn)行調(diào)整。如果需要,您可以隨時制作自己的 NPM 包,以便于在項(xiàng)目中重用。
看完上述內(nèi)容,你們對如何深入解析自定義的CSS重置樣式有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。