Next.js로 접근 가능하고 깜박이지 않는 어두운 모드 만들기

10346 단어 darkmodethemenextjs

일반적인 함정



웹 애플리케이션을 위한 다크 모드를 만드는 것은 쉬운 작업인 것 같고 실제로도 그렇습니다! 그러나 여전히, 당신이 직면할 수 있는 몇 가지 함정이 있습니다. 가장 일반적인 것은 다음과 같습니다.
  • ♿️ 접근성 문제, 즉 prefers-color-scheme 기능이 지원되지 않습니다. 그것이 하는 일은 기본적으로 웹사이트를 시스템과 같은 색상으로 만드는 것입니다. 특히 자동 다크 모드(낮에는 밝은 모습, 밤에는 어두운 모습)와 결합할 때 매우 유용합니다. 항상 해당 기능을 존중하는 것이 좋습니다. 그 때문에 사용자를 잃고 싶지는 않을 것입니다!

  • 📸 깜박임 - 밤에 새로고침하거나 페이지에 들어가면 화면 전체가 매우 강한 투광 조명으로 바뀝니다. 재미없어.



  • 솔루션



    깜박임 문제에 대한 몇 가지 솔루션이 있으며 모두 앱을 렌더링하는 방법에 따라 다릅니다.

    서버측 렌더링(SSR)을 사용하는 경우 선택한 색상 모드를 쿠키에 저장하고 이를 기반으로 서버에서 페이지의 적절한 변형을 렌더링하기만 하면 됩니다. 예, 어떤 경우에는 캐시를 무효화해야 할 수도 있습니다 🤟

    이미 SSR을 사용하고 있다면 완벽해 보입니다. 그러나 주요 단점은 서버가 클라이언트가 선호하는 색상 모드( prefers-color-scheme )를 알 수 없다는 것입니다. 따라서 사용자가 수동으로 변경해야 하며 이는 사용자에게 문제가 될 수도 있고 아닐 수도 있습니다.

    정적 응용 프로그램의 경우 매우 유사하지만 쿠키를 저장하고 읽는 대신 저장소(localStorage 또는 sessionStorage)에서 이 작업을 수행합니다. 그리고 우리는 서버 측이 아닌 클라이언트 측에서 페이지 렌더링을 연기하고 있습니다.

    따라서 흐름은 다음과 같습니다.
  • 페이지 로딩 시작 🔄
  • 차단 스크립트가 실행되고 다음이 수행됩니다.
  • 저장소에 이미 저장된 색상 모드가 있는지 확인합니다. 그리고 하나 있으면 마지막 단계로 바로 이동합니다
  • .
  • 저장소에 항목이 없으면 OS에서 현재 사용 중인 것과 동일한 색상 모드를 선택합니다
  • .
  • 본문 요소에 적절한 클래스를 설정합니다(예: .light-theme).

  • 적용된 클래스를 기반으로 앱이 변수에 올바른 값을 설정하고 플릭 없이 페이지를 렌더링합니다 ⛔📸

  • 위의 솔루션은 클라이언트 및 서버 측 렌더링 모두에 적용될 수 있습니다. 그들은 이론적으로 FCP 점수를 낮추지만 무시할 수 있는 감소입니다.

    구현



    다음은 my library을 사용하여 이를 구현하는 방법에 대한 예입니다.

    설치




    $ npm i --save nextjs-color-mode
    
    # or  
    
    $ yarn add nextjs-color-mode
    


    설정



    먼저 ColorModeScript에서 nextjs-color-mode를 가져와 _app.js 파일의 어딘가에 배치해야 합니다.

    import Head from 'next/head'  
    import { ColorModeScript } from 'nextjs-color-mode'  
    
    const criticalThemeCss = `  
    .next-light-theme {  
    --background: #fff;  
    --text: #000;  
    }  
    
    .next-dark-theme {  
    --background: #000;  
    --text: #fff;  
    }  
    
    body {  
      background: var(--background);  
      color: var(--text);  
    }  
    `  
    
    function MyApp({ Component, pageProps }) {  
      return (   
        <>  
          <Head>  
            <style dangerouslySetInnerHTML={{ __html: criticalThemeCss }} />  
          </Head>  
          <ColorModeScript />  
          <Component {...pageProps} />  
        </>  
      )  
    }
    


    styled-component나 감성을 사용하는 경우 criticalThemeCss의 내용을 GlobalStyles에 넣을 수 있습니다. 그것이 중요한 CSS이고 전역 스타일의 맨 위에 있는지 확인하십시오.

    테마 스위처



    테마 전환기를 구현하려면 useColorSwitcher 후크를 사용해야 합니다.

    import { ColorModeStyles, useColorModeValue, useColorSwitcher } from 'nextjs-color-mode'  
    
    export default function ColorSwitcher(props) {  
      const { toggleTheme, colorMode } = useColorSwitcher()  
    
      return (  
        <button onClick={toggleTheme}>  
          Change theme to {colorMode === 'light' ? 'dark' : 'light'}  
        </button>  
      )  
    }
    


    이 후크를 명시적으로 사용하는 모든 구성 요소는 클라이언트 측에서만 렌더링되어야 합니다. 이렇게 하려면 next/dynamic 모듈 또는 check out how it's done in the example 모듈을 사용할 수 있습니다.

    동적 변수 사용



    때로는 디자인 시스템을 생략하거나 빠르게 핫픽스해야 할 수도 있습니다. 여기에 대한 해결책이 있습니다.

    export default function SomeComponent() {  
      const [boxBgColor, boxBgCss] = useColorModeValue('box-color', 'blue', 'red')  
      const [boxBorderColor, boxBorderCss] = useColorModeValue('box-border-color', 'red', 'blue')  
      // the first item of the array returns CSS variable name  
      // and the second one returns a special object that then gets parsed into a themable CSS variable  
    
      return (  
        <>  
          <ColorModeStyles styles={[boxBgCss, boxBorderCss]} />  
          <div style={{ width: '24rem', height: '12rem', backgroundColor: boxBgColor, border: "10px solid", borderColor: boxBorderColor }} />  
        </>  
      )  
    }
    


    같은 이름을 두 번 사용하지 마십시오. 변수 재정의가 발생할 수 있고 디버그하기 어렵습니다. 또한 고유 ID, UUID 또는 임의로 생성된 문자 집합과 같은 것을 사용하는 것은 나쁜 생각입니다. 불일치 콘텐츠 경고를 표시하고 디버그하기가 훨씬 더 어려워집니다!

    working exampleits repository 을 확인하십시오.

    좋은 웹페이지 즐겨찾기