LoginSignup
91
81

More than 5 years have passed since last update.

Nuxt.js で CSS フレームワークを 3 つ試した。

Last updated at Posted at 2018-05-04

この記事は、 nuxt-community/express-template で新規作成したプロジェクトをベースに書いている。
この環境については、前回の記事で触れている。

今回、組み込んで見るのは

Vuetify 編

これ
https://www.npmjs.com/package/@nuxtjs/vuetify

まずは、インストール。

npm install --save @nuxtjs/vuetify
npm install --save @nuxtjs/font-awesome

1)nuxt.config.js に modulesvuetify を追加する。

  modules: [
    '@nuxtjs/vuetify',
    '@nuxtjs/font-awesome'
  ]

modules については ココ を参照。

  vuetify: {
    theme: {
      primary: '#3f51b5',
      secondary: '#b0bec5',
      accent: '#8c9eff',
      error: '#b71c1c'
    }
  }

theme の中身については ココ を参照。

2)node_modules/@nuxtjs/vuetify/index.js を少し変更する。

変更前

href: '//fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'

変更後(https: を追加する。)

href: 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'

これやらないと、 http://localhost:3000 での実行時に、Material Icons が読み込めない。
(ただ読み込めた時もあって少し混乱。。)

image.png

image.png

(追記)

上記の回避方法が微妙だなと、対策を考えていたら、また微妙な方法を思いついた。
1)で追加した nuxt.config.js の vuetify の中(theme と同じ階層)に下記を追加して、 Material Icons の読み込みを無効化する。
(node_modules/@nuxtjs/vuetify/index.js の修正は不要。)

    materialIcons: false

で、今度は、Material Icons を読み込む記述を追加する。
nuxt.config.js の head.link の配列に下記を追加する。

      {
        rel: 'stylesheet',
        type: 'text/css',
        href: 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'
      }

インストールしたパッケージをいじるよりいいのかな。。

※ただこの問題、自分の環境でのみ発生するような気もしている。※

3)layouts/default.vue を、下記で上書きする。

https://codepen.io/johnjleider/pen/KQrPKJ を元にした。

<template>
  <div id="app">
    <v-app id="inspire">
      <v-navigation-drawer fixed v-model="drawerRight" right clipped app>
        <v-toolbar flat>
          <v-list>
            <v-list-tile>
              <v-list-tile avatar>
                <v-list-tile-avatar>
                  <v-icon medium>account_circle</v-icon>
                </v-list-tile-avatar>
                <v-list-tile-content>
                  <v-list-tile-title class="title">
                    User
                  </v-list-tile-title>
                </v-list-tile-content>
              </v-list-tile>
            </v-list-tile>
          </v-list>
        </v-toolbar>
        <v-list dense>
          <v-list-tile @click.stop="right = !right">
            <v-list-tile-action>
              <v-icon>exit_to_app</v-icon>
            </v-list-tile-action>
            <v-list-tile-content>
              <v-list-tile-title>Open Temporary Drawer</v-list-tile-title>
            </v-list-tile-content>
          </v-list-tile>
        </v-list>
        <v-list dense class="pt-0">
        <v-list-tile v-for="item in items" :key="item.title" :to="item.url">
          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title>{{ item.title }}</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
      </v-navigation-drawer>
      <v-toolbar color="blue-grey darken-2" dark fixed app clipped-right>
        <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
        <v-toolbar-title>Toolbar</v-toolbar-title>
        <v-spacer></v-spacer>
        <v-toolbar-items class="hidden-sm-and-down">
          <v-btn flat v-for="item in items" :key="item.title" :to="item.url">
            {{ item.title }}
          </v-btn>
        </v-toolbar-items>
        <v-toolbar-side-icon @click.stop="drawerRight = !drawerRight"></v-toolbar-side-icon>
      </v-toolbar>
      <v-navigation-drawer fixed v-model="drawer" app>
        <v-toolbar flat>
          <v-list>
            <v-list-tile>
              <v-list-tile avatar>
                <v-list-tile-avatar>
                  <v-icon medium>account_circle</v-icon>
                </v-list-tile-avatar>
                <v-list-tile-content>
                  <v-list-tile-title class="title">
                    User
                  </v-list-tile-title>
                </v-list-tile-content>
              </v-list-tile>
            </v-list-tile>
          </v-list>
        </v-toolbar>
        <v-list dense>
          <v-list-tile @click.stop="left = !left">
            <v-list-tile-action>
              <v-icon>exit_to_app</v-icon>
            </v-list-tile-action>
            <v-list-tile-content>
              <v-list-tile-title>Open Temporary Drawer</v-list-tile-title>
            </v-list-tile-content>
          </v-list-tile>
        </v-list>
        <v-list dense class="pt-0">
        <v-list-tile v-for="item in items" :key="item.title" :to="item.url">
          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>
          <v-list-tile-content>
            <v-list-tile-title>{{ item.title }}</v-list-tile-title>
          </v-list-tile-content>
        </v-list-tile>
      </v-list>
      </v-navigation-drawer>
      <v-navigation-drawer temporary v-model="left" fixed>
        Left
      </v-navigation-drawer>
      <v-content>
        <v-container fluid fill-height>
          <v-layout justify-center align-center>
            <v-flex text-xs-center>
            <div>
              <nuxt/>
            </div>
          </v-flex>
          </v-layout>
        </v-container>
      </v-content>
      <v-navigation-drawer right temporary v-model="right" fixed>
        Right
      </v-navigation-drawer>
      <v-footer color="blue-grey darken-2" app class="white--text">
      &copy;2018 — <strong>Vuetify</strong>
      <v-spacer></v-spacer>
      <v-btn v-for="icon in icons" :key="icon" icon class="white--text">
        <v-icon small>{{ icon }}</v-icon>
      </v-btn>
    </v-footer>
    </v-app>
  </div>
