T-CREATOR

Mermaid の高度なカスタマイズ術:スタイル・テーマの徹底活用法

Mermaid の高度なカスタマイズ術:スタイル・テーマの徹底活用法

Mermaidは、テキストベースで図表を作成できる強力なツールとして、多くの開発者に愛用されています。しかし、デフォルトのスタイルのままでは、企業のブランディングや特定のデザインシステムに合わせることができません。また、視覚的なインパクトや読みやすさの観点から、もう一歩踏み込んだカスタマイズが求められる場面も多いでしょう。

この記事では、Mermaidのスタイリング機能を基礎から応用まで段階的に学び、最終的にはプロフェッショナルなカスタマイズができるようになることを目指します。

背景

Mermaidを使い始めた開発者の多くは、まずはフローチャートやシーケンス図の基本的な記法を覚え、日常業務で活用するようになります。しかし、プロジェクトが進むにつれて、以下のような課題が浮上してきます。

デフォルトのスタイルでは、どの図表も似たような見た目になってしまい、差別化が困難です。特に、複数のプロジェクトで同じようなMermaid図を使用している場合、視覚的な一貫性や独自性を保つことが難しくなります。

また、企業やチームでMermaidを活用する際、ブランドガイドラインに沿った色使いやフォント、デザイントーンに合わせたい要望が生まれることも珍しくありません。

課題

Mermaidのカスタマイズにおいて、開発者が直面する主な課題は以下の通りです。

まず、「どこから手をつけていいかわからない」という情報不足の問題があります。Mermaidの公式ドキュメントは豊富ですが、スタイリングに関する情報は点在しており、体系的に学ぶのが困難です。

次に、CSS変数やセレクターの知識が不足していると、思ったような見た目を実現できません。特に、Mermaidが生成するSVG要素の構造を理解せずに、適当にCSSを書いても期待した結果が得られないことがあります。

さらに、組み込みテーマと独自カスタマイズの使い分けが明確でない場合、非効率な実装になりがちです。簡単な調整で済むものを複雑なコードで解決しようとしたり、逆に複雑な要件に対してテーマだけで対応しようとして限界に突き当たったりします。

解決策

Mermaidスタイルカスタマイズの基礎知識

Mermaidのカスタマイズを始める前に、まずはその仕組みを理解することが重要です。MermaidはSVGを生成するライブラリなので、最終的な見た目はCSSで制御されます。

CSS変数を使った色の変更

最も基本的なカスタマイズは、CSS変数を使った色の変更です。以下のコードで、Mermaidの主要な色を一括で変更できます。

javascript// 基本的な色の変更
mermaid.initialize({
  theme: 'base',
  themeVariables: {
    primaryColor: '#ff6b6b',        // 主要な色
    primaryTextColor: '#ffffff',    // テキスト色
    primaryBorderColor: '#ff5252',  // 枠線の色
    lineColor: '#333333',           // 線の色
    sectionBkgColor: '#f8f9fa',     // セクション背景色
    altSectionBkgColor: '#e9ecef',  // 代替セクション背景色
    gridColor: '#cccccc',           // グリッド線の色
    secondaryColor: '#ffeb3b',      // セカンダリカラー
    tertiaryColor: '#4caf50'        // ターシャリカラー
  }
});

この設定により、図表全体の色調を統一できます。特にprimaryColorは最も影響範囲が広く、ノードの背景色やアクセントカラーとして使用されます。

フォントファミリーの設定

視認性と統一感を高めるため、フォントのカスタマイズも重要です。

javascript// フォント設定のカスタマイズ
mermaid.initialize({
  theme: 'base',
  themeVariables: {
    fontFamily: '"Helvetica Neue", Arial, sans-serif',
    fontSize: '16px',
    primaryTextColor: '#2c3e50',
    lineColor: '#34495e'
  }
});

この設定では、読みやすいHelvetica Neueフォントを指定し、フォントサイズを16pxに統一しています。日本語環境では、以下のような設定がおすすめです。

