用 Sass 玩出自己的 Memo Style

你有看過深色的便條紙嗎?

坊間好像比較少看到深色系的便條紙耶,雖然還是有,但大多數的便條紙都是以提醒效果比較好的、較醒目的亮色、淺色系為主,又或者是因為藍、黑、紅色的原子筆(文字顏色預設:黑)比較通用的緣故?總之,便條紙的顏色我要自己決定!! (任性)

既然要自己決定背景色,那麼如何自動搭配較適合的文字顏色便是關鍵,試想如果選擇黑底又配上預設的黑字,大概要用全選反白或是開 DevTools 才能一探究竟了,如果要手動更改文字顏色又覺得好麻煩…本篇文章主要透過便條紙的自動配色,來介紹 SASS 的一些應用。

Photo by AbsolutVision on Unsplash

首先,刻出一個基本的便條紙樣式

以下就背景色、文字、button 底色的搭配設定相關的部分來說明:

// HTML
<div class="memo memo--bg-black">
  <header class="header">
    <a class="btn-change-bg-color btn"><i class="fas fa-palette"></i></a>
    <a class="btn-close btn">&nbsp;</a>
  </header>
  <div class="content">
  </div>
</div>
// CSS
$primary-color: #000;
$text-color: #fff;

.memo--bg-black {
  color: $text-color;
  background-color: $primary-color;

  .header {
    border-bottom: 1px solid $text-color;

    .btn-close {
      background-color: lighten($primary-color, 20%);

      &:before, &:after {
        background-color: $text-color;
      }

      &:hover {
        cursor: pointer;
        background-color: $text-color;

        &:before, &:after {
          background-color: lighten($primary-color, 20%);
        }
      }
    }

    .btn-change-bg-color {
      background-color: lighten($primary-color, 20%);

      &:hover {
        color: lighten($primary-color, 20%);
        background-color: $text-color;
      }
    }
  }

  .content {
    @include textarea($primary-color, $text-color);
  }
}

目前看起來的 memo 會是這樣:

sample

實作過程

接下來,就是我們要透過選擇背景顏色,自動產生適合文字顏色的實作過程:

Step.1 - 決定基本文字顏色

  1. 用來搭配深色背景的白色 #fff
  2. 用來搭配亮色背景的深灰色 #333

Step.2 - @function、@if、@else

  1. 定義一個 @function,將背景色當做參數傳入
  2. @function 裡,以 CSS 的 lightness 數值為基準,再用 @if@else 去判斷,@return 回傳符合條件的文字色碼
@function set-text-color($bg-color) {
  @if(lightness($bg-color) > 50) {
    @return #333;
  } @else {
    @return #fff;
  }
}

//使用方式:
background-color: $primary-color;
color: set-text-color($primary-color);


Step.3 - @mixin

  1. 重複的動作一次都會做 2 個:設定背景色、設定文字顏色
  2. 使用 @mixin 將他們包在一起吧
@mixin set-background($bg-color) {
  background-color: $bg-color;
  color: set-text-color($bg-color);
}

//使用方式:
@include set-background($primary-color);


Step.4 - 調整 button 的底色

  1. button 底色設定為 $primary-color 再提高亮度 20%
  2. 如果 $primary-color 本身亮度就很高的話,就將 button 底色改為降低亮度 10%
  3. .btn-close 以及 .btn-change-bg-color 關於顏色設定的部分歸納為同一個 class .btn,在 HTML 的部分要記得補上這個 class 哦
@function set-btn-bg($bg-color) {
  @if (lightness($bg-color) > 50) {
    @return darken($bg-color, 10%);
  } @else {
    @return lighten($bg-color, 20%);
  }
}

@mixin set-button($bg-color) {
  background-color: set-btn-bg($bg-color);

  &:before, &:after {
    background-color: set-text-color($bg-color);
  }

  &:hover {
    background-color: set-text-color($bg-color);

    &:before, &:after {
      background-color: set-btn-bg($bg-color);
    }
  }
}

其他區塊的背景跟文字設定,跟上述的整理方式差不多,就不再贅述。
到這邊為止,我的 .memo--bg-black 的內容修改過後如下:

.memo--bg-black {
  @include set-background($primary-color);

  .header {
    .btn {
      @include set-button($primary-color);
    }
  }

  .content {
    @include textarea($primary-color);
  }
}

其他透過 @function@mixin 設定跟顏色有關的部分:

@function set-text-color($bg-color) {
  @if(lightness($bg-color) > 50) {
    @return #333;
  } @else {
    @return #fff;
  }
}

@function set-btn-bg($bg-color) {
  @if (lightness($bg-color) > 50) {
    @return darken($bg-color, 10%);
  } @else {
    @return lighten($bg-color, 20%);
  }
}

@mixin set-background($bg-color) {
  background-color: $bg-color;
  color: set-text-color($bg-color);
}

@mixin set-button($bg-color) {
  background-color: set-btn-bg($bg-color);

  &:before, &:after {
    background-color: set-text-color($bg-color);
  }

  &:hover {
    background-color: set-text-color($bg-color);
    color: $bg-color;

    &:before, &:after {
      background-color: $bg-color;
    }
  }
}

@mixin textarea($primary-color) {
  @include set-background($primary-color);
}


Step.5 - @each

到這邊,基本上只要把 $primary-color 指定為其他顏色,就可以看到我們要的效果:只要改變底色,其他地方顏色配置就會自動完成!
以上都是以黑色背景的 .memo--bg-black 做範例,接下來的步驟就是要產生更多的 class:

  1. 將自己喜歡的顏色個別用變數去指定
  2. 定義一個 map,以 name: value 的格式指定顏色名稱及相對應的變數
  3. 運用 @each,將顏色變數們的名字透過處理變成 class name,並且將對應的顏色變數傳入 @function
// 1. 用變數指向顏色色碼
$color-white: #fff;
$color-red: #F50057;
$color-cyan: #18FFFF;
$color-yellow: #FFEE58;
$color-green: #69F0AE;
$color-purple: #6A1B9A;
$color-black: #000;
$color-gray: #ccc;

// 2. 定義一個 map,以 name: value 的格式指定顏色名稱及相對應的變數
$theme: (
  white: $color-white,
  red: $color-red,
  cyan: $color-cyan,
  yellow: $color-yellow,
  green: $color-green,
  purple: $color-purple,
  black: $color-black,
  gray: $color-gray
);

// 3. 使用 @each 遍歷 map 裡的所有元素,將 $theme 的 name 及 value 使用在 class 的命名以及函數套用
@each $color, $value in $theme {
  .memo--bg-#{$color} {
    @include set-background($value);

    .header {
      .btn {
        @include set-button($value);
      }
    }

    .content {
      @include textarea($value);
    }
  }
}


Step.6 - 套用

這時候就可以把 .memo--bg-black 換成其他的 class 了,看看轉譯後的 CSS,多了 .memo--bg-purple.memo--bg-cyan …等等的 class 可以套用了呢,之後要增加這個 memo 的顏色設定 class 的話,基本上只需要在 map 裡增加 name 跟 value ,像是 pink: #ffc0cb 就可以囉,但如果先用變數指定色碼的話會更有利於管理哦

最後,把剛才設定的 memo 都列出來吧:

total