Skip to content

🎨 テーマカスタマイズガイド - あなたのアプリを唯一無二に!

🌈 あなたのアプリに独自のブランド魅力を持たせたいですか?このテーマカスタマイズの宝典が、ゼロから始めて独自のビジュアルスタイルを作り上げる方法をご案内します!基本的な色調整から高度な動的テーマ切り替え、レスポンシブ対応からダークモードサポートまで、テーマカスタマイズの達人になるためのステップバイステップのガイドを提供します。あなたの創造性を解き放つ準備はできていますか?

🎨 テーマカスタマイズ方針

CSS 変数を使用したテーマカスタマイズ(推奨)

Vant は CSS 変数を使用してテーマスタイルを定義しています。これにより、テーマを簡単にカスタマイズできます。

css
/* グローバルテーマ変数 */
:root {
  /* 主色 */
  --van-primary-color: #1989fa;
  --van-success-color: #07c160;
  --van-warning-color: #ff976a;
  --van-danger-color: #ee0a24;
  
  /* テキスト色 */
  --van-text-color: #323233;
  --van-text-color-2: #646566;
  --van-text-color-3: #969799;
  
  /* 背景色 */
  --van-background-color: #f7f8fa;
  --van-background-color-light: #fafafa;
  
  /* 境界色 */
  --van-border-color: #ebedf0;
  
  /* フォントサイズ */
  --van-font-size-xs: 10px;
  --van-font-size-sm: 12px;
  --van-font-size-md: 14px;
  --van-font-size-lg: 16px;
  --van-font-size-xl: 18px;
  
  /* パディング */
  --van-padding-base: 4px;
  --van-padding-xs: 8px;
  --van-padding-sm: 12px;
  --van-padding-md: 16px;
  --van-padding-lg: 24px;
  --van-padding-xl: 32px;
  
  /* 境界半径 */
  --van-border-radius-sm: 2px;
  --van-border-radius-md: 4px;
  --van-border-radius-lg: 8px;
  --van-border-radius-max: 999px;
}

コンポーネントレベルのカスタマイズ

css
/* ボタンコンポーネントのカスタマイズ */
.van-button {
  --van-button-primary-background-color: #007bff;
  --van-button-primary-border-color: #007bff;
  --van-button-border-radius: 8px;
  --van-button-font-weight: 600;
}

/* ナビゲーションバーのカスタマイズ */
.van-nav-bar {
  --van-nav-bar-background-color: #ffffff;
  --van-nav-bar-title-text-color: #323233;
  --van-nav-bar-icon-color: #1989fa;
  --van-nav-bar-height: 56px;
}

/* タブコンポーネントのカスタマイズ */
.van-tabs {
  --van-tabs-default-color: #646566;
  --van-tabs-line-height: 44px;
  --van-tab-active-text-color: #1989fa;
  --van-tabs-bottom-bar-color: #1989fa;
}

/* セルコンポーネントのカスタマイズ */  
.van-cell {
  --van-cell-background-color: #ffffff;
  --van-cell-border-color: #ebedf0;
  --van-cell-font-size: 14px;
  --van-cell-line-height: 24px;
}

🌈 ブランド色彩システム

ブランド色彩配置

javascript
// theme/colors.js
export const brandColors = {
  // 主色 - 主要な色を表し、アプリケーションのブランドイメージを形成します。
  primary: {
    50: '#e3f2fd',
    100: '#bbdefb',
    200: '#90caf9',
    300: '#64b5f6',
    400: '#42a5f5',
    500: '#2196f3', // 主要色
    600: '#1e88e5',
    700: '#1976d2',
    800: '#1565c0',
    900: '#0d47a1'
  },
  
  // 辅助色 - 主色に対して補完的な色を提供し、ユーザーエクスペリエンスを向上させます。  
  secondary: {
    50: '#fce4ec',
    100: '#f8bbd9',
    200: '#f48fb1',
    300: '#f06292',
    400: '#ec407a',
    500: '#e91e63', // 辅助色
    600: '#d81b60',
    700: '#c2185b',
    800: '#ad1457',
    900: '#880e4f'
  },
  
  // 成功色 - 操作が成功したことを示す色です。
  success: '#4caf50',
  // 警告色 - 注意が必要な操作を示す色です。
  warning: '#ff9800',
  // エラー色 - 操作が失敗したことを示す色です。
  error: '#f44336',
  // 情報色 - 一般的な情報を示す色です。
  info: '#2196f3',
  
  // 中性色 - 一般的な色を表し、ブランドイメージを形成します。  
  gray: {
    50: '#fafafa',
    100: '#f5f5f5',
    200: '#eeeeee',
    300: '#e0e0e0',
    400: '#bdbdbd',
    500: '#9e9e9e',
    600: '#757575',
    700: '#616161',
    800: '#424242',
    900: '#212121'
  }
}

动态主题切换

vue
<script setup>
import { ref, watch } from 'vue'

const themes = {
  light: {
    '--van-primary-color': '#1989fa',
    '--van-background-color': '#ffffff',
    '--van-text-color': '#323233'
  },
  dark: {
    '--van-primary-color': '#4fc3f7',
    '--van-background-color': '#1a1a1a',
    '--van-text-color': '#ffffff'
  },
  custom: {
    '--van-primary-color': '#e91e63',
    '--van-background-color': '#f5f5f5',
    '--van-text-color': '#2c3e50'
  }
}

const currentTheme = ref('light')

const applyTheme = (themeName) => {
  const theme = themes[themeName]
  const root = document.documentElement
  
  Object.keys(theme).forEach(property => {
    root.style.setProperty(property, theme[property])
  })
  
  // テーマ設定を保存
  localStorage.setItem('theme', themeName)
}

watch(currentTheme, (newTheme) => {
  applyTheme(newTheme)
}, { immediate: true })

// ページロード時にテーマを復元
const savedTheme = localStorage.getItem('theme')
if (savedTheme && themes[savedTheme]) {
  currentTheme.value = savedTheme
}
</script>

<template>
  <div class="theme-switcher">
    <van-cell-group title="テーマ設定">
      <van-cell title="明るいテーマ" clickable @click="currentTheme = 'light'">
        <template #right-icon>
          <van-icon v-if="currentTheme === 'light'" name="success" color="#1989fa" />
        </template>
      </van-cell>
      
      <van-cell title="ダークテーマ" clickable @click="currentTheme = 'dark'">
        <template #right-icon>
          <van-icon v-if="currentTheme === 'dark'" name="success" color="#1989fa" />
        </template>
      </van-cell>
      
      <van-cell title="カスタムテーマ" clickable @click="currentTheme = 'custom'">
        <template #right-icon>
          <van-icon v-if="currentTheme === 'custom'" name="success" color="#1989fa" />
        </template>
      </van-cell>
    </van-cell-group>
  </div>
</template>

🎭 ダークモードのサポート

システムレベルのダークモード

css
/* ダークモード変数 */
@media (prefers-color-scheme: dark) {
  :root {
    --van-primary-color: #4fc3f7;
    --van-success-color: #4caf50;
    --van-warning-color: #ff9800;
    --van-danger-color: #f44336;
    
    --van-text-color: #ffffff;
    --van-text-color-2: #cccccc;
    --van-text-color-3: #999999;
    
    --van-background-color: #1a1a1a;
    --van-background-color-light: #2d2d2d;
    
    --van-border-color: #333333;
  }
  
  /* コンポーネントのダークモード対応 */
  .van-nav-bar {
    --van-nav-bar-background-color: #2d2d2d;
    --van-nav-bar-title-text-color: #ffffff;
  }
  
  .van-cell {
    --van-cell-background-color: #2d2d2d;
    --van-cell-border-color: #333333;
  }
  
  .van-button--default {
    --van-button-default-background-color: #333333;
    --van-button-default-color: #ffffff;
    --van-button-default-border-color: #555555;
  }
}

