점점 다크모드를 적용하는 사이트들이 늘어나고 있는데, Sass를 사용하여 다크모드를 쉽게 적용할 수 있게 코드를 만들어 봤습니다.
우선 일반 컬러 테마와 다크모드 테마를 $light-theme와 $dark-theme 맵에 각각 선언합니다. (4-13줄)
그리고 위의 맵을 사용해서 CSS에서 var()를 사용하기 위한 변수를 선언하고, 미디어쿼리도 적용해 줍니다. (15-25줄)
그러면 CSS의 1-13줄과 같이 변수가 생성됩니다.
이제 본격적으로 믹스인을 생성합니다. (28-41줄)
기본적으로 color-theme(key: value)의 형태로 한 개 이상의 키:밸류 쌍으로 된 속성을 전달할 수 있습니다. 그러나 border나 background 등과 같이 색상 이외에 다른 속성도 같이 설정할 필요가 있는 경우에 color, prefix, suffix의 속성을 가진 맵을 사용할 수 있습니다.
43-53줄과 같이 믹스인을 사용하면 CSS의 14-29줄에 해당하는 코드를 생성합니다.
같은 속성이 두 개씩 만들어 지는 것은 CSS의 변수나 미디어쿼리를 지원하지 않는 구형 브라우저에서는 첫 번째 속성의 컬러를 사용하고, 지원하는 브라우저는 변수와 미디어쿼리가 적용되도록 하기 위해서 입니다.
IE와 같은 구형 브라우저를 지원할 필요가 없다면 31, 37줄의 코드는 삭제하면 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | @use "sass:map"; @use "sass:meta"; $light-theme: ( bgc: #fff, txt: #333, brd: #ff6 ); $dark-theme: ( bgc: #333, txt: #eee, brd: #339 ); :root{ @each $k, $v in $light-theme{ #{"--" + $k}: #{$v}; } } @media (prefers-color-scheme: dark){ :root{ @each $k, $v in $dark-theme{ #{"--" + $k}: #{$v}; } } } @mixin color-theme($args...){ @each $k, $v in meta.keywords($args){ @if(meta.type-of($v) == "string"){ #{$k}: map.get($light-theme, $v); #{$k}: #{"var(--" + $v + ")"}; }@else if(meta.type-of($v) == "map"){ $c: map.get($v, color); $p: map.get($v, prefix); $s: map.get($v, suffix); #{$k}: $p map.get($light-theme, $c) $s; #{$k}: $p #{"var(--" + $c + ")"} $s; } } } html, body{ @include color-theme($color: txt, $background-color: bgc); } .border{ @include color-theme($border: (prefix: 1px solid, color: brd)); } .background{ @include color-theme($background: (color: bgc, suffix: url(bg.jpg) no-repeat 50% 50%)); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | :root { --bgc:#fff; --txt:#333; --brd:#ff6; } @media (prefers-color-scheme: dark) { :root { --bgc:#333; --txt:#eee; --brd:#339; } } html, body { color: #333; color: var(--txt); background-color: #fff; background-color: var(--bgc); } .border { border: 1px solid #ff6; border: 1px solid var(--brd); } .background { background: #fff url(bg.jpg) no-repeat 50% 50%; background: var(--bgc) url(bg.jpg) no-repeat 50% 50%; } |