약 2달 전, 워낙 방문자 수가 적은 블로그라서 아무도 알아차리지 못했을 테지만, 기존 Jekyll로 구축했던 블로그를 Next.js와 React 기반으로 리모델링했다. 손수 디자인까지 하는 등 밑바닥부터 새로 만든다고 고생깨나 했다. 외관도 신상, 소스 코드도 신상. 아주 따끈따끈한 블로그가 되었다. "이게 갈아엎은 거라고?" 라는 생각은 뒤로 넣어두시고, 이번 글에선 새 블로그를 만들며 겪은 어려웠던 점과 함께 자잘한 도움말 카테고리의 20회를 축하하는 의미로 새 기능들에 대해서도 소개하고자 한다.
블로그를 운영하면 가장 많이 신경 쓰게 되는 부분이 SEO(Search Engine Optimization, 검색 엔진 최적화)다. 글을 아무리 많이 쓰고, 도네이션 버튼이나 광고를 아무리 많이 달아도 결국 구글 검색에 노출되지 않으면 말짱 꽝. 하지만 신경 쓴다고 항상 잘 되는 건 아니기 마련이라 스스로 "어차피 내가 보려고 글 쓰는 거야"라고 위로해 왔지만, 그래도 좋은 게 좋은 거지. 그래서 이번에 SEO에 도움이 될 변화를 도입하게 되었다.
슬러그(Slug)란, 일반적으로 URL의 끝에 포함되는 웹 주소의 식별자 부분이다. 이전 버전에선 이 부분이 아주 사무적이고 딱딱하게 작성되고 있었다. URL 주소 또한 검색 엔진이 크롤링하는 요소 중 하나이다. 그만큼 사용자 친화적인 슬러그가 SEO에 도움 된다고 한다. 최대한 5단어가 넘지 않도록 짧고 간결하게, 하지만, 이 페이지의 핵심 내용을 담고 있도록 모든 기존 작성 글에 신규 슬러그를 부여하였다.
그리고 단순히 URL이 변경되었다는 사실보다 중요한 것. 수년간 사용해 왔던 URL을 하루아침에 버릴 순 없었다. (혹시 모를) 기존 사용자들이 내 글을 링크해놓거나 북마크 해뒀을 수도 있잖아. 그래서 신규 URL을 적용함과 동시에 기존 방식의 URL 목록을 자동 생성하는 스크립트를 작성했으며, 과거 URL로 접속한 사용자를 자동으로 신규 URL로 리다이렉션 해주는 페이지를 생성하도록 기능을 구현했다. 이렇게 레거시 지원에도 게을리하지 않는 Anteater's laboratory가 되겠습니다 여러분.
예상 완독 시간이 추가되었습니다.
여러 블로그를 방문하며 눈독 들이고 있던 기능이었다. 멋있잖아. 멋도 멋인데, 나름 대시보드 서비스를 개발했던 사람으로서 이런 인사이트의 힘을 중요하게 생각하기 때문에 적극적으로 도입하게 되었다. 계산식에는 인터넷에 공개된 논문(「한국어 읽기 속도 측정 애플리케이션의 유효성 및 정상인의 읽기 속도에 대한 사전 연구」, 대한안과학회지, 2016)을 참고하였다. 대신 WPM(Words Per Minutes) 수치 정도만 참고했고, 이미지와 코드 수는 어림잡아서...
태그 시스템이 추가되었습니다.
기존 블로그에선 게시글을 카테고리 단위로만 분류하고 있었다. "자잘한 도움말", "독후감", "Not 4 Dev" 등등. 하지만 카테고리는 글의 형태에 따른 분류일 뿐. 내가 워낙 좋게 말하면 풀스택, 나쁘게 말하면 이도 저도 아닌 개발 커리어를 쌓고 있는 중이기 때문에 한 카테고리 안에서도 주제가 다양했다. 그래서 주제에 따라 게시글 목록을 분류할 수 있도록 태그 시스템을 구현했다.
기존 게시글 모두에 태그를 부여했으며, 태그를 통해 게시글을 필터링할 수 있는 기능도 구현했다. 필터 컴포넌트 구현에 어려움은 없었는데 한 50년쯤 뒤에 게시글이 500개가 넘어가면 어떻게 해야 하나 고민 중.
Buy Me A Coffee 버튼이 더 화려해졌습니다.
가난한 개발자는 커피 마실 돈이 필요해요. 하지만 글솜씨가 미려하지도 않고, 기술적으로 아주 깊은 통찰을 보여주지도 않는 데다 창의성도 부족한 이 블로그에서 저 버튼을 기꺼이 누를 사람이 얼마나 있을까. 버튼에 눈길이라도 한 번 주십사 재롱을 좀 부려봤다.
기본 모드와 다크 모드, 두 가지 테마를 지원합니다.
기존 블로그엔 어두운 색상을 사용했었다. 개발자의 친구 다크 모드지만 역시 칙칙해. 신규 블로그에선 디자인을 산뜻한 흰색을 바탕으로 꾸며보았다. 하지만 이걸로 끝낼 순 없지, 테마 시스템을 적용해 흰색 배경의 기본 모드와 검은색 배경의 다크 모드를 모두 지원 가능하도록 구현했다. 이제 새벽에 불 꺼놓고 몰래 블로그 보다가 안구 테러당할 일 없다구.
웹에서 다크 모드 구현하기
오늘은 위에 나열한 변경 점 중 다크 모드에 대해서 한 번 다뤄보자. 사이트의 핵심까지는 아니지만 없으면 눈이 아파 신경 쓰이는 이것. 웹 페이지에서 다크 모드는 어떻게 구현해야 할까? 일단 기본적으로 다크 모드와 같은 테마(Theme) 기능은 GUI의 스타일 영역에 포함되는 만큼 CSS를 기반으로 구현하면 된다. CSS에선 미디어 쿼리에 다음과 같은 규칙을 지원한다.
일종의 반응형 디자인 구현이라고 볼 수 있다. 반응하는 게 뷰포트의 크기가 아니라 시스템의 테마일 뿐. 하지만 이 방식 만으로 다크 모드를 구현하는 건 비추천한다. 첫째 이유는 레거시 지원. Web API 관련 글을 쓸 때마다 비슷한 이야기를 반복하는 것 같다. 2010~2020년대쯤 처음 소개된 웹 기반 기술을 다룰 땐 2024년 현재 기준 과거 버전의 웹 브라우저에서 잘 동작하지 않을 수 있다는 사실을 염두에 둬야 한다.
물론 웬만한 상황에선 동작하긴 한다. 그러나 이 방식엔 또 다른 문제도 있다. 오직 시스템의 설정에 따라서만 웹 앱의 테마가 결정된다는 것. 이 방식에선 웹 앱 자체적으로 테마를 변경할 수 없다. 현재 내 블로그 우측 하단에 존재하는 테마 변경 버튼 같은 기능을 구현하려면 어떻게 해야 할까.
최상위 엘리먼트(<body> 혹은 의사 클래스 :root에 해당하는 엘리먼트)에 테마를 설정하는 클래스를 동적으로 제어해 주면 된다. 이렇게 JavaScript가 개입할 수 있게 되면 다양한 가능성이 발생한다. 첫 번째 방식과 조합해 편의성을 조금 더 높여볼 수도 있다.
웹 페이지가 복잡해질수록 다크 모드의 영향을 받는 엘리먼트도 늘어날 것이다. 엘리먼트 하나마다 일일이 클래스를 조작하며 다크 모드와 라이트 모드 속성을 구분해 주긴 귀찮으니 다음과 같이 CSS 변수(사용자 지정 속성)를 설정하는 것이 좋다.
Next.js, React에서 다크 모드 구현하기
프론트엔드 프레임워크를 사용하는 현대적인 웹 개발에선 다크 모드를 어떻게 구현하면 될까? 앞서 CSS를 사용해 다크 모드를 구현하는 방식을 살펴보았다. 그런데 다크 모드 기능은 조금 더 복잡해질 수 있다. 예를 들어, 다크 모드에 따라 스타일이 아닌 HTML 엘리먼트의 내용까지 변경될 수도 있다. 이를 구현하기 위해선 컴포넌트에서 다크 모드에 대한 상태를 참조해 값을 변경하면 될 것이다. 그렇다면 그 "다크 모드에 대한 상태"는 역시 전역 상태로 관리해야겠지?
이번 블로그 Next.js 기반 개편 작업을 사례로 들어보자. 작업에는 CSS-in-JS 라이브러리 styled-components와 전역 상태 관리 라이브러리 Zustand가 사용되었다.
참 쉽죠? 일부 불필요한 부분은 제외했다. 정리하자면, 1) 전역 상태를 생성 2) 스타일시트 라이브러리에서 그 상태를 참조하도록 설정 3) 최상위 컴포넌트에서 스타일시트 라이브러리를 통해 테마를 주입. 이렇게 설명할 수 있겠다. 그리고 전역 다크 모드 상태는 아래처럼 필요한 컴포넌트에서 불러와 HTML 조작에 사용하면 된다.
내가 배운 것
Next.js로 만든 웹 사이트
다크 모드를 구현하는 다양한 방법들
사실, 10월 안에 이 글을 올리는 것이 목표였는데 그러지 못했다. 글의 뒷부분에 힘이 빠졌다는 느낌도 든다. 더 다뤄 보고 싶었던 주제가 있는데, 다른 글에서 다시 도전해 봐야 할 것 같다. 집에 좀 큰일이 생겨가지고 거기에 온 정신이 팔려 있거든 지금. 다들 건강 잘 챙기자.