手動ダークモード制御

javascript
// composables/useTheme.js
import { ref, computed } from 'vue'

const isDark = ref(false)

export function useTheme() {
  const toggleDark = () => {
    isDark.value = !isDark.value
    updateTheme()
  }
  
  const updateTheme = () => {
    const root = document.documentElement
    
    if (isDark.value) {
      root.classList.add('dark')
      root.classList.remove('light')
    } else {
      root.classList.add('light')
      root.classList.remove('dark')
    }
    
    localStorage.setItem('theme-mode', isDark.value ? 'dark' : 'light')
  }
  
  const initTheme = () => {
    const savedMode = localStorage.getItem('theme-mode')
    const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches
    
    isDark.value = savedMode ? savedMode === 'dark' : systemDark
    updateTheme()
  }
  
  const themeClass = computed(() => isDark.value ? 'dark' : 'light')
  
  return {
    isDark,
    themeClass,
    toggleDark,
    initTheme
  }
}

🖼️ アイコンカスタマイズ

カスタムアイコンライブラリ

javascript
// カスタムアイコンの登録
import { Icon } from 'vant'

// 方法1:画像URLを使用
Icon.add('custom-icon', 'https://example.com/icon.png')

// 方法2:SVG文字列を使用
Icon.add('custom-svg', `
  <svg viewBox="0 0 24 24">
    <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>
  </svg>
`)

// 方法3:フォントアイコンを使用
Icon.add('font-icon', (h) => h('i', { class: 'iconfont icon-custom' }))

アイコンのテーマ対応

vue
<script setup>
import { computed } from 'vue'
import { useTheme } from '@/composables/useTheme'

const { isDark } = useTheme()

const iconColor = computed(() => {
  return isDark.value ? '#ffffff' : '#323233'
})

const iconStyle = computed(() => ({
  color: iconColor.value,
  fontSize: '20px'
}))
</script>

<template>
  <div class="icon-container">
    <!-- 計算プロパティを使用してアイコンの色を動的に設定 -->
    <van-icon name="star" :style="iconStyle" />
    
    <!-- CSS変数を使用 -->
    <van-icon name="heart" class="themed-icon" />
    
    <!-- カスタムアイコン -->
    <van-icon name="custom-icon" :color="iconColor" />
  </div>
</template>

<style scoped>
.themed-icon {
  color: var(--van-text-color);
  font-size: var(--van-font-size-lg);
}
</style>

📱 レスポンシブテーマ

ブレークポイントシステム

css
/* レスポンシブブレークポイントの定義 */
:root {
  --breakpoint-xs: 480px;
  --breakpoint-sm: 768px;
  --breakpoint-md: 1024px;
  --breakpoint-lg: 1200px;
  --breakpoint-xl: 1440px;
}

/* 小さな画面への対応 */
@media (max-width: 480px) {
  :root {
    --van-font-size-md: 12px;
    --van-padding-md: 12px;
    --van-nav-bar-height: 48px;
  }
}

/* 中程度の画面への対応 */
@media (min-width: 481px) and (max-width: 768px) {
  :root {
    --van-font-size-md: 14px;
    --van-padding-md: 16px;
    --van-nav-bar-height: 52px;
  }
}

/* 大きな画面への対応 */
@media (min-width: 769px) {
  :root {
    --van-font-size-md: 16px;
    --van-padding-md: 20px;
    --van-nav-bar-height: 56px;
  }
}

動的なフォントサイズ

javascript
// composables/useResponsive.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useResponsive() {
  const screenWidth = ref(window.innerWidth)
  const fontSize = ref(14)
  
  const updateFontSize = () => {
    screenWidth.value = window.innerWidth
    
    if (screenWidth.value < 480) {
      fontSize.value = 12
    } else if (screenWidth.value < 768) {
      fontSize.value = 14
    } else {
      fontSize.value = 16
    }
    
    document.documentElement.style.setProperty('--dynamic-font-size', `${fontSize.value}px`)
  }
  
  onMounted(() => {
    updateFontSize()
    window.addEventListener('resize', updateFontSize)
  })
  
  onUnmounted(() => {
    window.removeEventListener('resize', updateFontSize)
  })
  
  return {
    screenWidth,
    fontSize
  }
}

