Nuxt.js 3.x 搭配 CSS Framework-以 Bootstrap 5 為例

本篇文章同步發表於 2023 iThome 鐵人賽:Nuxt.js 3.x 筆記-打造 SSR 專案

Bootstrap 版本:v5.3.1
Sass 版本:v1.63.6

在 Nuxt 專案中,我們可以自由選擇 CSS 預處理器、CSS 框架或是 UI Library 來定義樣式。在 CSS 框架百家爭鳴的時代,這幾年熱門的 Tailwind CSS、基於 Vue.js 開發的 Quasar、或是搭配 Vue3 開發的 Element Plus 都能快速上手,協助我們打造精美的網站。

由於工作上較常使用 Bootstrap 協作,本篇將以 Bootstrap 5 搭配 SCSS 進行說明。

廣告

Bootstrap 5 簡介

Bootstrap 有豐富的 Sass 變數、mixins、網格系統、元件、JS 插件,Bootstrap 5 與先前版本最大的不同,除了將 jQuery 從相依項目中移除,也新增 Utilities API(基於 Sass Maps 生成 Utilities Class),可以更簡易的管理或擴充樣式,不需手刻太多 CSS 即可完成多元、複雜的畫面。

套件安裝

npm install bootstrap
npm install sass

使用 Bootstrap 樣式搭配自訂樣式

assets/ 靜態資源目錄定義 SCSS,範例 assets/scss/app.scss,需注意 Bootstrap 樣式與自訂樣式引入順序:

不建議直接引入整包 bootstrap components bootstrap/scss/bootstrap ,選擇需要的樣式引入即可,避免 CSS 檔案過大,造成系統負擔

// assets/scss/app.scss

/** 1. 引入 functions,才能操控 color, svg, calc... */
@import "bootstrap/scss/functions";

/** 2. 自訂變數置於 bootstrap variables 前,覆蓋 bootstrap 變數 */
@import "./color";
@import "./variables";

/** 3. 引入 variables, mixins, root */
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import 'bootstrap/scss/maps';
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";

/** 4. 引入 utilities */
@import "~bootstrap/scss/utilities";

/** 5. 自訂、擴充、調整 utilities */
@import "./utilities";

/** 6. 引入需要的 bootstrap components */
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/tables";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/helpers";
/** ... */

/** 7. 使用 utilities 需引入 utilities api(將 sass map 轉換為 utility classes) */
@import "bootstrap/scss/utilities/api";

/** 8. 客製樣式置於最後,覆蓋前面的樣式 */
@import "./style";

自訂樣式檔案結構:

assets/
|—— scss/
|—— app.scss
|—— _color.scss
|—— _variables.scss
|—— _style.scss

自訂、擴充、調整 utilities:

透過 map-merge 合併 bootstrap utilities,詳細定義方式參考 官方文件

// assets/scss/utilities.scss
$utilities: map-merge(
$utilities,
(
"cursor": (
property: cursor,
class: cursor,
responsive: true,
values: auto pointer grab
)
)
);

配置全域共用 CSS

接著在 nuxt.config 配置全域共用 CSS,接下來整個專案 HTML 都能使用編譯後的樣式

// nuxt.config.js
export default defineNuxtConfig({
css: [
'@/assets/scss/app.scss'
],
postcss: { // CSS 屬性加上瀏覽器相容性前綴
plugins: {
autoprefixer: true
}
}
})

Nuxt 專案已內建 postcss,加上 autoprefixer: true 會自動為屬性加上瀏覽器相容性前綴
範例定義以下樣式:

.container {
display: flex;
}

編譯後的 CSS:

.container {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}

定義全域共用 Sass / SCSS 變數(搭配 Vite)

如果想在 .vue 檔內的 <style> 直接使用 Sass / SCSS 變數,需搭配 preprocessorOptions 進行配置

// nuxt.config.js
export default defineNuxtConfig({
vite: {
css: {
preprocessorOptions: {
scss: {
additionalData: `
@import "@/assets/scss/_color.scss";
@import "@/assets/scss/_variables.scss";
`
}
}
}
}
});
// assets/scss/_color.scss
$primary: #49240F;
$secondary: #E4A79D;

接著就可以在 SCF(單一元件檔)使用 SCSS 變數

// pages/hello.vue
<template>
<div>
<h1>Hello World</h1>
</div>
</template>

<style lang="scss" scoped>
h1 {
color: $primary;
}
</style>

加上 scoped,將樣式作用域限制在元件內,避免造成全域污染,如果希望樣式可以渲染到子元件,透過 :deep() 定義如下

:deep(h3) {
color: $primary;
}

使用 Bootstrap Plugins

plugins/ 目錄註冊 Bootstrap JavaScript Plugins

  1. 新增 plugins/bootstrap.client.js

注意:Nuxt 會自動引入(auto imports)plugins,bootstrap plugins 要限制在 client 端使用,否則會拋錯 document is not defined ,檔名需加上 .client 後綴

  1. 透過 Provide 定義全局變數,將需要的 Bootstrap Plugins 注入到 NuxtApp
// plugins/bootstrap.client.js
import * as bootstrap from 'bootstrap';
const { Modal, Collapse } = bootstrap;

export default defineNuxtPlugin(_nuxtApp => {
return {
provide: {
bootstrap: {
modal: element => new Modal(element),
collapse: element => new Collapse(element)
}
}
};
});
  1. 使用 Modal Plugins
// pages/about.vue
<template>
<div>
<div class="modal fade" tabindex="-1" ref="modalRef">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
...
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" data-bs-dismiss="modal">close</button>
</div>
</div>
</div>
</div>
<button type="button" class="btn btn-success" @click="showModal">
點我看 Modal
</button>
</div>
</template>

<script setup>
const { $bootstrap } = useNuxtApp();
const modalRef = ref(null);
let modal;
const showModal = () => {
modal.show();
};

onMounted(() => {
modal = $bootstrap.modal(modalRef.value);
});

onBeforeUnmount(() => {
// 加上 dispose,避免切換頁面時或是 HMR 看到殘留畫面
modal.dispose();
});
</script>

動態樣式

動態樣式定義方式同 Vue3,在 CSS 使用 v-bind function

// pages/hello.vue
<template>
<div>
<h1>hello</h1>
<h2>world</h2>
<button @click="theme.color = 'red'">change color</button>
</div>
</template>

<script setup>
const theme = ref({
color: 'green'
});
</script>

<style lang="scss" scoped>
h1, h2 {
color: v-bind('theme.color');
}
</style>

參考資源:

https://nuxt.com/docs/getting-started/styling
https://vite.nuxtjs.org/misc/common-issues#styleresources
https://getbootstrap.com/

廣告
Nuxt.js 3.x 自訂 Loading 效果 Nuxt.js 3.x 導入 I18n 實作多國語系

評論

廣告
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×