# CSS 專家密技 - CSS Protips [竹白筆記本](https://chupainotebook.blogspot.com/2019/03/css-css-protips.html),學習筆記,2019/03/21 ###### tags: `CSS 專家密技` `CSS Protips` >[CSS 專家密技 ](https://github.com/AllThingsSmitty/css-protips/blob/master/translations/zh-TW/README.md) [CSS專家密技3 - CSS Protips - 阿莫斯の網頁料理室](https://www.youtube.com/playlist?list=PLqivELodHt3gYOrZe4oVUP4_TNRJunD5P) --- # 1. 使用 CSS Reset CSS Reset 可以幫你在不同的瀏覽器上維持一致的樣式風格。 幾套常見的 CSS Reset: - [Reset CSS](https://meyerweb.com/eric/tools/css/reset/),此為 Eric Meyer 的版本 - [HTML5 Reset Stylesheet](http://html5doctor.com/html-5-reset-stylesheet/),HTML5 Doctor 網站修改自 - Eric A. Meyer 的版本。 - [CSS Reset - YUI Library](https://yuilibrary.com/yui/docs/cssreset/),由 Yahoo UI Library v3 所提供的 CSS Reset 版本。 因為 reset.css 重置了各個瀏覽器的樣式設定,使得有些有用、常用標籤的默認樣式必須要重新設定,因為這個問題,有人開發出了 [Normalize.css](https://necolas.github.io/normalize.css/)。 在 Normalize.css 的官方頁面上點出了他們的目標: - 保留有用的瀏覽器默認設置,而不是將其刪除。 - 為廣泛的 HTML 元素提供一般化的樣式。 - 修正瀏覽器的 Bug 與不一致。 - 透過微妙的改善提高可用性。 - 有詳細的文檔來解釋代碼。(每個樣式都有註解是處理什麼問題。) 最大的特色就是保留原本預設 HTML 標籤的樣式,僅針對不同瀏覽器與各版本間不相容的標籤進行些微調整。 更簡潔的 CSS Reset 方法: ```css *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } ``` --- # 2. 繼承 `box-sizing` 一般使用 `box-sizing` 都是: ```css *, *::before, *::after { box-sizing: border-box; } ``` 但假設今天有一個元件是使用 `box-sizing: content-box;`: ```css .component { box-sizing: content-box; } ``` 元件中的其他子元素也要是 `content-box`,但使用第一種方法設定 `box-sizing` 會影響到。 所以讓 `box-sizing` 屬性自動從 `html` 元素繼承下來 : ```css html { box-sizing: border-box; } *, *::before, *::after { box-sizing: inherit; } ``` 如此一來,你就很容易的在其他外掛或元件裡改變 `box-sizing` 的值。 --- # 3. 使用 `unset` 而不是重置所有屬性 `unset` 從其父級繼承,則將該屬性重新設置為繼承的值,如果沒有繼承父級樣式,則將該屬性重新設置為初始值。 - 如果該屬性是默認繼承屬性,該值等同於 `inherit` - 如果該屬性是非繼承屬性,該值等同於 `initial` 舉個例子,先列舉一些 CSS 中默認繼承父級樣式的屬性: - 部分可繼承樣式:`font-size`, `font-family`, `color`, `text-indent` - 部分不可繼承樣式:`border`, `padding`, `margin`, `width`, `height` `all: unset;` 將元素中所有樣式屬性回復到預設值: ```css button { all: unset; } ``` >[all|MDN](https://developer.mozilla.org/zh-CN/docs/Web/CSS/all) --- # 4. 使用 `:not()` 選擇器來決定表單是否顯示邊框 假設你用以下樣式先替元素新增邊框 ```css /* 新增邊框 */ .nav li { border-right: 1px solid #666; } ``` 然後在最後一個元素去除邊框 ```css /* 去掉邊框 */ .nav li:last-child { border-right: none; } ``` 不過你可以改用 `:not()` 偽類別 (pseudo-class) 來做到完全相同的效果: ```css .nav li:not(:last-child) { border-right: 1px solid #666; } ``` 當然,你也可以用 `.nav li + li`,但是使用 `:not()` 可以使語句更加清晰,更具可讀性。 **CodePen:**[:not 選擇器](https://codepen.io/CHUPAIWANG/pen/drzVYM) <iframe height="265" style="width: 100%;" scrolling="no" title=":not 選擇器" src="//codepen.io/CHUPAIWANG/embed/drzVYM/?height=265&theme-id=0&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/drzVYM/'>:not 選擇器</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> --- # 5. 將 `line-height` 加入到 `body` 元素 你不必為分別為每一個 `<p>`、`<h*>` 元素加入 `line-height` 樣式,相反的,你應該直接新增到 `body` 元素: ```css body { line-height: 1.5; } ``` 所有的文字元素預設就會繼承 `body` 的樣式。 --- # 6. 為表單元素設置 focus 給予使用者回饋,讓使用者可以距焦、確定所在位置。 ```css a:focus, button:focus, input:focus, select:focus, textarea:focus { box-shadow: none; outline: #000 dotted 2px; outline-offset: .05em; } ``` **CodePen:**[Search Box](https://codepen.io/chupai/pen/JeyOJJ) <iframe height="265" style="width: 100%;" scrolling="no" title="Search Box" src="//codepen.io/chupai/embed/JeyOJJ/?height=265&theme-id=0&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/chupai/pen/JeyOJJ/'>Search Box</a> by Chupai@Design (<a href='https://codepen.io/chupai'>@chupai</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> ## focus 在超連結中 考量到 CSS 的優先權,在超連結中要註意擺放順序,由上而下依序為: ```css a:link {} a:visited {} a:focus {} a:hover {} a:active {} ``` --- # 7. 將所有元素設定垂直居中 此處有問題,故跳過。 >[CSS 垂直置中技巧 23 招](https://www.youtube.com/redirect?v=PiczFSV9xGg&redir_token=gMr7j4xI4g56HDaNOenf8-zplQl8MTU1MjM3NTM4MEAxNTUyMjg4OTgw&event=video_description&q=http%3A%2F%2Fcsscoke.com%2F2018%2F08%2F21%2Fcss-vertical-align%2F) --- # 8. 逗號分隔列表 使列表的每項都由逗號分隔: ```css ul > li:not(:last-child)::after { content: ','; } ``` 列表中最後一項不用加逗號,所以可以使用 :not() 偽類別 (pseudo-class)。 --- # 9. 使用負數的 `nth-child` 來選擇元素 >[CSS3 :nth-child(n) 選取器教學](http://tinyurl.com/pr9m6b6) 使用負數的 `nth-child` 可以選擇 1 至 n 個元素。 ```css li { display: none; } /* 選擇第 1 至第 3 個元素並顯示出來 */ li:nth-child(-n+3) { display: block; } ``` 或者使用 `:not()` 選擇器來決定表單是否顯示邊框: ```css /* 選擇除了前 3 個之外的所有項目,並顯示出來 */ li:not(:nth-child(-n + 3)) { display: none; } ``` --- # 10. 使用 SVG 圖示 SVG 在所有解析度下都可以良好縮放,並且支援 IE9 之後的所有瀏覽器。 **注意:** 如果你有一個只用 SVG 圖示的按鈕,只給看的見的人來點選。當 SVG 無法載入的時候,以下樣式可以幫助你維持網頁的可及性(Accessibility): ```css .no-svg .icon-only::after { content: attr(aria-label); } ``` >[attr()|MDN](https://developer.mozilla.org/zh-TW/docs/Web/CSS/attr) --- # 11. 貓頭鷹 選擇器 Lobotomized Owl(貓頭鷹) ```css * + * { margin-top: 1.5em; } ``` 在此範例中,在文件中所有的元素,只要緊接著其他元素,就會套用一個 `margin-top: 1.5em` 樣式。 :::danger 效能不好,不建議使用。 ::: --- # 12. 使用 `max-height` 來建立純 CSS 的捲動軸 你可以透過 `max-height` 與 `overflow-y: hidden` 來實作出 CSS-only 的捲動軸: ```css .slider { max-height: 200px; overflow-y: hidden; width: 300px; } .slider:hover { max-height: 600px; overflow-y: scroll; } ``` 當滑鼠移到 `.slider` 的元素時,元素的內容如果過多,最大高度只會擴展到 `max-height` 的值,而且會自動顯示捲動軸。 **CodePen:**[建立純 CSS 的捲動軸](https://codepen.io/CHUPAIWANG/pen/ZPXYqR?editors=1100) :::warning 此方法有個缺點,因為需要鼠標移過去才會顯示卷軸,使用者會不知道此處可以捲動,所以需要額外增加提示。 ::: --- # 13. 讓表格中每個儲存格維持等寬 表格中要維持每一格都等寬是一件痛苦的是,所以你應該嘗試用 `table-layout: fixed` 來讓所有儲存格維持等寬: ```css .calendar { table-layout: fixed; } ``` **CodePen:**[Equal-Width Table Cells](http://codepen.io/AllThingsSmitty/pen/jALALm) --- # 14. 利用 Flexbox 去除多餘的 Margin 技巧 排版的時候,為了設計出每一欄的間隙(gutters),一般都會用到像是 `nth-`、`first-` 和 `last-child` 的技巧,來去除頭尾多餘的間隙,不如使用 Flexbox 的 `space-between` 屬性: ```css .list { display: flex; justify-content: space-between; } .list .person { flex-basis: 23%; } ``` <iframe height="265" style="width: 100%;" scrolling="no" title="Flex justify-content: space-between" src="//codepen.io/CHUPAIWANG/embed/PLybBQ/?height=265&theme-id=0&default-tab=css,result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/CHUPAIWANG/pen/PLybBQ/'>Flex justify-content: space-between</a> by CHUPAIWANG (<a href='https://codepen.io/CHUPAIWANG'>@CHUPAIWANG</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> # 15. 利用屬性選擇器填滿空白連結的文字內容 當 `<a>` 元素沒有文字內容,但有 `href` 屬性的時候,可以這樣做: ```css a[href^='http']:empty::before { content: attr(href); } ``` [`:empty`](https://developer.mozilla.org/en-US/docs/Web/CSS/:empty) 代表沒有子元素的元素。子元素只可以是元素節點或文本(包括空格)。 **CodePen:**[Use Attribute Selectors with Empty Links](https://codepen.io/CHUPAIWANG/pen/ywRgbN) # 16. 幫沒有類別的連結設定一個預設樣式 幫沒有套用 class 的超連結設定一個預設樣式: ```css a[href]:not([class]) { color: #008000; text-decoration: underline; } ``` 使用者透過後台 CMS 系統插入的超連結通常沒有 `class` 屬性,以上樣式可以針對這些超連結進行設定,且不會影響其它樣式定義。 # 17. 一致的垂直韻律 在元素中使用 通用選擇器 `*`,可以確保一致的垂直韻律 (consistent vertical rhythm): ```css .intro > * { margin-bottom: 1.25rem; } ``` 一致的垂直韻律可以提供視覺美感,並且讓內容更具可讀性。 :::info 沒啥用的技巧 ::: # 18. 等比例的方塊(RWD 相關) 要建立一個固定比例的方塊(Box),你需要的就是將 `padding-top` 或 `padding-bottom` 設定到 `<div>` 元素: ```css .container { height: 0; padding-bottom: 20%; position: relative; } .container div { border: 2px dashed #ddd; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } ``` 在 `padding-bottom` 設定 `20%` 意味著各個 div 方塊的高度等同於 20% 的寬度。無論 Viewport 現在的寬度多少,子元素的 div 將維持其寬高比(100% / 20% = 5:1)。 **CodePen:**[Intrinsic Ratio Boxes](http://codepen.io/AllThingsSmitty/pen/jALZvE) # 19. 為破圖定義樣式 只要一點 CSS 就可以美化所有破圖: ```css img { display: block; font-family: Helvetica, Arial, sans-serif; font-weight: 300; height: auto; line-height: 2; position: relative; text-align: center; width: 100%; } ``` 接著新增一個 偽元素規則(pseudo-elements rules)來顯示使用者訊息,以及這張破圖的 URL 參考: ```css img::before { content: "We're sorry, the image below is broken :("; display: block; margin-bottom: 10px; } img::after { content: '(url: ' attr(src) ')'; display: block; font-size: 12px; } ``` 想學習更多這類樣式技巧,可以參考 [Ire Aderinokun](https://github.com/ireade/) 的 [原始文章](http://bitsofco.de/styling-broken-images/)。 # 20. 用 `rem` 來調整全域大小;用 `em` 來調整區域大小 在根元素設定基礎字體大小後(`html { font-size: 100%; }`), 使用 `em` 設定文字元素的字體大小: ```css h2 { font-size: 2em; } p { font-size: 1em; } ``` 然後設定模組的字體大小為 `rem`: ```css article { font-size: 1.25rem; } aside .module { font-size: 0.9rem; } ``` 現在,每個模組變得獨立,更容易、靈活的樣式便於維護。 >[CSS 中的 EM REM PX 解析與運用|六角學院](https://www.youtube.com/watch?v=sKrVyhaeZqU) # 21. 隱藏沒有靜音並設定自動播放的影片 當你在一個可以自訂樣式的後台環境設定網站樣式時,這是一個不錯的小技巧。畢竟自動撥放影片是蠻惱人的,這個技巧可以幫助你避免影片在沒有靜音的情況下自動撥放。 ```css video[autoplay]:not([muted]) { display: none; } ``` # 22. 使用 `:root` 選擇器來設定彈性的字體大小 在響應式版面(responsive layout)中,字體大小通常需要根據不同的 Viewport(畫面大小)進行調整。你可以根據 `:root` 所定義的 Viewport 高度與寬度來調整字體大小: ```css :root { font-size: calc(1vw + 1vh + 0.5vmin); } ``` 現在你便能使用依 `:root` 字級為基準的 `rem` 單位了。 ```css body { font: 1rem/1.6 sans-serif; } ``` **CodePen:**[Use :root for Flexible Type](http://codepen.io/AllThingsSmitty/pen/XKgOkR) # 23. 為了更好的行動體驗來設定表單元素的 `font-size` 為了避免使用者在行動瀏覽器(iOS Safari, 等等)點擊 `<select>` 的下拉選單時在 HTML 表單元素進行縮放,你可以加上`font-size` 到這些選取器樣式規則: ```css input[type='text'], input[type='number'], select, textarea { font-size: 16px; } ``` # 24. 使用 `pointer-events` 控制鼠標事件 [`pointer-events `](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events) 允許您指定鼠標如何與其觸摸的元素進行交互。要禁用按鈕上的默認指針事件,例如: ```css .button-disabled { opacity: .5; pointer-events: none; } ```