比較 Next.js 中的樣式方法
已發表: 2022-03-10正如您可能知道的,關於 CSS-in-JS 有許多不同的觀點,而且我們都對這個主題有一種或另一種的看法,這可能與框架作者的看法大不相同。
Next.js是創建新 React 應用程序時推薦的工具鏈之一。 像 Next 這樣的工具有一個簡單的目標,即在編寫 React 應用程序時抽像出常見的冗餘任務。 這有助於開發人員更多地專注於編寫代碼,而不是重新發明輪子。 雖然這通常是一件好事,但開始時也可能有點乏味。 一方面,學習抽像是一個障礙,雖然在 Next 中有一大堆(路由、數據獲取……),但一個經常被忽視的是樣式。
為了服務更廣泛的受眾,Next.js 支持多種方式來設置組件樣式。 無論你是屬於 Utility 優先還是 CSS-in-JS 黨都不是 Next 關心的問題,它關心的是你如何將你的選擇注入到它的 API 中。
本文的目的是幫助您了解如何在 Next 應用程序中設置樣式。 我們將使用不同的方法來處理比較。 我們將在我設置的圖書應用程序中實現不同類型的樣式。 我們將要研究的樣式方法包括:
- 全球 CSS,
- SASS/SCSS,
- 組件級 SASS/SCSS,
- 組件級 CSS(CSS 模塊),
- 樣式化組件,
- 樣式化的 JSX,
- 情感。
先決條件
在我們開始我們的造型之旅之前,您需要了解一些 Next 細微差別。
-
_app.js
這是一個位於 pages 文件夾中的自定義組件。 Next.js 使用這個組件來初始化頁面。 -
_document.js
與_app.js
一樣,_document.js
是 Next.js 用來增強應用程序<html>
和<body>
標記的自定義組件。 這是必要的,因為 Next.js 頁面跳過了周圍文檔標記的定義。 -
_.babelrc
如果存在,Next.js 使用此文件作為某些內部配置的單一事實來源,並授予您擴展它的權限。
請記住,如果在添加_app.js
文件之前您的服務器正在運行,那麼您需要重新啟動它。
使用create-next-app
使用create-next-app
創建 Next 應用程序非常簡單,只需執行以下步驟:
- 全局安裝
create-next-app
。
yarn global add create-next-app // Installs create-next-app globally
- 創建一個名為style-in-next的新 Next 應用。
create-next-app styling-in-next // Creates a new Next app named styling-in-next
- 將目錄更改為新站點。
cd styling-in-next // Switch directory into the new Next app
- 運行站點。
yarn dev -p 3000 // Instruct Next to run on port 3000
有關創建和運行 Next 應用程序的更多信息,請參閱文檔。
該應用程序現在應該在https://localhost:3000
上運行。
演示庫
隨著我們的進展,我們將通過對每本書應用不同的樣式方法來構建一個人為的書架。 最終結果將如下所示:
上圖顯示了 6 本書; 每本書都有自己的組件,然後我們將為每本特定的書應用特定的樣式類型,即,書 1 將使用全局樣式,而書 2 將使用另一個樣式。 通過這種方式,我們將了解這些樣式中的每一個如何工作以及如何使用它們。 這將幫助您更好地決定選擇什麼選項。
為簡單起見,我搭建了一個 GitHub 存儲庫供您學習。 你可以在這裡抓住它。
對create-next-app
生成的默認啟動器也進行了一些更改。 諸如情感、全局、模塊、樣式組件等文件夾已添加到styles
文件夾中 - 及其相應的樣式文件 - 以及包含多個組件的components
目錄。
修改了index.js
文件以import
和render
所需的components
,並且每個組件的結構都類似於下圖所示。
如果您克隆並運行了演示存儲庫,您的頁面應該如下所示:
把所有這些都排除在外,讓我們開始造型吧。
全球風格
當你開始一個新的 web 項目時,你通常會做的一件常見的事情是重置或規範化你的 CSS,以便在瀏覽器之間有一個統一的起始位置。 這是一個使用全局 CSS 而不用擔心範圍的完美示例。
- 使用擴展的 Minimal CSS Reset 更新
styles/global/globals.css
。
/* styles/global/globals.css */ html { box-sizing: border-box; font-size: 16px; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; } *, *:before, *:after { box-sizing: inherit; } body, h1, h2, h3, h4, h5, h6, p, ol, ul { margin: 0; padding: 0; font-weight: normal; } h1, h2, h3, h4, h5, h6 { font-weight: bold; } ol, ul { list-style: none; } img { max-width: 100%; height: auto; } a { color: inherit; text-decoration: none; }
- 在
pages/_app.js
中導入 CSS 重置styles/global/globals.css
/global/globals.css。
// pages/_app.js import "../styles/global/globals.css"; function MyApp({Component, pageProps}) { return <Component {...pageProps} />; } export default MyApp;
全局樣式只能在pages/_app.js
中導入。 這是直接合乎邏輯的,因為這些樣式將應用於應用程序中的所有pages
和components
——無論你在哪裡導入它們——所以最好有一個單一的 [import] 真實來源,以保持事情簡單明了,和/或如果出現問題錯誤的。
在這一點上,我們的書架沒有太多的視覺變化,因為我們只進行了標準化更改。 您可能會注意到的一件事是字體和間距的變化。
SASS/SCSS
Next.js 還允許使用帶有.sass
或.scss
擴展名的 SASS 進行樣式設置。 安裝 Sass 是必需的。 就像全局樣式一樣,它們只能在pages/_app.js
中導入。
- 安裝 Sass 包。
yarn add sass
- 更新
styles/scss/bookshelf.scss
。
// styles/scss/bookshelf.scss .the-bookshelf { width: 100vw; height: 100vh; background-color: #e3e3e3; display: flex; justify-content: center; align-items: center; .bookshelf-wrap { > .bookshelf { box-shadow: inset 0 -20px #7b5019; padding-bottom: 20px; display: flex; align-items: flex-end; } [class*="book"] { font-size: 32px; letter-spacing: -0.045em; display: flex; transition: 0.2s; &:hover { transform: none; } } .book-info { text-transform: uppercase; writing-mode: sideways-rl; display: flex; justify-content: space-around; flex: 1; align-items: center; font-weight: bold; padding: 16px 0; .title { font-weight: inherit; font-size: 20px; } .author { font-weight: inherit; font-size: 15px; } } } }
- 同時更新
styles/sass/bookone.sass
和styles/sass/booktwo.sass
,如下所示:
// styles/sass/bookone.sass .book-one color: #f00 width: 78px height: 350px transform: rotate(-4deg) margin-left: 16px margin-right: 23px background-color: black
// styles/sass/booktwo.sass .book-two color: #781e0b width: 38px height: 448px margin-right: 23px background-color: #ffab44
SASS ( .sass
) 基於縮進。 為了使格式化更容易,您可以安裝此 VSCode Extension for SASS 文件支持(格式化、語法高亮...)
- 在
pages/_app.js
中導入三個樣式文件styles/scss/bookshelf.scss
bookshelf.scss、styles/sass/bookone.sass
和styles/sass/booktwo.sass
booktwo.sass。
// pages/_app.js import "../styles/globals.css"; import "../styles/scss/bookshelf.scss"; import "../styles/sass/bookone.sass"; import "../styles/sass/booktwo.sass"; function MyApp({Component, pageProps}) { return ; } export default MyApp;
// pages/_app.js import "../styles/globals.css"; import "../styles/scss/bookshelf.scss"; import "../styles/sass/bookone.sass"; import "../styles/sass/booktwo.sass"; function MyApp({Component, pageProps}) { return ; } export default MyApp;
我們的書架開始成型。 應用樣式後,第一本書和第二本書應按預期設置樣式和顯示。
CSS 模塊
CSS Modules 是一個組件級的 CSS,它內置在 Next 中,可以通過使用.module.css
擴展名命名樣式文件來激活。 也可以使用帶有.module.sass
或.module.scss
擴展名的 SASS/SCSS 的 CSS 模塊。
讓我們用它來設置components/BookThree.js
組件的樣式。
- 更新
styles/modules/BookThree.module.css
。
/* styles/modules/BookThree.module.css */ .book-three { color: #df66c3; width: 106px; height: 448px; margin-right: 23px; background-color: #153086; transform: rotate(-4deg); }
- 在
components/BookThree.js
中導入styles/modules/BookThree.module.css
BookThree.module.css,並應用.book-three
類。
// components/BookThree.js import BookThreeStyles from "../styles/modules/BookThree.module.css"; export default function BookThree() { return ( <div className={BookThreeStyles["book-three"]}> <div className="book-info"> <p className="title">the revolt of the public</p> <p className="author">Martin Gurri</p> </div> </div> ); }
在 CSS 模塊中訪問類名類似於 JavaScript 中的屬性訪問器——使用點或括號表示法。 這裡我們導入BookThreeStyles
,然後使用括號符號來應用我們在styles/modules/BookThree.module.css
文件中的樣式。
如果選擇器(在本例中為類名)被正確訪問,那麼現在應該設置第三本書的樣式。
情感
Emotion 是一個 CSS-in-JS 庫,與任何其他 CSS-in-JS 一樣,允許您使用 JavaScript 編寫 CSS 樣式。
讓我們用它來設置components/BookFour.js
組件的樣式。
- 安裝包:
@emotion/core
、@emotion/styled
、emotion
、emotion-server
。
yarn add @emotion/core @emotion/styled emotion emotion-server
- 更新
styles/emotion/StyledBookFour.js
。
// styles/emotion/StyledBookFour.js import styled from "@emotion/styled"; export const StyledBookFour = styled.div` color: white; width: 38px; height: 400px; margin-left: 20px; margin-right: 10px; background-color: #2faad2; transform: rotate(4deg); `;
從@emotion/styled
導入styled
後,我們導出StyledBookFour
樣式組件——不要與其他 CSS-in-JS 樣式組件混淆——使用styled.div
中的styled
情感方法進行了增強。 然後我們可以在下面的下一步中使用<StyledBookFour/>
。
了解有關情感樣式化功能的更多信息。
- 使用
<StyledBookFour/>
類似於使用任何其他 React 組件。 在components/BookFour.js
中導入styles/emotion/StyledBookFour.js
StyledBookFour.js,並應用StyledBookFour
組件。
// components/BookFour.js import {StyledBookFour} from "../styles/emotion/StyledBookFour"; export default function BookFour() { return ( <StyledBookFour className="book-four"> <div className="book-info"> <p className="title">the man died</p> <p className="author">wole soyinka</p> </div> </StyledBookFour> ); }
有了足夠的情感,第四本書應該是這樣的風格。
樣式化的 JSX
與 Global CSS 和 CSS-Modules 一樣,Styled-JSX 無需任何額外設置即可與 Next.js 一起使用。 如果有幫助,Styled-JSX 也是 Vercel 提供的基於組件的 CSS,Next.js 的創建者也是如此。
讓我們用它來設置components/BookFive.js
組件的樣式。
為了簡單起見,我們在這裡使用 styled-jsx 的內部模式。 通過將jsx
傳遞給<style/>
組件,我們可以像使用.book-five
一樣編寫盡可能多的 CSS,並且樣式被本地化到<BookFive/>
組件的額外好處。
// components/BookFive.js export default function BookFive() { return ( <div className="book-five"> <div className="book-info"> <p className="title">there was a country</p> <p className="author">Chinua Achebe</p> </div> <style jsx>{` .book-five { color: #fff; width: 106px; height: 448px; margin-right: 23px; background-color: #000; transform: rotate(4deg); } `}</style> </div> ); }
就這樣,第五本書採用了它的樣式。
樣式化的組件
Styled-Component 和 Emotion 一樣,也是一個 CSS-in-JS 庫,允許您使用 JavaScript 編寫 CSS 樣式。 設置它有點複雜。
- 首先,安裝
babel-plugin-styled-components
和styled-components
。
yarn add babel-plugin-styled-components styled-components
- 在應用的根目錄下創建一個
.babelrc
文件,以及一個pages/_document.js
文件,如下圖之前(左)和之後(右)所示。
- 更新
.babelrc
文件以包含next/babel
預設並包含styled-components
插件,並啟用服務器端渲染(ssr)。
// .babelrc { "presets": ["next/babel"], "plugins": [ [ "styled-components", { "ssr": true } ] ] }
- 通過將服務器端呈現的樣式註入
<head>
來更新pages/_document.js
。
請記住,下面的代碼片段 ( pages/_document.js
) 是 styled-components 與 Next.js 一起使用的必需邏輯。 您幾乎無需執行任何操作,只需複制 styled-components 文檔中指出的邏輯即可。
// pages/_document.js import Document from "next/document"; import {ServerStyleSheet} from "styled-components"; export default class MyDocument extends Document { static async getInitialProps(ctx) { const sheet = new ServerStyleSheet(); const originalRenderPage = ctx.renderPage; try { ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />), }); const initialProps = await Document.getInitialProps(ctx); return { ...initialProps, styles: ( <> {initialProps.styles} {sheet.getStyleElement()} </> ), }; } finally { sheet.seal(); } } }
在更新.babelrc
和pages/_document.js
,我們現在可以開始使用 styled-components。
- 更新
styles/styled-components/StyledBookSix.js
。
styled
是一種內部實用方法,可將樣式從 JavaScript 轉換為實際的 CSS。 <StyledBookSix/>
可以用作任何其他 React 組件。
// styles/StyledBookSix.js import styled from "styled-components"; const StyledBookSix = styled.div` color: #fff; width: 106px; height: 448px; margin-right: 23px; background-color: rebeccapurple; `; export default StyledBookSix;
了解有關如何在 React 中使用樣式化組件的更多信息。
- 在 components/BookSix.js 中導入
styles/styled-components/StyledBookSix.js
components/BookSix.js
,使用導入的 styled-components<StyledBookSix/>
。
// components/BookSix.js import StyledBookSix from "../styles/styled-components/StyledBookSix"; export default function BookSix() { return ( <StyledBookSix className="book-six"> <div className="book-info"> <p className="title">purple hibiscus</p> <p className="author">chimamanda ngozi adichie</p> </div> </StyledBookSix> ); }
第一步到第六步完成後,第六步應該樣式化,書架完成:
而已。
如果一切順利,那麼您應該擁有完整的書架,其中包含等待閱讀的書籍。
- 您可以在 GitHub 上獲取完整代碼 →
結論
在我自己使用 Next.js 時,全局樣式和样式組件通常就足夠了。 但毫無疑問,所有這些方法都有其優點和缺點。 當你決定使用什麼方法時,請記住:最後,它都是 CSS。 在這一點上,我相信您可以確定在您的下一個項目中哪種模式最適合您。
資源
我發現要學習使用 Next.js 設置樣式方法,沒有比它的官方文檔更好的地方了。
但也有各種樣式方法的特定存儲庫。 您可以通過各種存儲庫了解更多信息,或檢查更新,因為事情可能會隱身更改。
- 順風 CSS
- CSS 模塊
- 較少的
- 手寫筆
- 帶有情感的 Tailwind CSS
- Styletron
- 魅力
- CXS
- 阿芙羅狄蒂
- 費拉
- 樣式化的 JSX