</template>

<script>
import MyFooter from '~/components/Footer.vue'
import feature from '~/pages/feature.vue'
import contact from '~/pages/contact.vue'

export default {
  components: {
    MyFooter,
    feature,
    contact
  },
  data: () => ({
    drawer: null,
    items: [
      { title: 'Home', icon: 'home', url: '/' },
      { title: 'Feature', icon: 'code', url: '/feature' },
      { title: 'Contact', icon: 'question_answer', url: '/contact' }
    ],
    icons: ['fa-facebook', 'fa-twitter', 'fa-google-plus', 'fa-linkedin', 'fa-instagram'],
    // drawer: true,
    drawerRight: true,
    right: null,
    left: null
  }),
  props: {
    source: String
  }
}
</script>

4)pages/feature.vue を作成する。

<template>
  <div>
    Feature
  </div>
</template>

5)pages/contact.vue を作成する。

<template>
  <div>
    Contact
  </div>
</template>

6)pages/_id.vue の h1 と h2 タグのクラス( class="title" 、 class="info" )を削除する。

(必須ではない。)

7)起動

npm run dev

image.png

下記サイトを参考にさせていただいた。

[メモ]Font Awesome の他の導入方法

npm install --save font-awesome

nuxt.config.js へ下記を追加する。

  css: [
    'font-awesome/css/font-awesome.min.css'
  ],

使用方法は、下記のどちらでもいける。ただし、スタイルは異なる。

<i class="fa fa-camera"></i>
<v-icon>fa-camera</v-icon>

Vuetify は、 デフォルトで Material Icons に対応している。
導入は必要だが、 Material Design IconsFont Awesome をサポートしている。
Material Icons は接頭辞無し、Material Design Icons は接頭辞が mdi- 、Font Awesome は接頭辞が fa- とのこと。
https://vuetifyjs.com/en/components/icons

Bulma @nuxtjs

これ
https://github.com/nuxt-community/modules/tree/master/packages/bulma

npm install --save @nuxtjs/bulma @nuxtjs/font-awesome

1)nuxt.config.js の module.exports 内に modules を追加する。

  modules: [
    '@nuxtjs/bulma',
    '@nuxtjs/font-awesome'
  ]

