Luminon Itsuka.

a Luminon Canoness blog.

Space of moments.

ARTICLES/AT WORK

Twitter BIO 페이지 작업기

Luminon Canoness 2020. 5. 3. 20:00

Twitter의 프로필 화면

머리말

Twitter(트위터)의 프로필 화면을 보면 BIO(자기소개) 섹션이 굉장히 작고 눈에 띄지 않습니다. 물론 이곳을 잘 활용하시는 분들도 많지만, 가시성 있게 메시지를 전달하기가 쉽지 않죠. 그래서인지 화려하게 꾸민 자기소개 트윗을 메인 트윗으로 올리거나, 따로 웹페이지를 만들어 보여주는 등의 별도의 방법으로 BIO를 쓰시는 분들을 어렵지 않게 찾아볼 수 있었습니다.

 

저 또한.. 저를 처음 보시는 분들을 위해 제가 어떠한 사람이고, Twitter에서는 어떻게 살고 있는지(다른 말로.. 어떻게 인생을 낭비하고 있는지..) 알려드리기 위해 메인 트윗도 쓰고 제 자기소개 페이지를 만들어 한 번씩 볼 수 있도록 유도하고 있습니다. 서론이 길었는데, 여하튼 이번에는 바로 이 자기소개 페이지를 새로 작업했었고 오늘은 그것에 대한 작업기를 이야기해보고자 합니다.

 

암 그렇구 말구

물론 이번에 처음 만드는 것도 아니고 기존에도 몇 번씩 만들고 고쳐가며 썼지만, 이번 연휴를 맞이하여 미루고 미루던 JavaScript(자바스크립트) 공부를 다시 해보고 싶었기도 했고, 좀 더 디자인적으로 신경 쓴 웹페이지를 만들어보고 싶어  코드를 싹 지우고 날 잡아 한번 다시 웹페이지를 작성해보았습니다. 어차피 글과 사진 몇 장으로 이루어진 간단한 페이지기 때문에 이런 것들을 넣어서 실험해보기 안성맞춤이니까요! 

 


어떤 기능을 넣어볼까?

첫 삽을 뜨기 앞서, 어떤 기능을 넣어볼지 고민을 좀 해봤습니다. 하고싶은 것들을 다 넣고 싶었지만 기능이 많으면 막상 할 때 어려워서 흥미가 떨어질 것 같기도 했고, 섞어 넣으면 사용성이 떨어질 것 같기도 해서 말이지요. (ㅋㅋ) 한 3~4개 정도로 추려봤습니다.

 

 

Material Design에서 말하는 Dark Mode (Dark Theme)

Dark Mode

Dark Mode(다크 모드)는 요즘 핫한 기능중 하나입니다. 서비스 전반의 색상을 어둡게 하여 깜깜한 곳에서 화면을 볼 때 가는 눈의 피로를 덜어주고, Light Mode(라이트 모드)보다 소폭 좋은 가독성을 보여줍니다. 이를 활용해 색맹이신 분이나 밝기, 색상 등에 예민한 분들에게 향상된 접근성을 제공해주기도 하죠. 이미 회사에서 이 Dark Mode를 서비스에 올려보기도 했었어서 상당히 익숙한 작업이 될 것 같기도 했고, 디자인부터 마크업까지 "완전히 내가 할 때는 어떤 느낌일까~" 해서 넣어보기로 했습니다.

 

곤니치와~ 와타시와 루미논 카노네스데스~

다국어 기능

최근 일본어 연습 계정을 하나 만들어서 공부할 때 써먹고 있습니다. 그래서 혹시 모를 조우를 위해(ㅋㅋ) BIO 페이지에 한국어 버전의 글과 일본어 버전의 글을 토글해서 볼 수 있는 기능을 넣고 싶었습니다.

 

반응형

원래부터 꼭 해오고 있는 기능이기에 이번에도 역시 적용시키고자 했습니다. Twitter는 보통 PC보다는 모바일로 보는 경우가 잦기 때문이지요. 간단한 페이지이기 때문에 이번에도 역시 크게 어려워 보이지는 않았습니다.

 

기타

간단한 애니메이션이나.. 커서 아이콘 같은 부분 등 소소하게 외관도 꾸며보고 싶었습니다!

 