javascript// 日本語対応フォント設定
mermaid.initialize({
  theme: 'base',
  themeVariables: {
    fontFamily: '"Hiragino Kaku Gothic ProN", "ヒラギノ角ゴ ProN W3", "Meiryo", "メイリオ", sans-serif',
    fontSize: '14px'
  }
});

線の太さや形状の調整

図表の印象を大きく左右するのが、線の太さや形状です。

javascript// 線のスタイル調整
mermaid.initialize({
  theme: 'base',
  themeVariables: {
    lineColor: '#2c3e50',
    primaryBorderColor: '#3498db',
    clusterBorderColor: '#e74c3c'
  },
  flowchart: {
    curve: 'linear',        // 線の形状:linear, basis, cardinal
    padding: 15,            // ノード内の余白
    nodeSpacing: 50,        // ノード間のスペース
    rankSpacing: 50         // ランク間のスペース
  }
});

curveプロパティでは、線の形状を指定できます。linearは直線、basisは滑らかな曲線、cardinalは角度のある曲線を描画します。

テーマシステムの活用

Mermaidには事前定義されたテーマが用意されており、用途に応じて選択できます。

組み込みテーマの種類と特徴

Mermaidには以下の組み込みテーマが用意されています。

#テーマ名特徴適用場面
1default標準的な青基調一般的なドキュメント
2neutralモノクロ・グレースケール印刷物・技術文書
3darkダークモード対応夜間作業・開発環境
4forest緑基調の自然な色合い環境・自然関連プロジェクト
5baseカスタマイズベース独自テーマ作成時

各テーマの適用方法は以下の通りです。

javascript// テーマの基本的な適用
mermaid.initialize({
  theme: 'dark'  // 'default', 'neutral', 'dark', 'forest', 'base'
});

カスタムテーマの作成方法

より細かい制御が必要な場合は、独自のテーマを作成します。

javascript// カスタムテーマの詳細設定
const customTheme = {
  theme: 'base',
  themeVariables: {
    // 主要色の定義
    primaryColor: '#667eea',
    primaryTextColor: '#ffffff',
    primaryBorderColor: '#5a67d8',
    
    // セカンダリカラー
    secondaryColor: '#f093fb',
    secondaryTextColor: '#4a5568',
    secondaryBorderColor: '#e53e3e',
    
    // 背景色
    background: '#f7fafc',
    mainBkg: '#ffffff',
    secondBkg: '#edf2f7',
    
    // テキストとライン
    textColor: '#2d3748',
    lineColor: '#4a5568',
    
    // フォント設定
    fontFamily: '"Inter", sans-serif',
    fontSize: '14px'
  }
};

mermaid.initialize(customTheme);

このカスタムテーマでは、モダンなグラデーションカラーを使用し、読みやすさを重視した配色にしています。

テーマの切り替え実装

動的にテーマを切り替える機能を実装することで、ユーザーの好みや環境に応じた表示が可能になります。

javascript// テーマ切り替え機能の実装
function switchTheme(themeName) {
  const themes = {
    light: {
      theme: 'default',
      themeVariables: {
        primaryColor: '#3498db',
        background: '#ffffff',
        textColor: '#2c3e50'
      }
    },
    dark: {
      theme: 'dark',
      themeVariables: {
        primaryColor: '#74b9ff',
        background: '#2d3436',
        textColor: '#ddd'
      }
    },
    corporate: {
      theme: 'base',
      themeVariables: {
        primaryColor: '#e17055',
        primaryTextColor: '#ffffff',
        background: '#f8f9fa',
        fontFamily: '"Roboto", sans-serif'
      }
    }
  };
  
  if (themes[themeName]) {
    mermaid.initialize(themes[themeName]);
    // 既存の図表を再描画
    mermaid.reload();
  }
}

// 使用例
document.getElementById('theme-selector').addEventListener('change', (e) => {
  switchTheme(e.target.value);
});

この実装では、ライト・ダーク・コーポレートの3つのテーマを定義し、セレクトボックスから動的に切り替えができます。

高度なスタイリング技法

基本的なテーマ設定だけでは実現できない、より細かなカスタマイズ技法をご紹介します。