2)nuxt.config.js の module.exports の build 内に postcss を追加する。

[参考] https://github.com/nuxt/nuxt.js/issues/1670

    postcss: {
      plugins: {
        'postcss-custom-properties': {
          warnings: false
        }
      }
    }

これがないと Warning が出る。

image.png

3)components/NavBar.vue を作成する。

<template>
  <nav class="navbar has-background-light">
    <div class="navbar-brand">
      <nuxt-link class="navbar-item" to="/">
        <img src="https://bulma.io/images/bulma-logo.png" alt="Bulma" width="112" height="28">
      </nuxt-link>
      <div class="navbar-burger burger burger-font-icon" @click="showNav = !showNav" :class="{'is-active': showNav}">
        <img src="@/assets/ic_menu_black_24px.svg" />
      </div>
    </div>
    <div id="navbarExampleTransparentExample" class="navbar-menu" :class="{'is-active':showNav}">
      <div class="navbar-start">
        <nuxt-link class="navbar-item" to="/">
          Home
        </nuxt-link>
        <div class="navbar-item has-dropdown is-hoverable">
          <a class="navbar-link" href="/documentation/overview/start/">
            Docs
          </a>
          <div class="navbar-dropdown is-boxed">
            <nuxt-link v-for="item in items" :key="item.title" :to="item.url" class="navbar-item">
              {{ item.title }}
            </nuxt-link>
            <hr class="navbar-divider">
            <a class="navbar-item" href="https://bulma.io/documentation/elements/box/">
              Elements
            </a>
            <a class="navbar-item is-active" href="https://bulma.io/documentation/components/breadcrumb/">
              Components
            </a>
          </div>
        </div>
      </div>
      <div class="navbar-end">
        <div class="navbar-item">
          <div class="field is-grouped">
            <p class="control">
              <a class="bd-tw-button button" data-social-network="Twitter" data-social-action="tweet" data-social-target="http://localhost:4000" target="_blank" href="https://twitter.com/intent/tweet?text=Bulma: a modern CSS framework based on Flexbox&amp;hashtags=bulmaio&amp;url=http://localhost:4000&amp;via=jgthms">
                <span class="icon">
                  <i class="fa fa-twitter"></i>
                </span>
                <span>
                  Tweet
                </span>
              </a>
            </p>
            <p class="control">
              <a class="button is-primary" href="https://github.com/jgthms/bulma/releases/download/0.7.0/bulma-0.7.0.zip">
                <span class="icon">
                  <i class="fa fa-download"></i>
                </span>
                <span>Download</span>
              </a>
            </p>
          </div>
        </div>
      </div>
    </div>
  </nav>
</template>

<script>
import feature from '~/pages/feature.vue'
import contact from '~/pages/contact.vue'

export default {
  components: {
    feature,
    contact
  },
  data: () => ({
    showNav: false,
    items: [
      { title: 'Home', icon: 'home', url: '/' },
      { title: 'Feature', icon: 'code', url: '/feature' },
      { title: 'Contact', icon: 'question_answer', url: '/contact' }
    ]
  })
}
</script>

<style>
.navbar {
  margin-bottom: 20px;
}
.burger-font-icon img {
  height: 30px;
  margin: 10px 0 0 12px;
}
</style>

4)assets/ic_menu_black_24px.svg を作成する。

Material Icons のメニューアイコン を SVG でダウンロードし、 assets に保存する。

5)components/FooterBar.vue を作成する。(ファイル名に違和感あってもスルー)

<template>
  <footer class="footer has-background-primary has-text-white">
    <div class="container">
    <div class="content has-text-centered is-info">
      <p>&copy; 2018 HOGE inc.</p>
    </div>
    </div>
  </footer>
</template>

<style scoped>
footer.footer {
  padding: 0.5em;
}
</style>

6)components/QuoteCard.vue を作成する。

