もうチラ見えさせない!Vueのv-cloakで初期表示の“チラつき”をゼロにする(HTML & Pug対応)

こんにちは、さるまりんです。

Vueで「まだ表示準備ができてない状態で、一瞬だけテンプレートがチラッと見える…」
あの FOUC(Flash of Uncompiled Content) 問題ですね。

これを解決するのに、Vueは実はシンプルな仕組みを用意しています。
それが v-cloak です。

「Vue が準備できるまで、対象要素を一時的に非表示にしておく」
ただそれだけ。でも効果はかなり大きいです。

ここでは、HTML構成 / Pug構成を並列でまとめておきます。

✅ 手順は3つだけ

1. CSSに [v-cloak]{display:none}グローバル に書く
2. 隠したい要素に v-cloak 属性を付ける
3. Vueがマウントされると 自動で v-cloak が外れる(=表示される)

ポイント:[v-cloak] の CSS は scoped ではなくグローバル に置くこと

1) 最小サンプル(Vue CDN)

VueをCDNから使う構成です。

💡 A) HTML版(index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>v-cloak demo (HTML)</title>
  <style>
    [v-cloak] { display: none; }
  </style>
</head>
<body>
  <div id="app" v-cloak>
    <h1>{{ title }}</h1>
    <p>現在時刻:{{ now }}</p>
  </div>

  <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
  <script>
    const App = {
      data() { return { title: "v-cloakでチラ見え防止!", now: new Date().toLocaleString() } }
    }
    Vue.createApp(App).mount('#app')
  </script>
</body>
</html>

💡 B) Pug版(index.pugindex.html に生成)

doctype html
html(lang="ja")
  head
    meta(charset="UTF-8")
    title v-cloak demo (Pug)
    style.
      [v-cloak] { display: none; }
  body
    #app(v-cloak)
      h1 {{ title }}
      p 現在時刻:{{ now }}

    script(src="https://unpkg.com/vue@3/dist/vue.global.prod.js")
    script.
      const App = {
        data() { return { title: "v-cloakでチラ見え防止!", now: new Date().toLocaleString() } }
      }
      Vue.createApp(App).mount('#app')

生成例:

pug index.pug --out .

2) Vite / webpack でも同じ考え方です

🧰 A) HTML構成(Vite index.html

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>v-cloak × Vite</title>
    <link rel="stylesheet" href="/src/assets/global.css" />
  </head>
  <body>
    <div id="app" v-cloak></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>
/src/assets/global.css
[v-cloak]{ display:none; }
/src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import './assets/global.css'

createApp(App).mount('#app')

💡 B) Pug構成(index.pug → 事前ビルド)

doctype html
html(lang="ja")
  head
    meta(charset="UTF-8")
    title v-cloak × Vite (Pug)
    link(rel="stylesheet" href="/src/assets/global.css")
  body
    #app(v-cloak)
    script(type="module" src="/src/main.ts")

3) うまくいかないときチェックリスト

なんだかうまくいかない時は以下を見直してみましょう。

チェック項目 OKの状態
CSSの場所 [v-cloak]グローバル にある
読み込み順 CSSが遅れて適用されると一瞬見える → <head>で先に読み込む
セレクタ .v-cloak ではなく [v-cloak]
マウント Vue.createApp(...).mount('#app') のIDが一致している

4) データ準備を待ちたい時は v-if を併用する

<div id="app" v-cloak>
  <div v-if="loaded">読み込み完了!</div>
  <div v-else>読み込み中…</div>
</div>

こうすると二段構えになります。

v-cloak → Vueが動くまで隠す
v-if="loaded" → データ取得が終わるまで隠す

おわりに

v-cloak は「Vue の準備ができるまで静かに隠しておく」だけのシンプルな仕組みですが、
初期表示の印象がガラッと変わります。

毎日勉強、知らないこといっぱいです。また実験して遊びましょう〜!

読んでくださってありがとうございました🐒

それではまた!