🎨 テーマビルドツール

Sass変数のカスタマイズ

scss
// theme/variables.scss
$primary-color: #1989fa;
$success-color: #07c160;
$warning-color: #ff976a;
$danger-color: #ee0a24;

$text-color: #323233;
$text-color-2: #646566;
$text-color-3: #969799;

$background-color: #f7f8fa;
$background-color-light: #fafafa;

$border-color: #ebedf0;
$border-width: 1px;
$border-style: solid;

// フォント
$font-size-xs: 10px;
$font-size-sm: 12px;
$font-size-md: 14px;
$font-size-lg: 16px;
$font-size-xl: 18px;

// 間隔
$padding-base: 4px;
$padding-xs: 8px;
$padding-sm: 12px;
$padding-md: 16px;
$padding-lg: 24px;
$padding-xl: 32px;

// 角丸
$border-radius-sm: 2px;
$border-radius-md: 4px;
$border-radius-lg: 8px;
$border-radius-max: 999px;

// 影
$box-shadow-light: 0 1px 3px rgba(0, 0, 0, 0.12);
$box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.12);
$box-shadow-dark: 0 4px 12px rgba(0, 0, 0, 0.15);

// アニメーション
$animation-duration-base: 0.3s;
$animation-duration-fast: 0.2s;
$animation-timing-function: ease;

テーマジェネレーター

javascript
// utils/themeGenerator.js
export class ThemeGenerator {
  constructor(baseTheme = {}) {
    this.baseTheme = baseTheme
    this.generatedTheme = {}
  }
  
  // カラーバリエーションの生成
  generateColorVariants(baseColor) {
    const variants = {}
    const hsl = this.hexToHsl(baseColor)
    
    // 異なる明度のバリエーションを生成
    for (let i = 1; i <= 9; i++) {
      const lightness = Math.max(5, Math.min(95, hsl.l + (5 - i) * 10))
      variants[`${i}0`] = this.hslToHex(hsl.h, hsl.s, lightness)
    }
    
    return variants
  }
  
  // 完全なテーマの生成
  generateTheme(primaryColor) {
    const primaryVariants = this.generateColorVariants(primaryColor)
    
    return {
      primary: primaryVariants,
      colors: {
        primary: primaryColor,
        success: '#07c160',
        warning: '#ff976a',
        danger: '#ee0a24',
        info: primaryVariants['40']
      },
      text: {
        primary: '#323233',
        secondary: '#646566',
        disabled: '#969799'
      },
      background: {
        primary: '#ffffff',
        secondary: '#f7f8fa',
        disabled: '#f5f5f5'
      },
      border: {
        color: '#ebedf0',
        width: '1px',
        style: 'solid'
      }
    }
  }
  
  // テーマをCSS変数に適用
  applyTheme(theme) {
    const root = document.documentElement
    
    Object.entries(theme).forEach(([category, values]) => {
      if (typeof values === 'object') {
        Object.entries(values).forEach(([key, value]) => {
          root.style.setProperty(`--van-${category}-${key}`, value)
        })
      } else {
        root.style.setProperty(`--van-${category}`, values)
      }
    })
  }
  
  // 色変換ツール
  hexToHsl(hex) {
    const r = parseInt(hex.slice(1, 3), 16) / 255
    const g = parseInt(hex.slice(3, 5), 16) / 255
    const b = parseInt(hex.slice(5, 7), 16) / 255
    
    const max = Math.max(r, g, b)
    const min = Math.min(r, g, b)
    let h, s, l = (max + min) / 2
    
    if (max === min) {
      h = s = 0
    } else {
      const d = max - min
      s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
      
      switch (max) {
        case r: h = (g - b) / d + (g < b ? 6 : 0); break
        case g: h = (b - r) / d + 2; break
        case b: h = (r - g) / d + 4; break
      }
      h /= 6
    }
    
    return { h: h * 360, s: s * 100, l: l * 100 }
  }
  