이제 실제로 만들어보자!

먼저 Dark Mode 기능을 만들어보기로 했습니다. 실제로 작업하기에 앞서 구글링을 해보니, 적용 자체는 생각보다 간단하게 되는 것 같았습니다.

 

@media (prefers-color-scheme: dark) {
  .theme {
    background: black;
    color: white;
  }
}

 

prefers-color-scheme 라는 미디어 쿼리를 이용하면 브라우저의 테마를 판단하여 특정 테마일 때 지정된 CSS를 먹일 수 있었습니다. 다만, 아직 Draft(초기 정의) 상태이기에 최신 브라우저가 아니면 동작하지 않는다는 치명적인 단점이 있었습니다. 따라서 이를 지원하지 않는 브라우저에서도 Dark Mode로 전환할 수 있는 토글 버튼 같은 게 필요했고, 그것과 관련하여 다시.. 구글링을 했습니다.

 

그러던 중 JavaScript로 위의 기능들을 제어할 수 있는 방법이 소개된 이 미디엄 포스트를 보게 되었습니다. 최상위 DOM인 html에 Class를 토글하는 방식으로, 테마 값을 저장한 변수를 만들어 그 변수에 따라 Dark Mode 클래스를 토글 하는 방식이라고 말씀해주셨습니다. (해당하는 코드는 위에 링크된 포스트에서 확인하실 수 있습니다. 좋은 정보 제공해주신 홍구님 감사드립니다!)

 

물론 이제 처음 책 읽고 입문한 저에게는 코드가 그저 외계어로밖에 보이진 않았지만(...) "토글 방식의 Function을 만들고, 로컬 스토리지에 테마 값을 저장하는 변수 userMode를 생성, 그리고 테마 값 auto에 필요한 정보를 가져오기 위해 위의 prefers-color-scheme를 활용해 브라우저의 테마를 가져오는 osMode 변수를 만든다. 그리고 switch-case문을 이용해서 auto → dark → light → auto 순으로 테마를 토글 하는 기능을 만들고, 그 값에 따라 html.darkmode 클래스를 부여 / 제거하도록 한다.. "라고 일단 간단하게 이해했습니다.

 

먼저 CSS 부분은 위의 JavaScript 때문에 미디어 쿼리를 사용할 필요가 없었습니다. (물론 있어봤자 색상이긴 하지만..) 따라서 아래와 같이 Dark Mode 색상 팔레트에 대한 변수를 만들어두었습니다.

 

:root {
    /* Color */
    --primary: #5C5D64;
    --primary-disabled: #DADAE0;
    --secondery: #6D989B;
    --link: #8790EA;
    --paper: #F8F8F8;
    /* Font */
    --font: 'Raleway','Nanum Gothic',sans-serif;
}
html.darkmode:root {
    --primary: #DBDDED;
    --primary-disabled: #232436;
    --secondery: #5BF5FF;
    --link: #F17979;
    --paper: #12131F;   
}

 

이 변수로 대강 CSS를 짜서 보니 정말로 테마가 변경이 되었습니다! 막상 적용돼서 동작하는 것을 보니 신기했었긴 했지만 제가 뜻하는 대로 완벽히 되지는 않았고, 아래의 문제들이 발생했습니다.

 

  • 토글이 "auto → dark → light → auto..." 순으로 돌기 때문에 내 기본 테마에 따라 "light → dark → light → light"처럼 한번 테마 값이 중복되어 버튼을 눌러도 반응이 없는 경우가 발생한다.
  • 위의 코드로 바뀌는 css가 적용된 항목일 뿐.. 이미지 리소스가 바뀌지 않는다.

 

코드 복붙만으로는 실력을 늘릴 수 없다는 신의 계시인지는 모르겠으나.. 그래도 좋은 기회 이리라 생각하고 한번 위의 문제들을 해결해보기로 했습니다.

 

이럴때를 위해 준비했다 Do it! 자바스크립트!! (이상한 책들도 보이지만 무시하자)

토글 문제 해결하기

일단 사용할 수 있는 변수를 잘 활용하면 해결할 수 있을 것 같았습니다. 기존의 switch-case 문을 보면,

 

