<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>

          【CSS】2083- Tailwind輕松實現(xiàn)夜間模式,能跟隨系統(tǒng)又能手動控制!

          共 14702字,需瀏覽 30分鐘

           ·

          2024-06-23 10:32

          作者:evanryuu
          原文:https://juejin.cn/post/7312727134297210914

          通過本文,你將會收獲到:

          1. 如何讓vscode不會再對 @tailwind , @apply 之類的屬性報錯
          2. 如何讓你的應用既能跟隨系統(tǒng)設(shè)置,又能手動設(shè)置夜間模式

          如果本文對你有所幫助,希望你能動動小手點個免費的贊,這會讓我更有動力進行寫作,謝謝你!

          VSCode配置:

          這一步可以讓你的 @apply@tailwind 之類的 @ 屬性都不會報錯,并有提示

          image.png
          image.png
          1. 在項目根目錄下新建 .vscode 文件夾
          2. 配置settings.json
              {
                "css.customData": [".vscode/tailwind.json"]
              }
          1. 配置tailwind.json
              {
                "version"1.1,
                "atDirectives": [
                  {
                    "name""@tailwind",
                    "description""Use the `@tailwind` directive to insert Tailwind's `base`, `components`, `utilities` and `screens` styles into your CSS.",
                    "references": [
                      {
                        "name""Tailwind Documentation",
                        "url""https://tailwindcss.com/docs/functions-and-directives#tailwind"
                      }
                    ]
                  },
                  {
                    "name""@apply",
                    "description""Use the `@apply` directive to inline any existing utility classes into your own custom CSS. This is useful when you find a common utility pattern in your HTML that you’d like to extract to a new component.",
                    "references": [
                      {
                        "name""Tailwind Documentation",
                        "url""https://tailwindcss.com/docs/functions-and-directives#apply"
                      }
                    ]
                  },
                  {
                    "name""@responsive",
                    "description""You can generate responsive variants of your own classes by wrapping their definitions in the `@responsive` directive:\n```css\n@responsive {\n  .alert {\n    background-color: #E53E3E;\n  }\n}\n```\n",
                    "references": [
                      {
                        "name""Tailwind Documentation",
                        "url""https://tailwindcss.com/docs/functions-and-directives#responsive"
                      }
                    ]
                  },
                  {
                    "name""@screen",
                    "description""The `@screen` directive allows you to create media queries that reference your breakpoints by **name** instead of duplicating their values in your own CSS:\n```css\n@screen sm {\n  /* ... */\n}\n```\n…gets transformed into this:\n```css\n@media (min-width: 640px) {\n  /* ... */\n}\n```\n",
                    "references": [
                      {
                        "name""Tailwind Documentation",
                        "url""https://tailwindcss.com/docs/functions-and-directives#screen"
                      }
                    ]
                  },
                  {
                    "name""@variants",
                    "description""Generate `hover`, `focus`, `active` and other **variants** of your own utilities by wrapping their definitions in the `@variants` directive:\n```css\n@variants hover, focus {\n   .btn-brand {\n    background-color: #3182CE;\n  }\n}\n```\n",
                    "references": [
                      {
                        "name""Tailwind Documentation",
                        "url""https://tailwindcss.com/docs/functions-and-directives#variants"
                      }
                    ]
                  }
                ]
              }

          來源:github.com/tailwindlab…[1]

          思路

          方案1: 僅使用dark: 切換夜間模式

          我們在 tailwind 中可以很輕松地靠類名去實現(xiàn)切換:

          <div class="bg-white dark:bg-black">...</div>

          但是我們并不希望每個地方都要我們?nèi)懀驗槿绻覀円O(shè)置n個屬性,就要寫2n個類名

          <div class="bg-white dark:bg-black" />

          所以會超出預想的長。

          另外的問題是,如果我們將來希望去實現(xiàn)主題色的話,我們還要 bg-white dark:bg-black some-theme:bg-navy (假設(shè)有 some-theme: 這個東西),就更多了。

          那有什么方法可以幫我們解決這個問題呢?

          方案2: 利用 @apply 自定義類名實現(xiàn)切換

          換一個思路,如果我們能有一個 bg-theme 這樣的類名,自動幫我們做這件事,是不是就解決了呢?

          我們利用 @apply 的話就可以很簡單地寫出來下面的原子CSS:

          .bg-theme {
          @apply bg-white dark:bg-black;
          }

          哈!問題解決了…嗎?

          要知道這樣寫出來的類名在vscode是沒有提示的,因為tailwind并不會自動去找css文件然后掃描里面的看起來像原子CSS的類名的,vscode 的tailwind插件是通過 tailwind.config. 文件工作的,只有在 tailwind.config. 里面有定義的東西才會有提示。

          那我們可以這樣嗎?

              // tailwind.config.js
              module.exports = {
                ...
                theme: {
                  extend: {
                    colors: {
                      theme'white dark:black'
                    }
                  }
                }
                ...
              }

          很遺憾,dark:畢竟是類名而不是顏色值,因此tailwind并不支持這樣的寫法。

          但是!Tailwind是支持CSS變量的。比如你可以寫成

              // tailwind.config.js
              ...
                    colors: {
                      theme'var(--theme-color)'
                    }
              ...

          有了這個功能,這里就可以引入第三個方案

          方案3:媒體查詢 + CSS變量

          我們知道如果用戶的系統(tǒng)設(shè)置為深色模式的話,我們是可以通過媒體查詢屬性 prefers-color-shceme: dark讀取到的,因此我們就能以此為根據(jù)寫出日間/夜間模式兩套變量

          :root {
            --theme-color: white;
          }

          @media (prefers-color-scheme: dark) {
            :root {
              --theme-color: black;
            }
          }
              // tailwind.config.js
                      colors: {
                        theme'var(--theme-color)',
                      },

          這樣寫出來的tailwind配置,不僅可以直接給bg / text / … 等等屬性使用,更重要的是,vscode這會兒有提示了!

          Kapture 2023-12-16 at 18.57.21.gif

          這是一件非常棒的事情!并且,當我們使用css變量之后,我們要切換主題也很方便。

          :root {
            --blue-400#4489f6;
            --blue-500#0070f3;
          }

          @media (prefers-color-scheme: dark) {
            :root {
              --blue-400#2d79f0;
              --blue-500#063784;
            }
          }
              // tailwind.config.js
                      colors: {
                        theme'var(--theme-color)',
                        blue: {
                          400'var(--blue-400)',
                          500'var(--blue-500)',
                        }
                      },

          當然,你也可以不修改顏色,而是更改類名對應的色值

              :root {
                --theme-blue#4489f6;
              }

              @media (prefers-color-scheme: dark) {
                :root {
                  --theme-blue#0070f3;  
                }
              }
              // tailwind.config.js
                      colors: {
                        theme'var(--theme-color)',
                        'theme-blue''var(--theme-blue)'
                      },

          你還可以設(shè)置同名的屬性名分別給文本和背景

          // tailwind.config.js
                  textColor: {
                    'theme''var(--theme-color-invert)'
                  },
                  backgroundColor: {
                    'theme''var(--theme-color)',
                  },

          這個方案最大的缺點就是,本來只需要一個tailwind.config 的文件,現(xiàn)在還需要多個 css 文件(main.css / theme-light.css / theme-dark.css / …

          即使我們可以使用一個入口main.css引入其余的css,這也會導致項目中需要多一行 import 'my-tailwind.css' 之類的文件,所以我個人認為仍然是有優(yōu)化空間的。

          方案4: 類名 + 媒體查詢 + css變量

          實際上,通過前面的流程,我們已經(jīng)可以比較完美地支持系統(tǒng)的深色模式了,但是有的時候我們的用戶可能只希望在我們的網(wǎng)站上開啟深色模式,所以我們要提供給用戶手動切換的能力。

          這個時候dark就要以類名的形式添加在html上,而不是單純使用媒體查詢了,那我們可以大概思考一下我們的需求:

          1. 剛進入頁面時的夜間模式要以用戶的設(shè)置為準
          2. 用戶可以手動切換日間/夜間模式
          3. 用戶手動切換之后,仍然可以跟隨系統(tǒng)進行變化

          由此,我們可以寫一個hook useDark 做下面的事情:

          1. 獲取當前系統(tǒng)的dark mode是否開啟,設(shè)為 systemDark,做useState默認值
          2. const [dark, setDark] = useState<boolean>(systemDark)
          3. const toggleDark = () => setDark(!dark) ,用來手動切換日間/夜間模式
          4. 監(jiān)聽 mediaQuery ,讓 dark 跟隨用戶系統(tǒng)設(shè)定變化而變化
          5. 聲明并暴露 dark變量 以及 toggleDark 方法

          最后我們的成果如下:

          useDark 可以參考這里[2]

          使用state導致的問題

          如果有兩個組件A和B同時使用useDark的話,那么就可能會有bug。因為此時dark是組件內(nèi)部的state,這就導致了組件A點擊之后,只有組件A自己的dark變化了,組件B的dark是不會跟著變的。

          如何解決這個問題,各位自由發(fā)揮就好了??localStorage,全局狀態(tài)管理,或者別的什么方法,都可以。

          方案對比

          至此,我們來對比下上述的幾個方法

          方案對比 僅使用 dark: 選擇器 @apply 自定義類名 媒體查詢+css變量 類名+監(jiān)聽媒體查詢+css變量
          配置簡單 ?????? ???? ???? ??
          開發(fā)友好 ?? ?? ?????? ??????
          主題拓展 ?? ?? ???? ??????
          適配性(系統(tǒng) / 用戶設(shè)置) ???? ???? ???? ??????

          思考:如何實現(xiàn) useTheme?

          我們現(xiàn)在是基于類名實現(xiàn)深色模式的,那我們其實也很容易切換主題。比如

          :root {
            --theme-color: white;
          }

          .dark {
            --theme-color: black;
          }

          .violet {
            --theme-color: violet;
          }

          只要我們對useDark稍作改動,就可以變?yōu)閡seTheme了!至于如何實現(xiàn),大家也可以自己嘗試。

          總結(jié)

          建議使用類名+監(jiān)聽媒體查詢+css變量的形式,除了剛開始的配置較為復雜,其余時候都很爽快。無論是開發(fā)使用的方便程度還是主題的拓展性。

          由于我們項目中接入了 next-themes ,所以也省去了自己開發(fā) useDark ,畢竟它自帶了 useTheme 的鉤子。最后的解決方案就是

          1. base.css 配置色值、字號等變量
          2. theme-.css 配置各個主題下的設(shè)計類名
          3. main.css 引入
          4. tailwind.config. 配置別名

          如果你覺得本文有錯誤,也歡迎你在評論區(qū)指出,我們可以友好討論??

          參考資料
          [1]

          https://github.com/tailwindlabs/tailwindcss/discussions/5258#discussioncomment-1979394: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Ftailwindlabs%2Ftailwindcss%2Fdiscussions%2F5258%23discussioncomment-1979394

          [2]

          https://github.com/evanryuu/tw-dark-usecase/blob/main/src/hooks/useDark.ts: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fevanryuu%2Ftw-dark-usecase%2Fblob%2Fmain%2Fsrc%2Fhooks%2FuseDark.ts

          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  黄片在线免费网站 | 国产精品久久久久久久久久乐趣播 | 大操在线| 六月丁香综合在线 | 操逼视频免费在线观看 |