セレクターを使った細かな調整

MermaidのSVG出力に対してCSSセレクターを使用することで、特定の要素だけをピンポイントでカスタマイズできます。

css/* フローチャートの特定ノードタイプのスタイリング */
.node rect {
  fill: #e74c3c !important;
  stroke: #c0392b !important;
  stroke-width: 2px;
  rx: 8px; /* 角丸の設定 */
}

/* 決定ノード(ダイヤモンド)のスタイル */
.node polygon {
  fill: #f39c12 !important;
  stroke: #d68910 !important;
  stroke-width: 3px;
}

/* テキストラベルのスタイリング */
.nodeLabel {
  font-family: "Helvetica Neue", Arial, sans-serif !important;
  font-size: 14px !important;
  font-weight: 600 !important;
  fill: #2c3e50 !important;
}

/* エッジ(矢印)のカスタマイズ */
.edgePath path {
  stroke: #34495e !important;
  stroke-width: 2px !important;
  marker-end: url(#arrowhead) !important;
}

/* シーケンス図の参加者ボックス */
.actor {
  fill: #3498db !important;
  stroke: #2980b9 !important;
  stroke-width: 2px !important;
}

これらのCSSルールを適用することで、Mermaidのデフォルトスタイルを上書きし、独自のデザインを実現できます。

アニメーションの追加

静的な図表にアニメーション効果を追加することで、プレゼンテーションやインタラクティブなドキュメントでの訴求力を高められます。

css/* ノードにホバーエフェクトを追加 */
.node {
  transition: all 0.3s ease;
  cursor: pointer;
}

.node:hover {
  transform: scale(1.05);
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.2));
}

/* エッジのアニメーション(描画エフェクト) */
.edgePath path {
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: drawLine 2s ease-in-out forwards;
}

@keyframes drawLine {
  to {
    stroke-dashoffset: 0;
  }
}

/* ノードの順次表示アニメーション */
.node {
  opacity: 0;
  animation: fadeInUp 0.6s ease forwards;
}

.node:nth-child(1) { animation-delay: 0.1s; }
.node:nth-child(2) { animation-delay: 0.2s; }
.node:nth-child(3) { animation-delay: 0.3s; }

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

これらのアニメーションにより、図表が段階的に表示され、ユーザーの注意を引きつける効果が期待できます。

レスポンシブ対応

モバイルデバイスでの表示を考慮したレスポンシブ対応も重要です。

css/* レスポンシブ対応のCSS */
.mermaid {
  max-width: 100%;
  height: auto;
}

/* モバイル端末での調整 */
@media (max-width: 768px) {
  .mermaid {
    font-size: 12px;
  }
  
  .nodeLabel {
    font-size: 10px !important;
  }
  
  .node {
    transform: scale(0.8);
  }
  
  .edgePath path {
    stroke-width: 1px !important;
  }
}

/* タブレット端末での調整 */
@media (min-width: 769px) and (max-width: 1024px) {
  .mermaid {
    font-size: 14px;
  }
  
  .nodeLabel {
    font-size: 12px !important;
  }
}

さらに、JavaScriptでのビューポート検出と組み合わせることで、より柔軟な対応が可能です。

javascript// レスポンシブ設定の動的調整
function adjustMermaidForViewport() {
  const viewport = window.innerWidth;
  let config = {};
  
  if (viewport < 768) {
    // モバイル設定
    config = {
      theme: 'base',
      themeVariables: {
        fontSize: '10px',
        primaryColor: '#3498db'
      },
      flowchart: {
        nodeSpacing: 30,
        rankSpacing: 40,
        padding: 10
      }
    };
  } else if (viewport < 1024) {
    // タブレット設定
    config = {
      theme: 'base',
      themeVariables: {
        fontSize: '12px',
        primaryColor: '#3498db'
      },
      flowchart: {
        nodeSpacing: 40,
        rankSpacing: 50,
        padding: 12
      }
    };
  } else {
    // デスクトップ設定
    config = {
      theme: 'base',
      themeVariables: {
        fontSize: '14px',
        primaryColor: '#3498db'
      },
      flowchart: {
        nodeSpacing: 50,
        rankSpacing: 60,
        padding: 15
      }
    };
  }
  
  mermaid.initialize(config);
}

