태그 보관물: CSS

Sass에서 다크모드 적용하기

점점 다크모드를 적용하는 사이트들이 늘어나고 있는데, 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%;
}

크롬에서 opacity transition 사용할 때 레이어가 사라지는 문제

지금 진행하고 있는 프로젝트에서, 화면 하단에 고정된 레이어를 만들고, 경우에 따라 화면 아래로 사라졌다 나타나는 효과를 적용하였습니다.

1
2
3
.fixed_button_wrap{position:fixed;left:0;bottom:0;width:100%;height:45px;opacity:1;
    transition:bottom 0.3s, opacity 0.3s;}
.fixed_button_wrap.hide{pointer-events:none;bottom:-50px;opacity:0;}

테스트한 단말과 브라우저들에서는 모두 정상적으로 표시되었으나, 일부 안드로이드(크롬)에서 한 번 사라진 레이어가 다시 나타나지 않는 문제가 발견되었습니다. 디버깅 해보면 좌표와 투명도는 모두 정상으로 나타나지만, 화면에는 보이지 않더군요.
해결책은 -webkit-backface-visibility:hidden;를 추가해 주어야 합니다.

1
2
3
.fixed_button_wrap{position:fixed;left:0;bottom:0;width:100%;height:45px;opacity:1;
    transition:bottom 0.3s, opacity 0.3s;-webkit-backface-visibility:hidden;}
.fixed_button_wrap.hide{pointer-events:none;bottom:-50px;opacity:0;}

flex를 사용한 탭 만들기 2

flex를 사용한 탭 만들기에서 간단한 탭 만드는 방법을 알아봤습니다. 그런데 스마트폰에서 볼때는 의도한 데로 표시되지 않는 것을 볼 수 있습니다. 이는 모바일 브라우저에서 인식하는 스타일이 다르기 때문으로, 다음과 같이 -webkit- 접두어를 추가해 주면 됩니다.

1
2
3
4
5
6
7
8
.container{
    display: -webkit-flex;/* for mobile */
    display: flex;
}
.container .child{
    -webkit-flex:auto;/* for mobile */
    flex:auto;
}

이제 스마트폰에서도 대부분의 경우에는 원하는 결과를 얻을 수 있습니다. 그러나 우리의 기대를 저버리지 않는 갤레기 일부 갤럭시 시리즈에서는 제대로 동작하지 않습니다. 이런 일부 스마트폰을 위해서는 다음과 같이 두 줄의 코드를 더 추가해야 합니다.

1
2
3
4
5
6
7
8
9
10
.container{
    display:-webkit-box;/* for galaxy */
    display: -webkit-flex;/* for mobile */
    display: flex;
}
.container .child{
    -webkit-flex:auto;/* for mobile */
    flex:auto;
    width:33.3%;/* for galaxy */
}

여기서 병맛인건, width값은 탭의 갯수에 따라서 1/n 값으로 적용해야 한다는 점입니다. 예를 들어 2개이면 50%, 4개이면 25% 처럼 말이죠.

그래서 대안으로 자바스크립트를 사용해서 리스트의 갯수에 따라서 width 값을 입력해 주는 스크립트를 사용할 수 있습니다.

1
2
3
4
$(function(){
    var lis = $("ul.flex_container > li");
    lis.width((100 / lis.length) + "%");
});

이제 모바일에서도 원하는 결과를 얻을 수 있습니다.

  • 111
  • 222
  • 333

flex를 사용한 탭 만들기

폭이 가변으로 조종되는 메뉴나 탭을 만들 때 flex를 사용해면 쉽게 처리가 가능합니다.
탭을 포함하는 콘테이너에 display:flex를 적용하고, 콘테이너에 들어가는 요소는 flex:auto를 주면… 끝!!! HTML과 CSS 코드는 다음과 같습니다.
(box-shadow는 영역을 눈으로 확인하기 위해 사용하였고, 실제 코드상 필요없는 부분입니다.)

1
2
.container{display:flex;}
.container .child{flex:auto;box-shadow:0 0 1px 1px #69f;}
1
2
3
4
<div class="container">
    <div class="child">111</div>
    <div class="child">222</div>
</div>

그러면 다음과 같은 결과를 얻을 수 있죠.

111
222

.
flex를 사용한 탭 만들기 더보기

JavaScript와 SVG를 사용해서 아크(Arc) 그리기

사각형이나 라운드 사각형, 원 같은 경우는 레이어와 CSS로 얼마든지 표현할 수 있지만, 좀 더 복잡한 도형의 경우에는 CSS로는 표현하기가 어렵습니다. 그래서 SVG를 사용하는 방법을 찾던 중, 아크를 그리는데 어려움이 있어서 샘플로 만들어 봤습니다.

우선 데모를 보시죠.

Path 객체를 사용해서 원하는 모양의 아크를 만들려니 계산식이 복잡해 지더군요. 그래서 중심좌표, 반지름 및 각도를 가지고 아크를 그릴 수 있도록 공식을 짜 봤습니다.
시작점의 위치는 12시 방향으로 고정해서 잡고, 끝점의 좌표를 계산하여 시계 반대방향으로 아크를 그리도록 했습니다. 시계방향으로 그리거나, 시작점과 끝점을 제어하도록 하는 부분은 위 샘플을 응용하면 될 것 같네요.

물론 쉽게 사용할 수 있는 공개된 소스들도 많이 있지만, 개념을 이해하는 차원에서…