<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          使用 Gatsby.js 搭建靜態(tài)博客黑暗模式

          共 2836字,需瀏覽 6分鐘

           ·

          2021-02-02 10:40

          來(lái)源 | https://ssshooter.com/2020-06-25-gatsby-blog-8/


          沒(méi)想到久違的 Gatsby 系列還能繼續(xù)寫(xiě),最近為博客更新了黑暗模式和手動(dòng)切換功能,順便記錄下來(lái)。當(dāng)然下面的實(shí)現(xiàn)方案不限于 Gatsby 使用,對(duì)于其他框架,思路都大同小異。

          方案 1

          最初實(shí)現(xiàn)的方案是直接使用媒體查詢(xún)和?css?變量。關(guān)鍵是把區(qū)分兩個(gè)模式的變量抽離出來(lái),分別配置兩組變量,核心代碼如下:
          @media screen and (prefers-color-scheme: dark) {  :root {    --linkColor: #ec9bab;    --fontColor: #ecc3cb;    --codeBlock: #3c495b;    --code: #c3c7cb;    --divider: #3e4b5e;  }}@media screen and (prefers-color-scheme: light) {  :root {    --linkColor: #683741;    --fontColor: hsl(284, 20%, 30%);    --codeBlock: #3c495b;    --code: #c3c7cb;    --divider: #eee;  }}body {  background-color: var(--backgroundColor);  color: var(--fontColor);  transition: all 0.5s ease-in-out;}

          (prism 用戶(hù)還要自己整理一下兩個(gè)模式的 prism 樣式)

          css 變量除了在 IE 不能用之外其他瀏覽器的適應(yīng)性還算不錯(cuò),如果必須適配 IE 的話(huà)需要另外寫(xiě)一份不用變量的樣式保底。

          方案 2

          按上面的寫(xiě)法其實(shí)已經(jīng)可以實(shí)現(xiàn)根據(jù)系統(tǒng)配置轉(zhuǎn)換明亮和黑暗模式,但是要做到直接在網(wǎng)頁(yè)通過(guò)一個(gè)切換按鈕手動(dòng)修改還是遠(yuǎn)遠(yuǎn)不夠,方案 2 登場(chǎng)。

          因?yàn)楝F(xiàn)在 JavaScript 不能改變系統(tǒng)級(jí)的明暗模式,只能獲取和監(jiān)聽(tīng)模式變化,所以手動(dòng)操作鐵定不能靠 prefers-color-scheme 了。

          我們需要反過(guò)來(lái)通過(guò)?JavaScript?獲取 color-scheme 然后告訴 CSS 明暗模式發(fā)生變化,這樣的變化包括系統(tǒng)級(jí)的改變和用戶(hù)在網(wǎng)頁(yè)選擇改變。

          首先把兩組變量的作用范圍改為 class:

          .light-theme {  --linkColor: #ec9bab;  --fontColor: #ecc3cb;  --codeBlock: #3c495b;  --code: #c3c7cb;  --divider: #3e4b5e;}.dark-theme {  --linkColor: #683741;  --fontColor: hsl(284, 20%, 30%);  --codeBlock: #3c495b;  --code: #c3c7cb;  --divider: #eee;}

          下面這一段代碼我寫(xiě)在 Layout.js 的 componentDidMount 中,只有這里才是服務(wù)器渲染的范圍之外。

          // setTheme 的實(shí)現(xiàn)setTheme = themeName => {  localStorage.setItem('theme', themeName)  document.documentElement.className = themeName + '-theme'  this.setState({    theme: themeName,  })}// 第一部分let localTheme = localStorage.getItem('theme')if (localTheme) {  if (localTheme === 'dark') {    this.setTheme('dark')  } else {    this.setTheme('light')  }} else if (window.matchMedia) {  if (window.matchMedia('(prefers-color-scheme: dark)').matches) {    this.setTheme('dark')  } else {    this.setTheme('light')  }} else {  // default light  this.setTheme('light')}// 第二部分const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)')darkModeMediaQuery.addListener(e => {  const darkModeOn = e.matches  if (darkModeOn) {    this.setTheme('dark')  } else {    this.setTheme('light')  }})

          先講 setTheme 的實(shí)現(xiàn):

          數(shù)據(jù)持久化

          實(shí)現(xiàn)設(shè)置整個(gè)文檔的 class,然后 CSS 根據(jù) class 配置變量(而不是方案 1 的媒體查詢(xún))

          修改組件狀態(tài)

          第一部分是頁(yè)面初始化時(shí)處理頁(yè)面主題的邏輯:

          首先查詢(xún)有無(wú)被保存到 localstorage 的主題,有的話(huà)直接使用

          沒(méi)有的話(huà)使用 JavaScript 查詢(xún)系統(tǒng)明暗方案,然后按系統(tǒng)配置設(shè)定

          上面兩種都不可行的情況下默認(rèn)使用 light

          第二部分是 JavaScript 監(jiān)聽(tīng)系統(tǒng)明暗方案修改,響應(yīng)式地改變頁(yè)面的明暗方案(意味著不需要刷新頁(yè)面)

          剩下的切換按鈕就沒(méi)什么特別的,所以不放代碼了。

          hack

          最后附帶一個(gè)處理畫(huà)面閃爍的方法。

          雖然已經(jīng)在樣式添加 transition 屬性,但是從 JavaScript 程序知道用戶(hù)需要的明暗模式前仍然有一段空擋。如果用戶(hù)選擇了黑暗模式,就會(huì)造成畫(huà)面先是明亮模式,然后幾百毫秒后變?yōu)楹诎的J降膶擂尉置妗?/span>

          我的解決方案是先把頁(yè)面 display 設(shè)為 none,在判斷并設(shè)置完頁(yè)面 class 之后再將頁(yè)面設(shè)為可見(jiàn),這樣就避免了畫(huà)面閃爍,但是頁(yè)面展示時(shí)間會(huì)慢一點(diǎn)點(diǎn)點(diǎn)點(diǎn)。

          document.documentElement.style.display = 'none'// 同步的判斷程序document.documentElement.style.display = 'block'



          本文完?

          瀏覽 51
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  做爱网站免费 | 亚洲看片 | 色多多视频在线观看 | 97色婷 | 亚洲第一黄色视频 |