if(toggle) {
    switch(userMode) {
        case 'auto':
            userMode = 'dark';
            break;
        case 'dark':
            userMode = 'light';
            break;
        default:
            userMode = 'auto';
    }
    localStorage.userThemeMode = userMode;
}

 

로 되어 있는데, 결과적으로 "auto → dark → light → auto..."로 순환하고 있었습니다. 일단 여기서 해결해야 할 부분은 "첫 번째 auto일 경우"와 "그 이후의 auto일 경우"로 가려냈습니다.

 

대강 이런 개념도

후자의 경우는 생각보다 쉽게 해결책을 생각해 내었는데, light 케이스를 하나 더 만들어 "Light Mode일 때, dark로 토글이 되어라!"라고 써주면 뒷부분 토글이 auto를 생략하고 dark와 light 사이에서만 돌거라 생각했고 실제로 그렇게 되었습니다.

 

그다음.. 전자의 경우는 브라우저 테마 값을 가지고 있는 osMode 변수를 활용해서 가려내면 어떨까 싶었습니다. "만약 osMode의 값이 dark면, 이다음 토글 할 때 light로 토글 해!" 라고 하면 해결될 것 같았습니다. 

 

if(toggle) {
    switch(userMode) {
        case 'auto': 
            if(osMode=='dark') {
                userMode = 'light';
            }else {
            	userMode = 'dark';
            }
            break;
        case 'dark':
            userMode = 'light';
            break;
        case 'light':
            userMode = 'dark';
            break;
        default:
            userMode = 'auto';
    }
    localStorage.userThemeMode = userMode;
}

 

그리하여 위와 같이 코드를 고쳤습니다. auto일 경우 osMode의 값을 활용하여 osMode가 dark일 때에는 light로, 그 반대일 경우에는 dark로 넘어가도록 if문을 만들어주었고, Light Mode의 case를 추가하여 서로 반대 테마로만 토글이 반복되도록 했습니다. 

 

확인을 위해 osMode 값을 표시하는 구문을 추가했다

결과는 대성공! 토글 버튼을 여러 번 눌러도 이제 반응이 없는 경우가 사라졌습니다!

 


 

리소스가 교체되지 않는 문제 해결하기

if(toggle) {
    switch(userMode) {
        case 'auto':
            userMode = 'dark';
            document.getElementById("theme-changer").src = "./elements/bio/ic_light.svg";
            document.getElementById("logo").src = "./elements/bio/img_logo_dark.svg";
            break;
        case 'dark':
            userMode = 'light';
            document.getElementById("theme-changer").src = "./elements/bio/ic_dark.svg";
            document.getElementById("logo").src = "./elements/bio/img_logo_light.svg";
            break;
        default:
            userMode = 'auto';
    }
    localStorage.userThemeMode = userMode;
}

 

처음엔 이렇게 case문에 끼워 넣어서 토글 될 때마다 리소스도 같이 변경되도록 하고자 했습니다. 이렇게 해보니 얼추 잘 되는 듯했으나 치명적인 문제가 발생했으니.. 그것은 userMode가 "auto"일 때 리소스가 올바르게 표시되지 않는 문제였습니다! dark와 light로 바뀔 때에는 서로를 위한 구문이 추가되어 있는데 막상 auto는 정의가 되지 않아 발생하는 문제 같았습니다.

 

해결되었나..!

그래서 처음에는 이 case문에 끼워 넣는 방식을 개선해나가는 방향으로 생각했는데.. 아무리 생각해도 무엇인가 잘못된 생각을 하고 있는 것이라는 느낌에서 헤어 나올 수 없었습니다. 그러던 도중 다시 한번 osMode 변수를 떠올리게 됩니다!

 

if(userMode=='auto') {
    if(osMode=='dark') {
        document.getElementById("theme-changer").src = "./elements/bio/ic_light.svg";
        document.getElementById("logo").src = "./elements/bio/img_logo_dark.svg";
    } else {
        document.getElementById("theme-changer").src = "./elements/bio/ic_dark.svg";
        document.getElementById("logo").src = "./elements/bio/img_logo_light.svg";
    }
} else if(userMode=='dark') {
    document.getElementById("theme-changer").src = "./elements/bio/ic_light.svg";
    document.getElementById("logo").src = "./elements/bio/img_logo_dark.svg";
} else if(userMode=='light') {
    document.getElementById("theme-changer").src = "./elements/bio/ic_dark.svg";
    document.getElementById("logo").src = "./elements/bio/img_logo_light.svg";
}

 

