--- title: '2020/02/08 Sass/Scss 教學筆記: 有效率的切版(上) 變數、Mixin與Extend來管理flexbox' disqus: hackmd --- 2020/02/08 Sass/Scss 教學筆記: 有效率的切版(上) 變數、Mixin與Extend來管理flexbox === 綱要 [TOC] 多利用線上工具幫助你檢查語法:Sass Meister --- https://www.sassmeister.com/ ![](https://i.imgur.com/mJGkBkK.png) **Sass Meister** 是個Sass/Scss的線上Playground,你可以將Sass語法寫在左邊,網頁會在你輸入完畢後自動在右邊產生編譯結果,Option中可以選擇編譯器要使用哪個版本,這邊我們演示的是dart-sass來幫助Debug。 課堂上日後會遇到更多一時之間無法釐清的編譯問題,所以老師建議每次上課都打開這個頁面來幫助你整理Code。 --- flexbox的應用 --- 自從`flexbox`出現後就徹底改變了以往動不動就得使用`position`和`float`排版的習慣,廣受推崇的理由便是它具有十足的彈性讓排版更容易上手。 ```css= /* 寫下你的第一行flex */ .container { display: flex; flex-direction: row; /* 預設值是row,代表橫向排列,column則是垂直 */ } ``` 此外,我們還可以透過`align-items`和`justify-content`來指定排列的規則,下方老師做了一個簡易速查表,可以自由替換。 實際上撰寫專案時,我們還會利用`justify-content: space-between`等來均分子元素的間隔距離等操作,留待後面的專案練習再來實作一次吧,這次上課我們只稍微帶過就好。 **flexbox 速查表:** ![](https://i.imgur.com/0LXd4HZ.jpg) --- mixin以及extend的應用 --- **抽象化的定義** 所謂的抽象化就是不在函式中帶值,以純JS為例也就是像這樣: ```javascript= function setValue(val) { return val + 100 } console.log(setValue(1)) // 執行結果就會是 1 + 100 = 101 ``` 雖然定義了一個函式,但我僅在執行階段才賦予值給它,取得最後運算的結果。 這個概念在撰寫Sass的時候佔有相當重要的位置,務必牢記。 **@mixin** 一組`@mixin`對應一個`@include`,事先將命名好的`@mixin`定義屬性後並抽象化,再由`@include`調用。 **@extend** `@extend`可以直接將寫好的CSS樣式直接沿用,省去要另外再寫的麻煩,我們看一下經過`@extend`處理後的差別是什麼: ```sass= /* sass */ .container { width: 100%; height: auto; } .new-container { @extend .container; } ``` ```css= /* 編譯後的CSS */ .container, .new-container { width: 100%; height: auto; } ``` 你會看見`.new-container`和原先的`.container`是一起被定義樣式的,實際上的用途便是減少你寫過多重複樣式。 **兩者的整合示例** 前面我們用很簡易的方式定義了容器的flex設定,現在來看看怎樣讓程式碼變得更有效率,使你的容器具有更多擴充的彈性: ```sass= .container { width: 100%; height: auto; } @mixin flexBox($direction) { display: flex; flex-direction: $direction; } @mixin flexAlign($alignItems, $justifyContent) { align-items: $alignItems; justify-content: $justifyContent; } .new-container { @include flexBox(column); @include flexAlign(flex-start, flex-start); @extend .container; } ``` ```css= /* 編譯後的CSS */ .container, .new-container { width: 100%; height: auto; } .new-container { display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-start; } ``` 當你需要的共通屬性越多,你也越能感受的到這樣做帶來的好處,因為只需要寫一次就可以沿用到不同的作用區上幫助你管理共通樣式,現在開始你也可以矯正以往的壞習慣,讓自己避免寫一堆垃圾Code,才不會使得前端工程師同事們對你拉警報。 --- 善用data-attribute增加撰寫樣式的彈性 --- 你一定在某些網頁的原始碼上看過這樣的html寫法: ```htmlmixed= <div class="tab__container" data-panel-count="1">...</div> ``` 而且你還試圖去Google了程式碼中的`data-panel-count`卻發現根本找不到任何解答對吧?正常,因為「data-」之後那串字都是我們工程師自己命名的你當然找不到! `data-attribute`原意是HTML5中提供給開發人員做選擇器之類的用途,不僅是Javascript可以任意調用,CSS也一樣可以: ```css= .container[data-width="10rem"] { width: 10rem; } .container[data-inset="0.5rem"] { box-sizing: border-box; padding: 0.5rem; } ``` 因應這個彈性,我們就能建立一個當網頁元素需要微調時,能不修改原本樣式設定就能符合要求的共用模組,並且覆蓋原有的設置,這樣就可以避免為了迎合修改某一兩個參數而必須要犧牲掉你原本計畫好的共用樣式內容,也是我們這套課程比較推崇的方式。 ```sass= /* 這邊提前先偷跑一個日後才要講的for迴圈 */ @for $i form 0 through 20 { /* #{} 的字符代表連接變數使用,{}中可以有運算式 */ [data-inset="#{$i * 0.1}rem"] { padding: #{$i * 0.1}rem; } } ``` ```css= /* 編譯結果的CSS */ [data-inset="0rem"] { padding: 0rem; } [data-inset="0.1rem"] { padding: 0.1rem; } [data-inset="0.2rem"] { padding: 0.2rem; } [data-inset="0.3rem"] { padding: 0.3rem; } ... ... ... ``` --- 你不應該把時間花在命名容器上,那是下等人做的事情 --- 主容器要叫`.main-container`,側邊欄要叫`.side-bar`,手機隱藏了側邊欄後還要顯示底部預先用media query藏好的`.tab-bar`...設計師真的好忙。 我們重新思考一下容器的定義,其實你不用這麼累! 前面`flexbox`就有提到排版核心概念的演進,以及類似共用組件的建構,假如你使用過Bootstrap之類的工具來製作網頁版型,那你應該很快就能理解命名太多容器,這麼做帶來的後續維護成本有多高。 前期什麼都是空白的,建立時都能因為設計師腦洞大開很迅速的切完一個網站,可是當你容器越來越多,命名也跟著越來越多,最後你連自己都不知道哪個容器是什麼特性了不是嗎? 所以老師建議大家使用組件化思考去解決這個情形,現在我們試著用最簡單的方式來處理一個**橫向排列,且垂直置中**的外觀: [CodePen範例](https://codepen.io/fortes-huang/pen/OJVyVxw) ![](https://i.imgur.com/tO2vWXL.png) ```htmlmixed= <div class="row horizontal v_center wrap"> <span>1</span> <span>2</span> <span>3</span> </div> ``` ```sass= /* 橫向排列,且垂直置中的外觀 */ @mixin flexBox($direction) { display: flex; flex-direction: $direction; } @mixin flexAlign($alignItems, $justifyContent) { align-items: $alignItems; justify-content: $justifyContent; } @mixin boxSizing { box-sizing: border-box; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; } .row { @include boxSizing; position: relative; width: 100%; margin: 0; /* &符號是sass的非變數連接字符,這裡的&.any就是 .row.any的意思 */ &.horizontal { @include flexBox(row); &.v_center { @include flexAlign(center, flex-start); } } /* wrap 可以確保子元素在寬度不夠時自動換行喔 */ &.wrap { flex-wrap: wrap; } } [data-border="all"] { border: 1px solid #000; } @for $i from 0 through 100 { [data-width='#{$i + "%"}'] { width: #{$i + "%"}; } } @for $i from 1 through 100 { [data-height="#{$i}vh"] { height: #{$i}vh; } } span { @include flexBox(row); @include flexAlign(center, center); width: 30px; height: 30px; background-color: #333; margin: 0.5rem; color: #fff; } ``` 本日後記 --- 以往我們很習慣的想到什麼就寫什麼,但實際上在多人開發環境當中我們並不能總是按自己的想法做事情,如果你想轉職前端,或者想改善設計師與工程師之間的隔閡,那最好從這堂課開始就去Review一下以往的Code,說不定你會有更多想法讓自己免於被Shit Code壓垮。 --- ###### tags: `Scss` `flexbox` `data-attribute`