  hslToHex(h, s, l) {
    h /= 360
    s /= 100
    l /= 100
    
    const hue2rgb = (p, q, t) => {
      if (t < 0) t += 1
      if (t > 1) t -= 1
      if (t < 1/6) return p + (q - p) * 6 * t
      if (t < 1/2) return q
      if (t < 2/3) return p + (q - p) * (2/3 - t) * 6
      return p
    }
    
    let r, g, b
    
    if (s === 0) {
      r = g = b = l
    } else {
      const q = l < 0.5 ? l * (1 + s) : l + s - l * s
      const p = 2 * l - q
      r = hue2rgb(p, q, h + 1/3)
      g = hue2rgb(p, q, h)
      b = hue2rgb(p, q, h - 1/3)
    }
    
    const toHex = (c) => {
      const hex = Math.round(c * 255).toString(16)
      return hex.length === 1 ? '0' + hex : hex
    }
    
    return `#${toHex(r)}${toHex(g)}${toHex(b)}`
  }
}

// 使用例
const generator = new ThemeGenerator()
const customTheme = generator.generateTheme('#e91e63')
generator.applyTheme(customTheme)

📚 ベストプラクティス

テーマデザイン原則 - デザイナーの黄金律 ✨

  1. 一貫性 🎯:全体の視覚スタイルを統一する(服装のように、全体感が大切)
  2. アクセシビリティ ♿:十分なコントラストを確保する(全員が使いやすく)
  3. レスポンシブ 📱:様々な画面サイズに対応(一つのテーマで全て対応)
  4. パフォーマンス ⚡:過度なスタイル計算を避ける(美観とパフォーマンスの両立)
  5. メンテナンス性 🔧:変数とモジュール化で管理(将来のあなたが今のあなたに感謝する)

テーマテストチェックリスト - リリース前の最終確認 ✅

  • [ ] 明るい/ダークモードの切り替えが正常(明確に区別でき、スムーズな切り替え)
  • [ ] すべてのコンポーネントのスタイルが一貫している(統一性が美の基本)
  • [ ] レスポンシブレイアウトが良好に対応(大画面も小画面も完璧)
  • [ ] 色のコントラストがアクセシビリティ標準に準拠(包容性デザイン)
  • [ ] テーマ切り替えのパフォーマンスが良好(瞬時に切り替わり、カクツキなし)
  • [ ] カスタムアイコンが正しく表示(細部まで完璧に)

💡 ベストプラクティスまとめ - テーマカスタマイズの成功の秘密

  1. ブランドから始める 🎨

    • ブランドカラー体系に基づいてテーマを設計(ブランドを深く印象付ける)
    • 視覚言語の一貫性を維持(統一された美学基準)
  2. ユーザー体験を優先 👥

    • システムレベルのダークモードをサポート(ユーザーの習慣に沿う)
    • テーマ切り替えオプションを提供(ユーザーに選択の自由を与える)
  3. 技術的実装 🛠️

    • CSS変数を使用して動的テーマを実現(最新の解決策)
    • スタイル構造を合理的に組織(保守しやすいコードアーキテクチャ)
  4. パフォーマンスの考慮

    • 頻繁なDOM操作を避ける(パフォーマンス最適化)
    • CSS変数を使用して再描画を減らす(ハードウェアアクセラレーション)

📚 関連コンテンツ

テーマカスタマイズの詳細な技巧を深く理解したいですか?これらのリソースは見逃せません:

上記のテーマカスタマイズの方法により、あなたは簡単に独自の特色あるVantアプリインターフェースを作成することができます。良いテーマは見栄えだけでなく、使いやすさも大切です!美しくて使いやすいユーザー体験を一緒に作り上げましょう!🎨✨

Vant に基づく企業向けモバイルソリューション