위에 토글 버튼을 고쳤을 때처럼, osMode를 활용하여 auto일 때는 브라우저 테마에 따라 리소스를 표시해주고, 이후에는 userMode의 값에 따라 변경되게 하는 아이디어를 생각해내었습니다. 근데 이거 생각해보니 위의 토글 구문과 기본적인 골자가 같네요(...) 한번 섞어볼까 했는데, 이 친구는 테마와 리소스를 매칭 하는 것이라 그것과 조합하기에는 좀 귀찮아질 부분이 많아 보입니다. 일단은 문제 해결로 만족!

 


 

언어 토글 버튼과 테마 토글 버튼

다음은 언어 변경 기능을 만들어볼 차례였습니다. 조금 조사해보니, 이렇게 언어 전환 등을 하는 것을 i18n(국제화)이라고 해서 이를 위한 라이브러리 등이 많이 제공되고 있었습니다. 근데.. 이런 라이브러리를 활용한 작업은 여기에 적용하기엔 덩치가 많이 커 보였고 (이해도 못할뿐더러 Dark Mode 때문에 지쳐 있었기에..) 무언가 꼼수(?) 같은 것으로 만들어볼 수 있지 않을까 싶었습니다.

 

한참을 고민하며 나온 결론은 결국.. display: none;으로 숨겼다가 전환될 때 이전 것이 none 처리되고 전환되는 언어가 표시되는 방식(...)을 택했습니다. 위의 Dark Mode 기능을 고치느라 토글 기능을 어느 정도 이해했기에 버튼에 따라 언어가 토글 되는 방식으로 만들었습니다.

 

<li><button onclick="localeJp(false);" id="korButton">KOR</button></li>
<li><button onclick="localeJp(true);" id="jpnButton" style="opacity: 0.5;">JPN</button></li>

 

일단은 일본어로 표시되는 상황을 참으로 설정하고 onclick이벤트로 localeJp 기능에 값을 보내게 했습니다.

 

function localeJp (toggle = false) {
    if(toggle){
        document.getElementById("jp").style.display = "inline";
        document.getElementById("ko").style.display = "none";
        document.getElementById("korButton").style.opacity = "0.5";
        document.getElementById("jpnButton").style.opacity = "1";
    } else {
        document.getElementById("jp").style.display = "none";
        document.getElementById("ko").style.display = "inline";
        document.getElementById("korButton").style.opacity = "1";
        document.getElementById("jpnButton").style.opacity = "0.5";
    }
} 

 

그다음 localeJp가 받아온 값에 다라 jpko 아이디를 가진 섹션을 보일지 말지 스타일로 제어하도록 했으며, 추가적으로 어떤 언어가 활성화되어 있는지에 따라 투명도로 현재 선택된 언어의 버튼을 구분해주는 기능도 만들었습니다. 생각보다.. 간단하게 만들 수 있었습니다. (올바른 방법은 아닌 것 같지만..)

 


左 : 750px보다 넓을 경우, 右 : 750px보다 좁을 경우

만들 때마다 생각하지만 반응형 작업은 이 규모의 페이지라면 크게 어려운 친구는 아닌 것 같습니다. (단지 귀찮을 뿐..) 이것 역시 미디어 쿼리를 활용하여 쉽게 수정할 수 있었고, 페이지 구조가 간단해서 모바일에서도 보기에 큰 이상이 없었기에 너비를 좁혔을 때 깨지는 지점부터 깨지지 않도록 하는 작업을 주로 했습니다.

 

@media ( max-width: 750px ) {
    ...
}

 

위의 쿼리를 사용하여 정상적으로 표시되지 않는 지점인 750px부터 다른 스타일이 적용되도록 작업했습니다. 주로 여백 값과 메뉴들이 있는 상단 부분을 정리하는 작업을 진행했습니다.

 


 