<template>
  <div class="card">
    <div class="card-content">
      <h2 class="title">&ldquo;{{ val.title }}&rdquo;</h2> 
      <h3 class="subtitle">{{ val.subtitle }}</h3>
    </div>
    <div class="card-footer">
      <span class="card-footer-item">
        <a href="#" class="button is-primary">
          <i class="fa fa-thumbs-o-up"></i>
        </a>
      </span>
      <span class="card-footer-item">
        <a href="#" class="button is-danger">
          <i class="fa fa-thumbs-o-down"></i>
        </a>
      </span>
      <span class="card-footer-item">
        <a href="#" class="button is-info">
          <i class="fa fa-retweet"></i>
        </a>
      </span>
    </div>
  </div>
</template>

<script>
export default {
  props: ['val']
}
</script>

<style scoped>
.card {
  margin-bottom: 8px;
}
</style>

こんなコンポーネント。
image.png

7)components/SignIn.vue を作成する。

<template>
  <div class="card">
    <div class="card-content login">
      <p class="title">
        Already a member?
      </p>
      <p class="subtitle">
        Sign in to continue.
      </p>
      <div class="field">
        <label class="label">Email</label>
        <div class="control">
          <input class="input" type="text" placeholder="Email address">
        </div>
      </div>
      <div class="field">
        <label class="label">Password</label>
        <div class="control">
          <input class="input" type="email" placeholder="My password">
        </div>
      </div>
      <div class="subtitle is-6 has-text-centered">or</div>
      <div class="field is-grouped is-grouped-centered">
        <p class="control">
          <button class="button is-link">Facebook</button>
        </p>
        <p class="control">
          <button class="button is-info">Twitter</button>
        </p>
      </div>
    </div>
    <div class="card-footer has-text-primary has-background-white-bis">
      <p class="card-footer-item register">
        <span>
          Register
        </span>
      </p>
    </div>
  </div>
</template>

こんなコンポーネント。
image.png

8)layouts/default.vue を書きで上書きする。

<template>
  <div class="site">
    <nav-bar/>
    <div class="siteContent">
      <nuxt class="has-text-centered"/>
    </div>
    <footer-bar/>
  </div>
</template>

<script>
import FooterBar from '~/components/FooterBar.vue'
import NavBar from '~/components/NavBar.vue'

export default {
  components: {
    FooterBar,
    NavBar
  }
}
</script>

<style>
.site {
  display: flex;
  min-height: 100vh;
  flex-direction: column;
}
.siteContent {
  flex: 1;
}
</style>

9)pages/feature.vue を作成する。

<template>
  <div>
    <section class="section"> 
      <div class="container"> 
        <div class="columns is-centered ">
          <div class="column is-one-third ">
            <quote-card v-for="item in items" :key="item.title" :val="item"></quote-card>
          </div>
          <div class="column is-one-third">
            <quote-card v-for="item in items2" :key="item.title" :val="item"></quote-card>
          </div>
          <div class="column is-one-third">
            <quote-card v-for="item in items3" :key="item.title" :val="item"></quote-card>
          </div>
        </div>
      </div>
    </section>
  </div>
</template>

<script>
import QuoteCard from '~/components/QuoteCard.vue'

export default {
  components: {
    QuoteCard
  },
  data: () => ({
    items: [
      { title: 'Quote 1', subtitle: 'Programmer-01' },
      { title: 'Quote 2', subtitle: 'Programmer-02' },
      { title: 'Quote 3', subtitle: 'Programmer-03' }
    ],
    items2: [
      { title: 'Order 1', subtitle: 'Programmer-01' }
    ],
    items3: [
      { title: 'Deliver 1', subtitle: 'Programmer-01' },
      { title: 'Deliver 2', subtitle: 'Programmer-02' }
    ]
  })
}
</script>

10)pages/contact.vue を作成する。

<template>
  <div class="columns is-centered">
    <div class="column is-one-third is-mobile">
      <sign-in/>
    </div>
  </div>
</template>

<script>
import SignIn from '~/components/SignIn.vue'

export default {
  components: {
    SignIn
  }
}
</script>

