You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
테마는 다크, 라이트 테마 정도로만 구성 되어선 안 됩니다. 사용자의 운영체제에서 설정해 둔 시스템 설정에 따라 테마를 결정해줘야 합니다. 그 후 작업으로 토글 버튼을 제공해 사용자가 원하는 테마를 지정할 수 있도록 해주는 게 좋습니다.
사용자가 직접 사이트의 테마를 지정해 둔 상황이 아니라면, OS의 기본 설정 테마에 맞춰 자동으로 변경해줘야 합니다.
먼저 개선 전/후 비교 gif를 확인해보고 어떠한 작업을 거쳤는지 아래에서 설명합니다.
개선 전
사용자가 시스템의 테마를 변경해도 사이트의 테마가 이에 맞춰 자동으로 변경되지 않습니다. (위에 살짝 노출된 크롬 북마크 탭바를 보면 이해하기 편합니다) 사이트의 테마도 동기화 되려면 사용자가 OS 테마를 변경하고 직접 사이트를 새로고침 해줘야 반영되는 모습입니다. 이는 사용자 경험에 좋지 않습니다.
개선 후
사용자가 시스템의 테마를 변경하면 자동으로 사이트의 테마도 그에 맞춰 변경됩니다.
구현
Gatsby의 이점
먼저, Gatsby가 React로 만들어진 기존 client-side 앱과 어떻게 다른지 조금 파고들어 보겠습니다. React를 사용하면 모든 렌더링이 브라우저에서 발생합니다. 이 초기 HTML은 비어 있고 몇 가지 JS 스크립트가 포함되어 있습니다. 브라우저가 해당 스크립트를 다운로드하고 구문 분석 하여 DOM 노드를 주입하는 등 모든 렌더링이 클라이언트에서 발생합니다. 이를 client-side redering 이라고 하죠.
이 방식의 문제점은 사용자에게 매우 좋은 경험을 제공할 수 없다는 점입니다. 이 모든 작업에는 시간이 걸리고 브라우저와 React가 무언갈 하는 동안 사용자는 텅 빈 흰 화면을 응시하고 있어야 하기 때문입니다.
중요시 생각해봐야 할 점은 많은 웹 사이트의 막대한 부분이 정적이며 컴파일 타임에 구축될 수 있다는 점입니다. 그래서 어느정도 완성된 초기 HTML을 생성해서 브라우저가 JS를 다운, 구문 분석 등을 하는 동안 사용자는 흰 화면이 아닌 중요한 요소들을 미리 확인할 수 있게 됩니다.
Gatsby는 이 작업을 굉장히 편하게 할 수 있게끔 제공해줍니다. 기술적으로 Gatsby가 하는 일은 서버 측 렌더링 입니다. 동일한 ReactDOMServer API, Node.js를 사용해 React 앱을 보다 전통적인 SSR 방식으로 렌더링하기 때문입니다. 하지만 개념적으로 다릅니다. "SSR" 방식은 프로덕션 서버 요청에 따라 실시간으로 실행되는 반면, 컴파일 타임 때 렌더링하는 것은 빌드 프로세스의 일부로 훨씬 이전에 실행되기 때문입니다. 이를 SSG(Static Site Generation) 방식이라 부릅니다.
테마 깜빡이는 현상
지금 설명하려는 것은 #49 이슈도 함께 연관되어 있는 내용입니다. 사용자가 내가 만든 사이트의 테마를 직접 설정한 상태가 아니라면 사용자가 선호하는 테마를 자동으로 적용해주고 싶은 상황이 있습니다.
하지만 따로 특정 로직을 작성하지 않은 경우, 화면이 깜빡이는 현상이 발생하는데요. 예를 들어 사용자가 선호하는 테마는 다크테마라 했을 때, 흰색 배경이었다가 검은색 배경으로 교체할 때 사이의 시간차 때문에 사용자는 화면이 깜빡 거린다 느낄 수 있는 겁니다. 이 문제는 꽤 까다롭습니다. 위에서 설명한 대로 HTML이 사용자의 디바이스에 도달하기 훨씬 전에 생성되므로 사용자가 선호하는 색상 테마를 알 수 있는 방법이 없기 때문입니다.
이 문제는 CSS 변수와 Gatsby에서 제공하는 API를 통해 해결할 수 있었습니다.
요구 사항
먼저 이 기능에 대한 기준을 정리해보겠습니다.
처음 로드할 때 사이트가 깜박이지 않아야 합니다.
토글 상태가 동기화되어 일치해야 합니다.
OS 설정에 따라 사용자가 "선호하는" 테마로 기본 설정되어야 합니다. 설정하지 않으면 기본적으로 라이트 테마가 보여집니다.
사용자는 토글 버튼을 클릭해 라이트/다크 테마를 전환할 수 있어야 합니다.
향후 방문 시 사용자가 지정한 테마를 사용할 수 있도록 사용자의 기본 설정을 저장해야 합니다.
초기 테마 결정하기
위 요구 사항을 고려할 때 초기 테마는 어떻게 결정되어야 할까요? 테마는 dark, light, undefined가 될 수 있겠습니다. undefined인 경우는 사용자가 처음 진입한 경우로 볼 수 있습니다. prefers-color-scheme를 통해 사용자가 어느 테마를 선호하는지 알 수 있습니다. 로직은 아래와 같습니다.
이 스크립트를 추가하면 사용자가 선호하는 테마와 지정한 테마를 관리할 수 있습니다. 그리고 토글 버튼 컴포넌트를 구현할 수 있습니다. 하지만 이 정도로 이상적인 목표를 달성할 순 없습니다. React가 처음 렌더링할 때 사용자가 선호하는 테마가 무엇인지 알 수 있는 방법이 없습니다. 렌더링은 사용자가 방문하기 한참 전에 클라우드에서 수행되기 때문입니다. 사용자가 라이트 테마를 원한다고 가정하고 클라이언트에서 React가 하이드레이션된 후에 교체할 수 있습니다. 따라서 깜박임이 발생하는 건 여전합니다.
이상적으로는, 사용자에게 보내는 HTML이 첫 프레임에 이미 올바른 테마를 가지고 있어야 한다는 것입니다. 여러 해결 방법이 있겠지만 컴파일 타임에 HTML을 생성할 때 모든 콘텐츠 앞에 <script> 태그를 삽입하는 방법이 있습니다. 그러면 이 스크립트가 실행 완료될 때까지 화면에 아무것도 그려지지 않습니다. 이를 위해 Gatsby에서 지원하는 API를 활용해 목적을 달성할 수 있습니다.
Gatsby에서의 HTML 업데이트
Gatsby는 빌드할 때 사이트의 각 페이지에 대한 HTML 파일을 생성합니다. 최종 목표는 이 컨텐츠 위에 <script>태그를 삽입하여 브라우저가 먼저 파싱하도록 하는 것입니다.
Gatsby는 이를 위한 SSR API들을 지원해줍니다. 루트 경로에 gatsby-ssr.tsx 파일을 생성하고 아래 코드를 추가하면 목표를 달성할 수 있게 됩니다.
setPreBodyComponents는 <body> 태그 내에서 빌드하는 콘텐츠 위에 React 요소를 삽입하는 기능입니다.
dangerouslySetInnerHTML를 사용해 스크립트를 포함시킵니다.
이제 원하는 바와 같이 첫 프레임에 사용자가 선호하는 테마를 올바르게 보여줍니다. 토글 버튼을 추가해 사용자가 테마를 제어할 수 있도록 설정하면 끝납니다.
토글 추가
사용자가 사이트에서 라이트/다크 테마를 자유롭게 선택할 수 있도록 하고 싶다면 토글 버튼을 추가해야 합니다. 만약 설정한 적이 없다면 OS에서 설정한 테마를 따르도록 해야 하죠.
토글이 트리거되면 다음 작업을 수행해야 합니다.
현재 테마를 추적하는 React 상태를 업데이트합니다.
localStorage를 업데이트하여 다음 번에 해당 사용자의 기본 설정을 기억합니다.
모든 CSS 변수가 테마에 해당하는 색상을 가리키도록 업데이트합니다. (with tailwindcss)
테마를 저장하고 업데이트 하기 위해 theme 값을 사용해 사용자에게 UI를 표시해줍니다.
하이드레이션 불일치 오류와 CLS 지표 신경 쓰기
단, 한 가지 문제가 있습니다. 토글 �버튼이 항상 올바른 상태로 초기화되지 않는다는 점입니다.
서버 측에선 사용자가 선호하는 테마 값을 알 수 없기 때문에 클라이언트에 마운트하기 전에는 undefined입니다.
따라서 클라이언트에서 마운트될 때만 렌더링해야 합니다. 대충 이 테마를 설정할 수 있는 버튼 요소가 어느 위치에 들어가야 할 지 구멍만 뚫어놓는 것이죠.
여기서 신경 써야 할 점은, 클라이언트 측에서 마운트될 때까지 플레이스홀더를 렌더링해서 갑작스런 레이아웃 이동을 방지하는 게 좋습니다.
이로써 모든 목적을 달성하고 사용자에게 좋은 경험을 줄 수 있게 되었습니다.
The text was updated successfully, but these errors were encountered:
테마는 다크, 라이트 테마 정도로만 구성 되어선 안 됩니다. 사용자의 운영체제에서 설정해 둔 시스템 설정에 따라 테마를 결정해줘야 합니다. 그 후 작업으로 토글 버튼을 제공해 사용자가 원하는 테마를 지정할 수 있도록 해주는 게 좋습니다.
사용자가 직접 사이트의 테마를 지정해 둔 상황이 아니라면, OS의 기본 설정 테마에 맞춰 자동으로 변경해줘야 합니다.
먼저 개선 전/후 비교 gif를 확인해보고 어떠한 작업을 거쳤는지 아래에서 설명합니다.
개선 전
사용자가 시스템의 테마를 변경해도 사이트의 테마가 이에 맞춰 자동으로 변경되지 않습니다. (위에 살짝 노출된 크롬 북마크 탭바를 보면 이해하기 편합니다) 사이트의 테마도 동기화 되려면 사용자가 OS 테마를 변경하고 직접 사이트를 새로고침 해줘야 반영되는 모습입니다. 이는 사용자 경험에 좋지 않습니다.
개선 후
사용자가 시스템의 테마를 변경하면 자동으로 사이트의 테마도 그에 맞춰 변경됩니다.
구현
Gatsby의 이점
먼저, Gatsby가 React로 만들어진 기존 client-side 앱과 어떻게 다른지 조금 파고들어 보겠습니다. React를 사용하면 모든 렌더링이 브라우저에서 발생합니다. 이 초기 HTML은 비어 있고 몇 가지 JS 스크립트가 포함되어 있습니다. 브라우저가 해당 스크립트를 다운로드하고 구문 분석 하여 DOM 노드를 주입하는 등 모든 렌더링이 클라이언트에서 발생합니다. 이를 client-side redering 이라고 하죠.
이 방식의 문제점은 사용자에게 매우 좋은 경험을 제공할 수 없다는 점입니다. 이 모든 작업에는 시간이 걸리고 브라우저와 React가 무언갈 하는 동안 사용자는 텅 빈 흰 화면을 응시하고 있어야 하기 때문입니다.
중요시 생각해봐야 할 점은 많은 웹 사이트의 막대한 부분이 정적이며 컴파일 타임에 구축될 수 있다는 점입니다. 그래서 어느정도 완성된 초기 HTML을 생성해서 브라우저가 JS를 다운, 구문 분석 등을 하는 동안 사용자는 흰 화면이 아닌 중요한 요소들을 미리 확인할 수 있게 됩니다.
Gatsby는 이 작업을 굉장히 편하게 할 수 있게끔 제공해줍니다. 기술적으로 Gatsby가 하는 일은 서버 측 렌더링 입니다. 동일한 ReactDOMServer API, Node.js를 사용해 React 앱을 보다 전통적인 SSR 방식으로 렌더링하기 때문입니다. 하지만 개념적으로 다릅니다. "SSR" 방식은 프로덕션 서버 요청에 따라 실시간으로 실행되는 반면, 컴파일 타임 때 렌더링하는 것은 빌드 프로세스의 일부로 훨씬 이전에 실행되기 때문입니다. 이를 SSG(Static Site Generation) 방식이라 부릅니다.
테마 깜빡이는 현상
지금 설명하려는 것은 #49 이슈도 함께 연관되어 있는 내용입니다. 사용자가 내가 만든 사이트의 테마를 직접 설정한 상태가 아니라면 사용자가 선호하는 테마를 자동으로 적용해주고 싶은 상황이 있습니다.
하지만 따로 특정 로직을 작성하지 않은 경우, 화면이 깜빡이는 현상이 발생하는데요. 예를 들어 사용자가 선호하는 테마는 다크테마라 했을 때, 흰색 배경이었다가 검은색 배경으로 교체할 때 사이의 시간차 때문에 사용자는 화면이 깜빡 거린다 느낄 수 있는 겁니다. 이 문제는 꽤 까다롭습니다. 위에서 설명한 대로 HTML이 사용자의 디바이스에 도달하기 훨씬 전에 생성되므로 사용자가 선호하는 색상 테마를 알 수 있는 방법이 없기 때문입니다.
이 문제는 CSS 변수와 Gatsby에서 제공하는 API를 통해 해결할 수 있었습니다.
요구 사항
먼저 이 기능에 대한 기준을 정리해보겠습니다.
초기 테마 결정하기
위 요구 사항을 고려할 때 초기 테마는 어떻게 결정되어야 할까요? 테마는 dark, light, undefined가 될 수 있겠습니다.
undefined
인 경우는 사용자가 처음 진입한 경우로 볼 수 있습니다. prefers-color-scheme를 통해 사용자가 어느 테마를 선호하는지 알 수 있습니다. 로직은 아래와 같습니다.이 스크립트를 추가하면 사용자가 선호하는 테마와 지정한 테마를 관리할 수 있습니다. 그리고 토글 버튼 컴포넌트를 구현할 수 있습니다. 하지만 이 정도로 이상적인 목표를 달성할 순 없습니다. React가 처음 렌더링할 때 사용자가 선호하는 테마가 무엇인지 알 수 있는 방법이 없습니다. 렌더링은 사용자가 방문하기 한참 전에 클라우드에서 수행되기 때문입니다. 사용자가 라이트 테마를 원한다고 가정하고 클라이언트에서 React가 하이드레이션된 후에 교체할 수 있습니다. 따라서 깜박임이 발생하는 건 여전합니다.
이상적으로는, 사용자에게 보내는 HTML이 첫 프레임에 이미 올바른 테마를 가지고 있어야 한다는 것입니다. 여러 해결 방법이 있겠지만 컴파일 타임에 HTML을 생성할 때 모든 콘텐츠 앞에
<script>
태그를 삽입하는 방법이 있습니다. 그러면 이 스크립트가 실행 완료될 때까지 화면에 아무것도 그려지지 않습니다. 이를 위해 Gatsby에서 지원하는 API를 활용해 목적을 달성할 수 있습니다.Gatsby에서의 HTML 업데이트
Gatsby는 빌드할 때 사이트의 각 페이지에 대한 HTML 파일을 생성합니다. 최종 목표는 이 컨텐츠 위에
<script>
태그를 삽입하여 브라우저가 먼저 파싱하도록 하는 것입니다.Gatsby는 이를 위한 SSR API들을 지원해줍니다. 루트 경로에
gatsby-ssr.tsx
파일을 생성하고 아래 코드를 추가하면 목표를 달성할 수 있게 됩니다.위 코드를 분석해보자면 아래와 같습니다.
onRenderBody
는 Gatsby가 보여주는 라이프사이클 메서드입니다. 빌드 프로세스 중에 HTML을 생성할 때 이 기능을 실행합니다.setPreBodyComponents
는<body>
태그 내에서 빌드하는 콘텐츠 위에 React 요소를 삽입하는 기능입니다.dangerouslySetInnerHTML
를 사용해 스크립트를 포함시킵니다.이제 원하는 바와 같이 첫 프레임에 사용자가 선호하는 테마를 올바르게 보여줍니다. 토글 버튼을 추가해 사용자가 테마를 제어할 수 있도록 설정하면 끝납니다.
토글 추가
사용자가 사이트에서 라이트/다크 테마를 자유롭게 선택할 수 있도록 하고 싶다면 토글 버튼을 추가해야 합니다. 만약 설정한 적이 없다면 OS에서 설정한 테마를 따르도록 해야 하죠.
토글이 트리거되면 다음 작업을 수행해야 합니다.
테마를 저장하고 업데이트 하기 위해 theme 값을 사용해 사용자에게 UI를 표시해줍니다.
하이드레이션 불일치 오류와 CLS 지표 신경 쓰기
단, 한 가지 문제가 있습니다. 토글 �버튼이 항상 올바른 상태로 초기화되지 않는다는 점입니다.
서버 측에선 사용자가 선호하는 테마 값을 알 수 없기 때문에 클라이언트에 마운트하기 전에는
undefined
입니다.따라서 클라이언트에서 마운트될 때만 렌더링해야 합니다. 대충 이 테마를 설정할 수 있는 버튼 요소가 어느 위치에 들어가야 할 지 구멍만 뚫어놓는 것이죠.
여기서 신경 써야 할 점은, 클라이언트 측에서 마운트될 때까지 플레이스홀더를 렌더링해서 갑작스런 레이아웃 이동을 방지하는 게 좋습니다.
이로써 모든 목적을 달성하고 사용자에게 좋은 경험을 줄 수 있게 되었습니다.
The text was updated successfully, but these errors were encountered: