1. 前言
本篇將會介紹 Tailwind CSS 的響應式開發,如何用一套程式碼實現多終端的樣式切換。
2. 媒體查詢
在以往,我們使用 CSS3 進行開發時會透過媒體查詢來實現。比如有程式碼如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> /* 樣式程式碼 */ </style> </head> <body> <div> <div id="app"></div> </div> <script> class App { constructor() { this.el = document.getElementById('app'); this.init(); } init() { this.render(); this.watch(); } render() { this.el.innerHTML = 'first render'; } watch() { window.addEventListener('resize', () => { const width = window.innerWidth; this.el.innerHTML = `${width}px`; }); } } const app = new App(); </script> </body> </html>
這是一個簡單的 Demo,當用戶調整瀏覽器寬度時就會更新寬度顯示,而且在不同的寬度下背景顏色發生變化。
2.1 @media
樣式程式碼是這樣的:
* { margin: 0; padding: 0; box-sizing: border-box; } #app { display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #fff; font-size: 48px; } @media screen and (min-width: 640px) { #app { background-color: red; } } @media screen and (min-width: 768px) { #app { background-color: orange; } } @media screen and (min-width: 1024px) { #app { background-color: yellow; } } @media screen and (min-width: 1280px) { #app { background-color: green; } } @media screen and (min-width: 1536px) { #app { background-color: blue; } }
上面用到了 CSS3 的一個特性:@media
,screen
表示裝置型別為螢幕,透過 and
關鍵字來並列多個配置。min-width
表示最小寬度,如果按照一把直尺的刻度去理解,最小寬度就是一條線段的左側較小值,往右,寬度大於這個值時就會應用對應的樣式宣告。
2.2 斷點
上面的多個媒體查詢定義決定了響應式的不同斷點,這些斷點被稱為 breakpoints,這是每一個具備響應式系統的 UI 規範都要考慮的。上面的 5 個斷點對應如下:
small:640px 起,橫向模式顯示狀態的手機(640px 到下一個斷點顯示為紅色)
medium:768px 起,平板(768px 到下一個斷點顯示為橙色)
large:1024px 起,電腦(1024px 到下一個斷點顯示為蛋心色)
x large:1280px 起,大型電腦(1280px 到下一個斷點顯示為綠色)
2x large:1536px 起,更大型電腦(1536px 到下一個斷點顯示為藍色)
2.3 mobile first
mobile first 是一個比較通用的概念——優先考慮移動裝置,隨著螢幕變大再去適應更大的裝置寬度。這主要依靠上面所說的斷點機制,下面來看在 Tailwind CSS 中如何使用響應式。
3. Tailwind CSS 中的響應式系統
在 Tailwind CSS 中不需要像上面那樣寫複雜的媒體查詢宣告程式碼了,而是透過提前預設好的 CSS 類名來定義元素的樣式。
3.1 斷點
Tailwind CSS 的斷點和 2.2 中提到的斷點一樣,與類名的對應關係如下:
3.2 斷點字首:類名
透過 斷點字首:類名
的形式就能定義元素的響應式樣式,下面是一個簡單的使用案例:
'use client'; import useWindowWidth from '@/hooks/useWindowWidth'; export default function Home() { const width = useWindowWidth(); return ( <main className="text-center sm:bg-red-300 md:bg-orange-300 lg:bg-yellow-300 xl:bg-green-300 2xl:bg-blue-300"> <div>hello tailwind css</div> <div>current width: {width}px</div> </main> ); }
以 Next.js 中的 React 為例:
sm:bg-red-300
表示在 640px 以上時為紅色md:bg-orange-300
表示 768px 以上時為橙色…
其他依次類推,sm
、md
等都是斷點字首,冒號後面是想要定義的樣式類名。
最終效果如下所示:
需要注意的是,沒有加上斷點字首的類名預設是作用於所有裝置大小的,比如上面程式碼中的 text-center
,可以看到在任何大小下都是文字居中對齊的。
3.3 定義範圍
如果我只想在 sm
到 lg
的範圍內應用背景顏色怎麼辦?顯然只寫 sm:bg-red-300
是不行的,因為它表示的是大於 640px 寬度都會應用到紅色。
解決辦法是使用 *:max-*
(*
表示斷點字首)為它定義一段範圍:
<main className="text-center sm:max-lg:bg-red-300"> <div>hello tailwind css</div> <div>current width: {width}px</div> </main>
sm:max-lg:bg-red-300
表示在sm
到lg
這段範圍內(640px~1024px)應用紅色
4. 自定義配置
同樣在 tailwind.config.ts 中來配置各種自定義的規則,對於響應式的部分則在 theme.screens
中去定義。
4.1 覆蓋預設值
預設情況下斷點字首的配置如下所示:
/** @type {import('tailwindcss').Config} */ module.exports = { theme: { screens: { 'sm': '640px', // => @media (min-width: 640px) { ... } 'md': '768px', // => @media (min-width: 768px) { ... } 'lg': '1024px', // => @media (min-width: 1024px) { ... } 'xl': '1280px', // => @media (min-width: 1280px) { ... } '2xl': '1536px', // => @media (min-width: 1536px) { ... } } } }
覆蓋預設值的方法很簡單,直接在 theme.screens
中替換掉原來的值即可,例如:
theme: { screens: { sm: '576px', // => @media (min-width: 576px) { ... } md: '960px', // => @media (min-width: 960px) { ... } lg: '1440px', // => @media (min-width: 1440px) { ... } }, },
注意:預設值有 sm
、md
、lg
、xl
、2xl
等等,因此上面只寫了 sm
、md
、lg
三種,實際上能應用的也就只有這三種。因此,這不是覆蓋原來的某個斷點,而是直接覆蓋了 theme.screens
物件的所有值。
4.2 覆蓋原來值
如果只是想覆蓋掉某一個斷點,只需要在 theme.extend.screens
中修改,比如我想覆蓋 sm
斷點:
extend: { screens: { sm: '576px', // => @media (min-width: 576px) { ... } }, }
這樣,sm
的值就從 640px 變為 576px,因此,從 576px 開始,背景顏色就是紅色了:
4.3 新增更大的斷點
在 theme.extend.screens
中也可以新增更大範圍的斷點:
extend: { screens: { '3xl': '1600px', // => @media (min-width: 1600px) { ... } }, }
給 main
新增 3xl
的斷點:
<main className="text-center sm:bg-red-300 md:bg-orange-300 lg:bg-yellow-300 xl:bg-green-300 2xl:bg-blue-300 3xl:bg-slate-300"> <div>hello tailwind css</div> <div>current width: {width}px</div> </main>
效果如下:
4.4 新增更小的斷點
雖然更大的斷點可以透過 theme.extend.screens
來實現,但是更小的卻不可以這麼做,原因在於 extend
是向原來的內容進行追加,所以是在最後一位,而 tailwind 需要它們按照從小到大的順序排序。
在 tailwindcss
模組中有一個 defaultTheme
物件,這裏存放著預設斷點值,只要將預設值和自定義的更小範圍斷點結合在一起就可以實現了:
import type { Config } from 'tailwindcss'; import defaultTheme from 'tailwindcss/defaultTheme'; const config: Config = { // ... theme: { screens: { xs: '475px', ...defaultTheme.screens, }, }, }; export default config;
之後就可以使用 xs
了:
<main className="text-center xs:bg-purple-300 sm:bg-red-300 md:bg-orange-300 lg:bg-yellow-300 xl:bg-green-300 2xl:bg-blue-300 3xl:bg-slate-300"> <div>hello tailwind css</div> <div>current width: {width}px</div> </main>
xs:bg-purple-300
表示 475px 起背景顏色為紫色
效果如下:
4.5 定義斷點範圍
在 3.3 節透過 *:max-*
的方式實現了斷點範圍的控制,在配置檔案中還提供了一種更加快捷的方案:
theme: { screens: { sm: { min: '640px', max: '767px' }, // => @media (min-width: 640px and max-width: 767px) { ... } md: { min: '768px', max: '1023px' }, // => @media (min-width: 768px and max-width: 1023px) { ... } lg: { min: '1024px', max: '1279px' }, // => @media (min-width: 1024px and max-width: 1279px) { ... } xl: { min: '1280px', max: '1535px' }, // => @media (min-width: 1280px and max-width: 1535px) { ... } '2xl': { min: '1536px' }, // => @media (min-width: 1536px) { ... } }, }
預設情況下的斷點範圍較大,比如 sm
表示 640px 起,這樣一旦 md
等斷點都沒有去設定就會都應用 sm
的樣式了。像上面這樣的配置就控制了斷點的範圍使之更加符合響應式的本質。
有下面程式碼:
<main className="text-center sm:bg-red-300"> <div>hello tailwind css</div> <div>current width: {width}px</div> </main>
只有在螢幕寬度處於 640px ~ 767px 的範圍下,背景顏色才表現爲紅色。
5. 總結
這篇文章主要講解了傳統響應式和 TailwindCSS 中的響應式,有了 Tailwind 就不用再去寫媒體查詢了,這對於開發者來說是一個喜訊。在開發響應式方面最值得關注的就是斷點,控制好斷點也就控制好了響應式。除了上述提到的配置特性,還有自定義名稱、自定義多個範圍、自定義查詢等等,這類特性其實並不是開發必需的,只屬於靈活性的範疇,如果需要可以自行查閱文件。