11)起動

npm run dev

image.png

ウィンドウの幅が減ると。
image.png
image.png

各ページは。
image.png
image.png

下記サイトを参考にさせていただいた。

下記は Bulma 関連の気になったサイトやページ。

Bulma おもしろそうだな。

Bulma SCSS編

npm install --save bulma font-awesome
npm install --save-dev sass-loader node-sass

1)nuxt.config.js に下記部分に追加

変更前

  css: ['~/assets/css/main.css'],

変更後

  css: [
    { src: '~/assets/main.scss', lang: 'scss' },
    { src: 'font-awesome/scss/font-awesome.scss', lang: 'scss' }
  ],

2)nuxt.config.js の build 内に追加

    postcss: {
      plugins: {
        'postcss-custom-properties': {
          warnings: false
        }
      }
    }

3)assets/main.scss を作成する。

// 1. Import the initial variables
@import "~bulma/sass/utilities/initial-variables";
@import "~bulma/sass/utilities/functions";

// 2. Set your own initial variables
// Update blue
$blue: #72d0eb;
// Add pink and its invert
$pink: #ffb3b3;
$pink-invert: #fff;
// Add a serif family
$family-serif: "Merriweather", "Georgia", serif;

// 3. Set the derived variables
// Use the new pink as the primary color
$primary: $pink;
$primary-invert: $pink-invert;
// Use the existing orange as the danger color
$danger: $orange;
// Use the new serif family
$family-primary: $family-serif;

// 4. Setup your Custom Colors
$linkedin: #0077b5;
$linkedin-invert: findColorInvert($linkedin);
$twitter: #55acee;
$twitter-invert: findColorInvert($twitter);
$github: #333;
$github-invert: findColorInvert($github);

// 5. Add new color variables to the color map.
@import "~bulma/sass/utilities/derived-variables";
$addColors: (
  "twitter":($twitter, $twitter-invert),
  "linkedin": ($linkedin, $linkedin-invert),
  "github": ($github, $github-invert)
);
$colors: map-merge($colors, $addColors);

// 6. Import the rest of Bulma
@import "~bulma";

4)前章と同じ様に追加、編集を行う。

割愛。

5)起動

npm run dev

image.png

むむむ。
image.png

とりあえず、今後対応で。。

下記サイトを参考にさせていただいた。

Element UI 編

これ
https://element.eleme.io/#/en-US/component/quickstart#use-nuxt-js

基本的には、公式ガイドの通り。
https://element.eleme.io/#/en-US/component/quickstart#use-nuxt-js

npm install --save element-ui

1)plugins/element-ui.js を作成する。

import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'

export default () => {
  Vue.use(Element, { locale })
}

2)nuxt.config.js の module.exports の css を下記に書き換える。

  css: ['element-ui/lib/theme-chalk/index.css'],

3)nuxt.config.js の module.exports に下記を追加する。

  plugins: [
    '@/plugins/element-ui'
  ]

4)components/NavBar.vue を作成する。

<template>
  <div>
    <el-menu
      :default-active="activeIndex2"
      class="el-menu-demo"
      mode="horizontal"
      @select="handleSelect"
      background-color="#545c64"
      text-color="#fff"
      active-text-color="#ffd04b">
      <el-menu-item index="1">Processing Center</el-menu-item>
      <el-submenu index="2">
        <template slot="title">Workspace</template>
        <el-menu-item index="2-1">item one</el-menu-item>
        <el-menu-item index="2-2">item two</el-menu-item>
        <el-menu-item index="2-3">item three</el-menu-item>
        <el-submenu index="2-4">
          <template slot="title">item four</template>
          <el-menu-item index="2-4-1">item one</el-menu-item>
          <el-menu-item index="2-4-2">item two</el-menu-item>
          <el-menu-item index="2-4-3">item three</el-menu-item>
        </el-submenu>
      </el-submenu>
      <el-menu-item index="3" disabled>Info</el-menu-item>
      <el-menu-item index="4"><a href="https://www.ele.me" target="_blank">Orders</a></el-menu-item>
    </el-menu>
  </div>
