Posted at

Nuxt & scssで、UA によってスタイルを適用し分ける方法


0. はじめに


  • 「レスポンシブでイケそう、でもアプリとしては UA 分割する」ような場合有効そう

  • 今回は Desktop or その他(= Mobile) で分岐させています

package
version

nuxt
2.6.1

vue
2.6.10

nuxt-device-detect
1.1.4


1. User Agent を判定する

https://github.com/dotneet/nuxt-device-detect

を利用しましたが、ここはなんでも大丈夫です。

グローバルの Mixin として、こんな感じに layout を分岐させると便利です。


~/plugins/global-mixins.js

import Vue from 'vue'

Vue.mixin({
layout({ app }) {
return app.$device.isDesktop ? 'desktop' : 'mobile'
}
})



レイアウトコンポーネント

レイアウトコンポーネントがそれぞれ #desktop or #mobile を持っていることが重要です。

下記では 2レイアウト準備していますが、動的に出力しても問題ありません。


~/layouts/desktop.vue

<template>

<div id="desktop">
<nuxt />
</div>
</template>


~/layouts/mobile.vue

<template>

<div id="desktop">
<nuxt />
</div>
</template>


2. あとは scss でなんとかする


mixins.scss

@mixin desktop {

#desktop & {
@content;
}
}

@mixin mobile {
#mobile & {
@content;
}
}


もちろん SCSS 周りの設定もいくつか必要ですが、割愛します

参考:


3. 使用例


~/components/TheFooter.vue

<template>

<script>
<style lang="scss" scoped>
.footer {
color: red;

@include desktop {
color: green;
}
}
</style>


祖先に #desktop#mobile があれば適用するモノですね。

いつかレスポンシブになるかもしれない際、mixin 内を変更すれば、メディアクエリへの移行も比較的楽に出来そうです。


Help wanted.

Desktop 時に、Mobile 時の CSS を出力しない ような方法はありませんか? 下記のように。


HogeHoge.vue

<style scoped v-if="$device.isDesktop">

.hoge {
width: 800px;
}
</style>

<style scoped v-else>
.hoge {
width: 100%;
}
</style>