적용된 커서와 애니메이션

애니메이션의 경우, 마법의 주문 transition을 활용하면 그럴싸한 페이드 애니메이션을 줄 수 있습니다. 

 

body {
    
    max-width: 900px;
    margin-left: auto;
    margin-right: auto;
    color: var(--primary);
    background-color: var(--paper);
    transition: .25s;
}

 

적절한 예로, body 전체에 transition을 주어 Dark Mode를 오갈 때 깜빡이지 않고 자연스럽게 전환되도록 한 것이 있습니다. 너무 길게 적용하면 답답한 느낌이 있어, 모든 애니메이션은 0.5s 이내로 하는데, 테마 전환의 경우 화면 전체가 바뀌는 것이기 때문에 이 속도를 더 빠르게 하여 0.25s로 했습니다.

 

#theme-changer {

    transition: .5s;
}

#theme-changer:hover {

    transform: rotate(90deg);
    transition: .5s;
}

 

테마 전환 버튼의 경우 호버 이펙트만 있으니 좀 심심한 감이 없지 않아 있어서 transform을 활용해 호버 하면 아이콘이 "빙글~"하고 돌아가도록 했습니다. 90도로 돌리는 애니메이션을 삽입하니 적당히 깔끔하면서도 재밌는 버튼이 되었습니다. (ㅋㅋ)

 

* {

    cursor: url(../elements/bio/cursor.svg), auto;
}

 

커서 바꾸는 건 별도의 작업이 필요한 줄 알았는데 찾아보니 그냥 cursor에 이미지 url을 넣어주면 되었습니다. 많은 강좌들이 .curani로 해야 한다고 했는데, 혹시나 해서 SVG 이미지를 넣어보니 잘 되었습니다. (...) 뭐.. 뒤에 있는 "auto" 때문에 이미지를 지원하지 않으면 알아서 잘 보여줄 테니.. 괜찮겠죠? (ㅋㅋ)

 


마치며

 

위의 작업들로 결국 원하는 대로 BIO 웹페이지를 완성할 수 있게 되었습니다! 저번 버전보다 깔끔하고 부드러운 인상으로 만들어져서 너무나 마음에 듭니다. (ㅋㅋ)

 

이번 작업을 진행하면서, JavaScript 코드의 맥락을 어느 정도 이해하는 것을 배웠다고 생각합니다. 처음 봤을 때에는 아무 감도 안 왔던 Dark Mode 코드를 책과 인터넷을 통해 어떻게든 이해하려고 노력해보니 전부 깨닫지는 못했지만 어떠한 방식으로 돌아가는 것인지는 알 수 있었고, 더 나아가 내가 원하는 바에 맞게 수정하고 정상적으로 돌아가는 것을 보니 감회가 새로웠습니다.

 

또 요소 선택자나 for문등 기초적인 것들을 활용해 직접 기능을 짜 보니 책으로만 보고 이해할 수 없었던 부분들을 잘 알 수 있었습니다. 적혀 있던 코드만 보고 머리 싸맸던 때를 생각하면 별거 아니네요! (더 심화적으로 들어가면 별거겠지만요..)

 

앗!

근데 솔직히 말하면, 이 수많은 JavaScript 함수들을 다 머리에 넣고 필요할 때마다 써먹을 자신은 아직 없습니다(...) 좀 더 공부하면 어느 정도 해결이 되려나요? 여하튼 좀 더 공부를 해서 다음 프로젝트에서는 코드를 빌려오지 않고 직접 조금 복잡한 로직을 짜 보고 싶은 목표가 생겼습니다. 이 작업에서 얻은 지식들을 바탕으로 빠른 시일 내에 블로그도 한번 손보고요!

 

마지막으로, 연휴에 했던 것들 중에 가장 재밌었고 유익했던 것 같았습니다. 앞으로도 쉬는 날에 놀지만 말고 이것저것 건드려 봐야겠습니다 (ㅋㅋ) 긴 글 읽어주셔서 감사합니다!

'ARTICLES > AT WORK' 카테고리의 다른 글

처음으로 재택근무를 해본 후기  (0) 2020.03.07
클라우드 서비스를 Dropbox로 옮기며.  (0) 2019.12.25