跳至主要内容

[筆記] SASS / SCSS

lighten($color, $amount) // Makes a color lighter.
darken($color, $amount) // Makes a color darker.

目錄

[TOC]

資料型態(Data Types)

SASSScript 支援 8 種資料型態:

  • 數值(number):1.2 , 13, 10px
  • 字串(strings):"foo", 'bar', baz(可以有引號或沒有)
  • 顏色(color):blue, #04a3f9, rgba(255, 0, 0, 0.4)
  • nullsnull
  • lists of value:1.5em 1em 0 2em, Helvetica, Arial, sans-serif
  • maps from one value to another:(key1: value1, key2: value2)
  • function references

Data Types @ SASS Reference

String Interpolation

在 SASS 中可以使用 #{} ,裡面的內容會被 SASS 編譯:

@mixin tooltip($background) {
background-image: url(#{$background});
}

Lists

Lists 是在 SASS 中用來表徵 CSS 樣式的方式,像是 margin: 10px 15px 0 0font-family: Helvetica, Arial, sans-serifLists 就是一系列的值,並且可以透過空格或逗號加以分隔,裡面的每個值稱作 item,實際上任何單一的值也是 lists,他就是只有一個 item 的 lists。

lists 本身被沒有太多作用,在透過 SASSScript list functions 則讓 lists 變得非常好用。

除了包含單一值之外,lists 也可以包含其他 lists,舉例來說,1px 2px, 5px 6px 是一個包了兩個 lists 的 lists,其中第一個 item 是 list 1px 2px,另一個 item 則是 list 5px 6px。如果裡面的 lists 和外面的 lists 有相同的分隔符號(即,空格或逗號),那麼則需要使用括號來定義清楚,舉例來說,(1px 2px) (5px 6px) 和前面一樣,都是包有兩個 lists 的 lists。

當 lists 被轉換成 CSS 時,SASS 不會添加任何括號,因為 CSS 並不了解他們,也就是說 (1px 2px) (5px 6px)1px 2px 5px 6px 在它們轉換成 CSS 之後,都是一樣的,但在轉換之前他們是不同的。

Lists 也可以不包含任何 items,這樣的 lists 可以用 () 表示(這也同樣是空的 map),他們沒辦法被直接轉換成 CSS。

Maps

Maps 在 SASS 中用來表徵 key 和 values 的關係,和 lists 不同,maps 總是必須要透過括號包著,並且用逗號分隔

$map: (
key1: value1,
key2: value2,
key3: value3,
);

和 Lists 類似,maps 經常透過 SASSScript functions 來使用:

  • map-get 可以找出在 map 裡面的 value。
  • map-merge :可以添加值到 map 當中。
  • @each directive :可以用來為 map 中的每一個 key/value pair 添加樣式。

Maps 也可以用來任和 lists 可以用的地方,當對 maps 使用 lists 的函式時,map 會被視為 a list of pairs,舉例來說,(key1: value, key2: value2),將會被視為 key1 value1, key2 value2 的 list。

但 Lists 並不能被當作 maps 使用,除了空的 lists () 之外,() 可以用來同時表示沒有 item 的 lists 或是沒有 key/value pairs 的 Maps。

Maps 並沒有辦法轉換成 CSS,透過 inspect($value) 可以用來檢視某個 maps 的內容,方便 debug 使用

建立變數(variable)

keywords: !global, !default

在 SASS 中可以使用關鍵字 $ 來建立變數。在 SASS 所定義的變數中,底線(_)和連結線(-)的使用可以互換,舉例來說,雖然下面定義的變數名稱是 $bg_black,但是一樣可以透過 $bg-black 提取:

$bg_black: #333;

.block1 {
background-color: $bg_black;
}

.block2 {
background-color: $bg-black;
}

全域變數(!global)

這些變數只有在它所定義的階層中有效,因此如果想定義的是全域變數,可以使用 $ 將變數定義在最外層,或者是用 !global 標籤來定義全域變數:

$black: '#CCC';

body {
background-color: $black;
$width: 100% !global; // 這個 $width 會變成全域變數
width: $width;
}

預設變數(!default)

對某一個變數後方加上 !default 後,如果這個變數有被賦值過,則使用該值,如果沒有被賦值過,則使用預設值:

// SCSS
$gray: #eaeaea;

$black: #333 !default; // $black 沒被賦值過,所以會套用預設值
$gray: #cacaca !default; // $gray 被賦值過,所以不會套用預設值

.block {
background-color: $black;
color: $gray;
}

編譯後:

/* CSS */
.block {
background-color: #333;
color: #eaeaea;
}

建立函式(function directive)

$grid-width: 40px;
$gutter-width: 10px;

@function grid-width($n) {
@return $n * $grid-width + ($n - 1) * $gutter-width;
}

#sidebar {
width: grid-width(5);
}

Function Directive @ SASS Documentation

Partials

keywords: @import

在 SASS 中會以底線開頭的方式來為 partials 檔案命名,例如 _partial.scss,SASS 會知道底線開頭的檔案是 partial,因此不會產生一支獨立的 CSS 檔。在主要的 SASS 檔中則可以透過 @import 來載入 partial 檔。

若想載入名為 _partial.scss 的 partial 檔,只需在主要的檔案使用 @import ,同時 partial 檔的底線(_)和副檔名(.scss)可以不用寫出來:

// main.scss
@import 'partial';

mixins

keywords: @mixin, @include, @content

使用關鍵字 @mixin 來建立函式;使用關鍵字 @include 來載入函式。

不帶參數的 mixin

/**
* 建立基本的 mixin
**/
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}

.page-title {
@include large-text;
padding: 4px;
margin-top: 10px;
}

帶有參數的 mixin

/**
* 建立帶參數和預設值的 mixin
**/

@mixin sexy-border($color, $width: 1px) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
p {
@include sexy-border(blue);
}
h1 {
@include sexy-border(blue, 2px);
}

@content

在使用 @mixin 時搭配 @content 可以把 @include 中的內容載入,這很適合用在 RWD 的 media-query 使用:

// SCSS
@mixin apply-to-ipad {
@media screen and (max-width: 768px) {
@content;
}
}
@mixin apply-to-iphone {
@media screen and (max-width: 375px) {
@content;
}
}

@include apply-to-iphone {
#logo {
background-image: url(/logo.gif);
}
}

@include apply-to-ipad {
#logo {
background-image: url(/logo2x.gif);
}
}

編譯後:

@media screen and (max-width: 375px) {
#logo {
background-image: url(/logo.gif);
}
}
@media screen and (max-width: 768px) {
#logo {
background-image: url(/logo2x.gif);
}
}

Extend/Inheritance

keywords: @extend, placeholder class

extend placeholder class(%)

// scss
%center-center {
display: flex;
align-items: center;
justify-content: center;
}

.icon {
@extend %center-center;
color: white;
}

.banner {
@extend %center-center;
width: 100%;
}

編譯出來的結果會是這樣:

  • %center-center 的內容並不會被編譯出來,因此在程式碼中並不能直接使用 .center-center 這個樣式
.banner,
.icon {
display: flex;
align-items: center;
justify-content: center;
}

.icon {
color: white;
}

.banner {
width: 100%;
}

extend 另一個 class

除了使用 placeholder class 之外,也透過 @extend 直接繼承另一個 class 內的樣式:

// scss
.message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}

.success {
@extend .message;
border-color: green;
}

.error {
@extend .message;
border-color: red;
}

編譯後的 CSS 會是這樣:

  • 在程式碼中可以直接使用 .message 這個 class:
/* CSS */
.message,
.success,
.error {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}

.success {
border-color: green;
}

.error {
border-color: red;
}

嵌套(nested)

keywords: &

使用關鍵字 & 來表示父層元素:

// SCSS
// 意思是 .nav:hover{...}
.nav {
&:hover {
color: #ccc;
}
}

Nested Properties

在 CSS 中許多的屬性都帶有相同的 "namespaces" ,例如 font-family, font-size, font-weight;在 SASS 中則提供了可簡便的寫法,你只需要寫一次 namespace 即可:

// SCSS
.foo {
font: {
family: fantasy;
size: 30em;
weight: bold;
}
}

SASS 會自動編譯成:

/* CSS */
.foo {
font-family: fantasy;
font-size: 30em;
font-weight: bold;
}

註解(Comments)

keywords: /*...*/ , //...

在 SASS 中提供了兩種註解的方式,一種是多行註解 /* ... */,另一種是單行註解 //... ,在編譯成 CSS 檔後,多行註解會被保留但單行註解會被移除

Directives 和 Functions

常用

darken(#ccc,12);
lighten(#ccc ,12);

adjust-hue(#F05941, 20%);

SASS::Script::Functions @ SASS Documentation

@root

透過 @root 可以把原本被牽套在內的樣式拉到最外層:

@root @ Sass Lang

@mixin apply-to-webp($child) {
@at-root html.webp #{$child} {
@content;
}
}

@mixin apply-to-no-webp($child) {
@at-root html.no-webp #{$child} {
@content;
}
}

.block-reviews {
// 透過 & 可以選到當前的 CSS 選擇器
@include apply-to-webp(&) {
background-image: url('~images/background/coffee_shop.webp');
}

// 透過 & 可以選到當前的 CSS 選擇器
@include apply-to-no-webp(&) {
background-image: url('~images/background/coffee_shop.png');
}
}

// 編譯出來後
html.webp .block-reviews {
background-image: url('~images/background/coffee_shop.webp');
}
html.no-webp .block-reviews {
background-image: url('~images/background/coffee_shop.png');
}

@each

keywords: @each $var in <list or map>, @each $var1, $var2, ... in <list>
// SCSS

// with one variable in list
@each $animal in puma, sea-slug, egret, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}

// with multiple variables in list
@each $animal, $color, $cursor in (puma, black, default), (sea-slug, blue, pointer),
(egret, white, move)
{
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
// SCSS

// with multiple variables in map
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$header} {
font-size: $size;
}
}

map_merge

透過 map_merge($map1, $map2) 可以用來合併兩個 map:

#map_merge($map1, $map2)

範例:

map-merge(("foo": 1), ("bar": 2)) => ("foo": 1, "bar": 2)
map-merge(("foo": 1, "bar": 2), ("bar": 3)) => ("foo": 1, "bar": 3)

map_get

透過 map_get 可以取得 map 中某個 key 相對應的 value:

map-get($map, $key) // Returns the value in a map associated with a given key.
map-get(("foo": 1, "bar": 2), "foo") => 1
map-get(("foo": 1, "bar": 2), "bar") => 2

參考資料