25
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vue.jsでSPAサイトを作成するチュートリアル【4. CSS編】

Last updated at Posted at 2018-02-14

Vue.jsを使い始めていろいろできることが多くなってきたので、整理する意味も兼ねてチュートリアルにまとめます。
今回はコーポレートサイトを想定して作成していきます。
※記事が長くなったのでチュートリアルを分割しました。

目次

前提

  • タスクはnpm scriptsで一限管理
  • コマンドはyarnを使用
  • vue-cliwebpack-simpleを使用
  • CSSはSCSSを使用し用途に合わせてPostCSSを使用

バージョン

  • "vue": "^2.5.11"
  • "webpack": "^3.6.0"
  • "node-sass": "^4.7.2"
  • "postcss": "^6.0.16"
  • "stylelint": "^8.4.0"

CSSの環境構築

SassとPostCSSを使用するので以下のコマンドでパッケージを追加します。
※今回はautoprefixerでPostcSSの動作確認をおこないます。

$ yarn add -D node-sass postcss postcss-loader autoprefixer

PostCSSの設定ファイルを追加します。

postcss.config.js
module.exports = (ctx) => ({
  plugins: [
    require('autoprefixer')
  ]
});

webpackの設定ファイルを修正します。

webpack.config.js
var path = require('path')
var webpack = require('webpack')