// ウィンドウリサイズ時の再調整
window.addEventListener('resize', debounce(adjustMermaidForViewport, 300));

// debounce関数でパフォーマンス最適化
function debounce(func, wait) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}

具体例

企業サイト向けブランドカラー適用プロジェクトを通じて、実際のカスタマイズ手順を見ていきましょう。

プロジェクト要件

架空の企業「TechFlow Inc.」のコーポレートサイトで使用するMermaid図表のカスタマイズを行います。

#要件項目詳細
1ブランドカラープライマリ: #2C5282, セカンダリ: #ED8936
2フォント企業指定: "Noto Sans JP", sans-serif
3角丸全要素に8pxの角丸を適用
4アニメーションホバー時に微細な拡大効果
5レスポンシブスマートフォン対応必須

実装手順

まず、基本的なテーマ設定を行います。

javascript// TechFlow Inc. 専用テーマ設定
const techFlowTheme = {
  theme: 'base',
  themeVariables: {
    // ブランドカラーの適用
    primaryColor: '#2C5282',
    primaryTextColor: '#FFFFFF',
    primaryBorderColor: '#2A4A7C',
    
    secondaryColor: '#ED8936',
    secondaryTextColor: '#FFFFFF',
    secondaryBorderColor: '#E07A2A',
    
    // 背景色
    background: '#F7FAFC',
    mainBkg: '#FFFFFF',
    
    // テキスト
    textColor: '#2D3748',
    lineColor: '#4A5568',
    
    // フォント設定
    fontFamily: '"Noto Sans JP", -apple-system, BlinkMacSystemFont, sans-serif',
    fontSize: '14px'
  },
  
  // フローチャートの詳細設定
  flowchart: {
    curve: 'linear',
    padding: 15,
    nodeSpacing: 60,
    rankSpacing: 60
  }
};

// テーマの初期化
mermaid.initialize(techFlowTheme);

次に、角丸やアニメーション効果を実現するCSSを追加します。

css/* TechFlow Inc. 専用スタイル */
.techflow-mermaid .node rect,
.techflow-mermaid .node circle,
.techflow-mermaid .node ellipse {
  rx: 8px !important;
  ry: 8px !important;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.1));
}

/* ホバーエフェクト */
.techflow-mermaid .node:hover rect,
.techflow-mermaid .node:hover circle,
.techflow-mermaid .node:hover ellipse {
  transform: scale(1.02);
  filter: drop-shadow(0 4px 12px rgba(44, 82, 130, 0.15));
}

/* ブランドカラーの細かな調整 */
.techflow-mermaid .node.primary rect {
  fill: #2C5282 !important;
  stroke: #2A4A7C !important;
}

.techflow-mermaid .node.secondary rect {
  fill: #ED8936 !important;
  stroke: #E07A2A !important;
}

/* レスポンシブ対応 */
@media (max-width: 640px) {
  .techflow-mermaid {
    font-size: 12px;
  }
  
  .techflow-mermaid .nodeLabel {
    font-size: 11px !important;
  }
  
  .techflow-mermaid .node {
    transform: scale(0.9);
  }
}

実際のMermaid記法での活用

カスタマイズしたテーマを使って、実際の業務フロー図を作成してみます。

mermaidflowchart TD
    A[プロジェクト開始] --> B{要件確認}
    B -->|OK| C[設計フェーズ]
    B -->|NG| D[要件再検討]
    D --> B
    C --> E[開発フェーズ]
    E --> F[テストフェーズ]
    F --> G{品質チェック}
    G -->|Pass| H[リリース]
    G -->|Fail| I[修正作業]
    I --> F
    H --> J[運用開始]
    
    classDef primary fill:#2C5282,stroke:#2A4A7C,stroke-width:2px,color:#fff
    classDef secondary fill:#ED8936,stroke:#E07A2A,stroke-width:2px,color:#fff
    classDef decision fill:#FFF,stroke:#4A5568,stroke-width:2px,color:#2D3748
    
    class A,C,E,F,H,J primary
    class D,I secondary
    class B,G decision