</template>

<style>
</style>

<script>
export default {
  data () {
    return {
      activeIndex: '1',
      activeIndex2: '1'
    }
  },
  methods: {
    handleSelect (key, keyPath) {
      console.log(key, keyPath)
    }
  }
}
</script>

5)components/SideBar.vue を作成する。

<template>
  <el-menu :default-openeds="['1', '3']">
    <el-submenu index="1">
      <template slot="title"><i class="el-icon-message"></i>Navigator One</template>
      <el-menu-item-group>
        <template slot="title">Group 1</template>
        <el-menu-item index="1-1">Option 1</el-menu-item>
        <el-menu-item index="1-2">Option 2</el-menu-item>
      </el-menu-item-group>
      <el-menu-item-group title="Group 2">
        <el-menu-item index="1-3">Option 3</el-menu-item>
      </el-menu-item-group>
      <el-submenu index="1-4">
        <template slot="title">Option4</template>
        <el-menu-item index="1-4-1">Option 4-1</el-menu-item>
      </el-submenu>
    </el-submenu>
    <el-submenu index="2">
      <template slot="title"><i class="el-icon-menu"></i>Navigator Two</template>
      <el-menu-item-group>
        <template slot="title">Group 1</template>
        <el-menu-item index="2-1">Option 1</el-menu-item>
        <el-menu-item index="2-2">Option 2</el-menu-item>
      </el-menu-item-group>
      <el-menu-item-group title="Group 2">
        <el-menu-item index="2-3">Option 3</el-menu-item>
      </el-menu-item-group>
      <el-submenu index="2-4">
        <template slot="title">Option 4</template>
        <el-menu-item index="2-4-1">Option 4-1</el-menu-item>
      </el-submenu>
    </el-submenu>
    <el-submenu index="3">
      <template slot="title"><i class="el-icon-setting"></i>Navigator Three</template>
      <el-menu-item-group>
        <template slot="title">Group 1</template>
        <el-menu-item index="3-1">Option 1</el-menu-item>
        <el-menu-item index="3-2">Option 2</el-menu-item>
      </el-menu-item-group>
      <el-menu-item-group title="Group 2">
        <el-menu-item index="3-3">Option 3</el-menu-item>
      </el-menu-item-group>
      <el-submenu index="3-4">
        <template slot="title">Option 4</template>
        <el-menu-item index="3-4-1">Option 4-1</el-menu-item>
      </el-submenu>
    </el-submenu>
  </el-menu>
</template>

<style scoped>
.el-menu {
  border: none;
}
</style>

6)layouts/devault.vue を上書きする。

<template>  
  <div>
    <el-header>
      <nav-bar />
    </el-header>
    <el-container>
      <el-aside width="auto">
        <side-bar />
      </el-aside>
      <el-main>
        <nuxt class="centered-text"/>
      </el-main>      
    </el-container>
    <el-footer>
      <my-footer/>
    </el-footer>
  </div>
</template>

<script>
import MyFooter from '~/components/Footer.vue'
import NavBar from '~/components/NavBar.vue'
import SideBar from '~/components/SideBar.vue'

export default {
  components: {
    MyFooter,
    NavBar,
    SideBar
  }
}
</script>

<style>
html, body {
  padding: 0;
  margin: 0;
  height: 100%;
  width: 100%;
}
.el-header {
  background-color: #545c64;
  line-height: 60px;
}
.el-aside {
  border-right: 1px solid #E4E7ED;
}
.el-footer {
  border-top: 1px solid #E4E7ED;
}
.centered-text {
  text-align: center;
}
</style>

7)起動

npm run dev

image.png

雑感

  • Vuetify は、アプリ感出すのに良いね。コンポーネントも多く用意されている。
  • Bulma は、いじってておもしろい。
  • Element UI は、Desktop と謳っているだけあって、コンポーネントはレスポンシブじゃないみたい。

他にも、気になる CSS Framework がいくつかあるので、また試す。

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