module.exports = {
  // 省略
  module: {
    rules: [
    // 省略
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            'scss': [
              'vue-style-loader',
              'css-loader',
              'postcss-loader',  // ← 追加
              'sass-loader'
            ],
// 省略

Index.scssとAbout.scssで動作確認用のスタイルを記述します。

/src/pages/Index/Index.scss
.block {
  color: red;
  display: flex;
}

/src/pages/About/About.scss
.block {
  color: blue;
  display: flex;
}

ブラウザでindexとaboutをそれぞれ確認し、開発ツールでdisplayがプレフィックスがついていて、それぞれ赤文字、青文字になっていたら成功です。

ちなみに、前回vueファイル側でstyle部分にscopedを記述していました。

/src/pages/Index/Index.vue
<template
  lang="pug"
  src="./Index.pug"
/>

<script src="./Index.js" />

<style
  lang="scss"
  src="./Index.scss"
  scoped
/>

ページ単位では上書きされないようにローカルなスタイルにする意味でscopedを記述していました。
上書きさせたい場合、scopedを記述しなければ通常の記述になります。

参考:スコープ付き CSS

グローバルなCSSの環境構築

上記のCSSの設定はvueコンポーネントごとの個別用で使用し、全体で使用するスタイルは別で用意します。
※reset.css, normarize.css, 各共通コンポーネント等です。
CSSディレクトリを作成し、CSS設計をおこないます(以下は参考)

/src
  /css
    /base
      _variable.scss
      _mixin.scss
      _function.scss
      _base.scss
    /components
      _typography.scss
      _button.scss
      _icon.scss
      _form.scss
      _table.scss
    /modules
      _header.scss
      _footer.scss
    /layouts
      _container.scss
    /templates
      _temp-list.scss
    _temp-article.scss
    /vendor
      _normarize.scss
    style.sscss
  /layouts
    Default.vue
  /pages
    Index.vue
    Hoge.vue
  App.vue
  main.js
  router.js
  index.html
  その他設定ファイル等

cssファイルを読み込む記述を追加します。

/src/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>vue-skeleton</title>
    <link rel="stylesheet" href="/css/style.css"> <!-- ← 追加 -->
  </head>
  <body>
    <div id="app"></div>
    <script src="/js/bundle.js"></script>
  </body>
</html>

normalize.scssをダウンロードして以下に格納します。

/src/css/vendor/

グローバルなSCSSはwebpackとは別で監視したほうがwebpackに依存しなくて良いので、node-sassを使って監視します。

package.json
{
  // 省略
  "scripts": {
    "watch:server": "browser-sync start --config bs-config.js",
    "watch:file": "cpx \"./src/**/{*.html,*.jpg,*.png,*.gif,*.svg,*.eot,*.ttf,*.woff,package.json}\" ./dist",
    // ↓ 追加
    "watch:css": "node-sass src/css/style.scss dist/css/style.css -w --source-map true",
    // ↑ 追加
    "watch:js": "webpack -w",
    "start": "run-p watch:*",
    // 省略
  },
  // 省略
}

vue-body-classの追加

CSS設計をおこなう際に、ページごとにスタイルをテンプレートとして出し分けたい場合があります。
そんな時にbodyにページごとのclassを振って出し分けるのですが、vue-routerはrouter-view部分の差分変更をおこなうので、基本的にはbodyの操作をしないようになっていると思います。
そんな時にrouter-viewでpathの変更ごとにbodyのclass設定をおこなえるようにしたのがvue-body-classです。
さっそく追加しましょう。

$ yarn add vue-body-class

main.jsに追記しましょう。
この時、Vue.use(BodyClass, router)const router = ...の後に記述しないときちんと反応しないので気をつけましょう。

/src/main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import Routes from './router.js'
import BodyClass from 'vue-body-class' // ← 追記

Vue.use(VueRouter)

const router = new VueRouter({
  mode: 'history',
  routes: Routes
})

Vue.use(BodyClass, router) // ← 追記

const app = new Vue({
  router,
  render:h => h(App)
}).$mount('#app');

次にrouter.jsに実際に各ページに付与するclass名を追記していきましょう。

/src/router.js
export default [
  {
    path: '/',
    name: '',
    component: require('./layouts/Default.vue').default,
    children: [
      {
        path: '',
        name: 'index',
        meta: { bodyClass: 'page-index' }, // ← 追記
        component: require('./pages/Index/Index.vue').default,
      },
      {
        path: '/about/',
        name: 'about',
        meta: { bodyClass: 'page-about' }, // ← 追記
        component: require('./pages/About/About.vue').default
      },
      {
        path: '/service/',
        name: 'service',
        meta: { bodyClass: 'page-service' }, // ← 追記
        component: require('./pages/Service/Service.vue').default
      },
      {
        path: '/recruite/',
        name: 'recruite',
        meta: { bodyClass: 'page-recruite' }, // ← 追記
        component: require('./pages/Recruite/Recruite.vue').default
      },
      {
        path: '/contact/',
        name: 'contact',
        meta: { bodyClass: 'page-contact' }, // ← 追記
        component: require('./pages/Contact/Contact.vue').default
      }
    ]
  }
]

ブラウザで確認してページごとにbodyのclassが変更されていれば成功です。
ちなみに、親で付与したclassを子に引き継いだり上書きしたり、ということもできます。
詳しくは公式ドキュメントを参考にしてください。

参考:vue-body-class

stylelintの設定

グローバルなCSSとwebpack環境下のCSS両方にstylelintを設定します。

パッケージを追加します。

yarn add -D stylelint stylelint-webpack-plugin

stylelintの設定ファイルを用意します。
今回は以下を/srcに格納します。

stylelintの設定ファイル

エディタで監視する設定をおこないます。
以下を参考におこなってみてください。

PostCSSとstylelintの環境構築

グローバルなCSS

他所から持ってきたSCSSファイルにstylelintを反応させたくないので、.stylelintignoreを/src直下に作成して以下を記述します。

/src/css/vendor/**/*.scss

/src/cssのscssファイルでエラーや警告表示になる記述をして、stylelintがエディタで反応したら成功です。

webpack環境下のCSS

webpackの設定ファイルに追記します。

/src/webpack.config.js
// 省略
var StylelintPlugin = require('stylelint-webpack-plugin')

module.exports = {
  // 省略
  plugins: [
    new StylelintPlugin({
      files: ['**/*.vue', '**/*.scss']
    })
  ],
  // 省略
}

参考:A nice way to lint .vue files with Stylelint? #303

Index.vueやAbout.scssでstylelintがエディタで反応していたら成功です。
エラー・警告が出ている場所を確認して修正しましょう。

postcss-sortingの追加

プロパティ順をソートできるようにしましょう。
以下の記事を参考に導入しましょう。scssファイルでもいけます。

参考:PostCSS SortingでCSSの@ルールやプロパティの記述順を整理

まとめ

CSSは設定しやすくハンドリングが難しいので、設計がとても大事です。
scopedはどれに適用させるのか、共通コンポーネントのスタイルはどこに書くべきか、等の判断も必要になってくるかと思います。
全体を俯瞰し、破綻しにくく運用しやすい設計を意識すると良いでしょう。

25
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
29

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?