このフローチャートでは、classDefを使用してノードごとに異なるスタイルを適用しています。プライマリアクション、セカンダリアクション、決定ポイントを色分けすることで、視覚的な理解を促進します。

パフォーマンスの最適化

大規模な図表や複数の図表を含むページでは、パフォーマンスの最適化も重要です。

javascript// パフォーマンス最適化の実装
const optimizedMermaidConfig = {
  ...techFlowTheme,
  
  // レンダリング最適化
  maxTextSize: 50000,
  maxEdges: 500,
  
  // セキュリティ設定
  securityLevel: 'loose',
  
  // 非同期レンダリング
  startOnLoad: false
};

// 遅延読み込みの実装
function initializeMermaidCharts() {
  const mermaidElements = document.querySelectorAll('.mermaid');
  
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting && !entry.target.hasAttribute('data-processed')) {
        mermaid.init(undefined, entry.target);
        entry.target.setAttribute('data-processed', 'true');
      }
    });
  }, {
    rootMargin: '50px'
  });
  
  mermaidElements.forEach(element => {
    observer.observe(element);
  });
}

// DOM読み込み完了後に初期化
document.addEventListener('DOMContentLoaded', () => {
  mermaid.initialize(optimizedMermaidConfig);
  initializeMermaidCharts();
});

この最適化により、ページの初期読み込み時間を短縮し、必要に応じて図表をレンダリングできます。

エラーハンドリングとデバッグ

実際の運用では、エラーハンドリングも重要な要素です。

javascript// エラーハンドリングの実装
mermaid.parseError = function(err, hash) {
  console.error('Mermaid parsing error:', err);
  
  // エラー内容に応じた対処
  if (err.message.includes('Parse error')) {
    displayErrorMessage('図表の記法にエラーがあります。記法を確認してください。');
  } else if (err.message.includes('Cannot read property')) {
    displayErrorMessage('図表の描画に失敗しました。ページを再読み込みしてください。');
  } else {
    displayErrorMessage('予期しないエラーが発生しました。');
  }
};

function displayErrorMessage(message) {
  const errorElement = document.createElement('div');
  errorElement.className = 'mermaid-error';
  errorElement.innerHTML = `
    <div style="padding: 20px; background: #fed7d7; border: 1px solid #e53e3e; border-radius: 8px; color: #c53030;">
      <strong>⚠️ エラー:</strong> ${message}
    </div>
  `;
  
  // エラーが発生したmermaid要素を置き換え
  const mermaidElements = document.querySelectorAll('.mermaid:not([data-processed])');
  if (mermaidElements.length > 0) {
    mermaidElements[0].parentNode.replaceChild(errorElement, mermaidElements[0]);
  }
}

まとめ

Mermaidのスタイルカスタマイズは、基礎的なCSS変数の理解から始まり、高度なセレクター活用、アニメーション実装、レスポンシブ対応まで幅広い技術要素を含んでいます。

重要なポイントは、まず組み込みテーマを理解し、その上で段階的にカスタマイズを進めることです。無理に複雑な実装から始めるのではなく、色やフォントの変更から慣れ親しみ、徐々にCSSセレクターやJavaScriptでの動的制御に挑戦していくことをお勧めします。

また、企業やプロジェクトでMermaidを活用する際は、ブランドガイドラインとの整合性、アクセシビリティの確保、パフォーマンスの最適化を常に意識することが大切です。これらの考慮事項を踏まえることで、ただ見た目が良いだけでなく、実用性と保守性を兼ね備えた図表システムを構築できるでしょう。

最後に、カスタマイズした設定やスタイルは、チーム内で共有しやすい形でドキュメント化し、再利用可能なコンポーネントとして整備することで、開発効率の向上にもつながります。Mermaidのカスタマイズ技術を身につけることで、あなたの図表がより魅力的で、より効果的なコミュニケーションツールになることを願っています。

関連リンク