0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

こんにちは、もんすんです。

個人で「自分専用のトレンドビューア」を作っているのですが、せっかく自分しか見ないアプリなので、見た目は趣味全開のサイバーパンク調にしました。

スクリーンショット 2026-07-12 14.36.38.png

そのUIを作るときに Tailwind CSS を v4 にしたのですが、最初に手が止まりました。

「あれ、tailwind.config.ts がない。どこにカスタムカラーを書くんだ?」

v3 までしかちゃんと触ったことがなく、設定といえば tailwind.config.ts(または .js)のイメージでした。
v4 では作法が変わっています。

この記事は、v4 で tailwind.config.ts を使わずに、CSS の中だけでテーマを組み、ネオン風UIを作る実践メモです。

題材は自作の個人アプリ(アプリ名は伏せます)のデザインシステムです。
値はそのまま使えるようにコピペ可で載せています。

対象読者・前提

  • Tailwind v3 の経験があり、v4 に移りたい人
  • ネオン/グロー系の「光るUI」を CSS で作りたい人

この記事のゴール

  • v4 の @theme でカスタムカラー・フォントを定義できるようになる
  • グロー/スキャンライン/グリッドなどの「らしさ」を出すユーティリティを作れる
  • v4 で動的クラス生成がハマる理由を知る

v4 の最小セットアップ:設定はCSSの中へ

v3 と v4 で、設定の置き場所がこう変わりました。

v3 v4
読み込み @tailwind base; @tailwind components; @tailwind utilities; @import "tailwindcss";
カスタムカラー等 tailwind.config.tstheme.extend CSSの @theme ブロック
設定ファイル 必須 基本的に不要

v4 では、グローバルCSSの先頭で読み込み、そのまま @theme でトークンを宣言します。

/* globals.css */
@import "tailwindcss";

@theme {
  /* カスタムカラー(--color-* がそのままユーティリティになる) */
  --color-cyber-bg: #070b13;
  --color-cyber-card: rgba(15, 23, 42, 0.6);
  --color-neon-blue: #00f0ff;
  --color-neon-cyan: #06b6d4;
  --color-neon-pink: #ff007f;
  --color-neon-purple: #a855f7;

  /* フォント */
  --font-orbitron: var(--font-orbitron);
  --font-sans: var(--font-sans);
}

ポイントは、@theme 内で --color-cyber-bg と定義すると、bg-cyber-bg / text-cyber-bg / border-cyber-bg といったユーティリティが自動で生えることです。設定ファイルに JS のオブジェクトを書いていた時代より、だいぶ直感的になりました。

<div class="bg-cyber-bg text-neon-blue">ネオンブルーの文字</div>

アニメーションも @theme で定義できる

v4 では @theme の中に @keyframes まで書けます。--animate-* を定義すると animate-* ユーティリティになります。

@theme {
  --animate-scanline: scanline 8s linear infinite;
  --animate-cyber-pulse: cyber-pulse 2s ease-in-out infinite;

  @keyframes scanline {
    0%   { transform: translateY(-100%); }
    100% { transform: translateY(100%); }
  }
  @keyframes cyber-pulse {
    0%, 100% { opacity: 0.8; box-shadow: 0 0 15px rgba(0, 240, 255, 0.2); }
    50%      { opacity: 1;   box-shadow: 0 0 25px rgba(0, 240, 255, 0.5); }
  }
}
<div class="animate-cyber-pulse">脈動するカード</div>

設定・キーフレーム・利用が全部 CSS の中で完結します。

“サイバーパンクらしさ”を作るカスタムユーティリティ

トークンだけでは「ネオンが光る」感じは出ません。
@theme の外(通常のCSS)で、雰囲気を作るユーティリティを定義します。
すべてコピペで動きます。

1. グロー(box-shadow)

.glow-cyan-lg { box-shadow: 0 0 20px rgba(0, 240, 255, 0.35); }
.glow-cyan-sm { box-shadow: 0 0 10px rgba(0, 240, 255, 0.2); }

2. 文字グロー(text-shadow)

.text-glow-cyan { text-shadow: 0 0 8px rgba(0, 240, 255, 0.6); }
.text-glow-pink { text-shadow: 0 0 8px rgba(255, 0, 127, 0.6); }

3. CRTスキャンライン(疑似要素で重ねる)

.scanline-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    rgba(18, 16, 16, 0) 50%,
    rgba(0, 240, 255, 0.05) 50%
  );
  background-size: 100% 4px;
  z-index: 10;
  pointer-events: none; /* クリックを透過させるのが地味に重要 */
}

pointer-events: none; を忘れると、オーバーレイがクリックを食ってボタンが反応しなくなります。

4. サイバーグリッド背景

.cyber-grid {
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.01) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.01) 1px, transparent 1px);
  background-size: 20px 20px;
}

5. ついでにスクロールバーも光らせる

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: #070b13; }
::-webkit-scrollbar-thumb { background: #1e293b; border-radius: 3px; }
::-webkit-scrollbar-thumb:hover {
  background: #00f0ff;
  box-shadow: 0 0 8px #00f0ff; /* ホバーで光る */
}

細部ですが、こういう「触ったら光る」が積み重なると一気にそれっぽくなります。

カテゴリごとの色分けと、動的クラスの落とし穴

私のアプリでは、カードのカテゴリごとに左ボーダーの色を変えています。

カテゴリ
tech cyan
biz purple
x-tech pink
digest amber

ここで v4(というか Tailwind 全般)で必ず踏む落とし穴があります。
クラス名を文字列連結で動的生成すると、ビルド時にパージ(未使用クラスの削除)されて色が出ません。

// ❌ ダメ:文字列を組み立てると、スキャナがクラスを発見できずパージされる
const color = category === 'tech' ? 'cyan' : 'purple';
<div className={`border-l-${color}-400`} /> // border-l-cyan-400 が消える

// ✅ 正解:完全なクラス名をそのまま書く(マップで持つ)
const BORDER: Record<string, string> = {
  tech:   'border-l-cyan-400',
  biz:    'border-l-purple-400',
  'x-tech':'border-l-pink-400',
  digest: 'border-l-amber-400',
};
<div className={BORDER[category]} />

Tailwind はソースを静的にスキャンして使われているクラスを集めます。
「完全な文字列として存在するクラスしか拾えない」

これを忘れると「ローカルでは出てたのに本番で色が消える」になります。
どうしても動的にしたい場合は safelist を使いますが、まずは「完全なクラス名で持つ」のが王道かと思います。

ハマりどころまとめ

  • フォントは CSS変数直書きより、ユーティリティ(font-orbitron 等)で当てる
    • @theme に登録しておけばクラスで使えます
  • モバイルファーストで作る
    • 私のアプリは max-w-md で約390px幅を基準にしています
    • スマホで見るツールなら、まずこの幅で破綻しないことが最優先
  • 動的クラスはパージされる(再掲・最重要)
  • スキャンライン等の疑似要素オーバーレイは pointer-events: none; を忘れない

まとめ

Tailwind v4 は、設定が「JSの設定ファイル」から「CSSの中の @theme」へ移りました。

最初は戸惑いますが、慣れると色・フォント・アニメーションが1つのCSSファイルに集約されて見通しが良いです。

  • カスタムカラーは @theme--color-* → 自動でユーティリティ化
  • グロー/スキャンライン等は通常CSSのユーティリティで「らしさ」を足す
  • 動的クラス生成はパージで死ぬ → 完全なクラス名で持つ

ダークテーマで光らせるUIは、コスパよく「作り込んだ感」が出るのでおすすめです。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?