第15章:JSXでのインラインスタイル
— style={{}} の“二重カッコ”をマスターして、動くデザインに! —
(camelCase・単位・型・条件付きスタイル・合体テクまでぜんぶ🌸)
きょうのゴール 🎯
style={{}}の正体(外カッコ=JSX、内カッコ=オブジェクト)を理解する- camelCase のプロパティ名と単位のルールを覚える
- TypeScriptで安全に書けるようにする(
React.CSSProperties) - 動的に色/サイズ/見た目を切り替えるハンズオンを完成させる
なにが「二重カッコ」なの?🧠
- 外側
{ ... }…「JSの値を埋め込む」ためのJSXのカッコ - 内側
{ ... }…「スタイルの辞書」を表すJavaScriptオブジェクト → つまりstyle={{ ... }}= JSX埋め込み + JSオブジェクト だよ🎀
まずは最小コード ✨
export default function App() {
return (
<h1 style={{ color: "#ff69b4", backgroundColor: "lavenderblush" }}>
こんにちは、インラインスタイル💖
</h1>
);
}
- プロパティ名は camelCase:
background-color→backgroundColor - 値は 文字列 か 数値。数値は多くのプロパティで px 扱いになるよ(後述)📏
TypeScriptの型を添えて安心に 🛟
import type { CSSProperties } from "react";
const titleStyle: CSSProperties = {
color: "#663399",
letterSpacing: 1, // ← 1px として解釈される
lineHeight: 1.6, // ← これは「単位なし」プロパティ
backgroundColor: "aliceblue",
};
export default function App() {
return <h2 style={titleStyle}>TSで安全にスタイル✨</h2>;
}
React.CSSProperties(CSSProperties)を使うと補完と型チェックが効いてミス激減🌟
文字列?数値?単位のルール早見表 📋
| 例 | 書き方(JSX) | 実際のCSS |
|---|---|---|
| 幅100px | width: 100 | width: 100px |
| 余白 8px | marginTop: 8 | margin-top: 8px |
| 不透明度 0.8 | opacity: 0.8 | opacity: 0.8 |
| 行の高さ1.6 | lineHeight: 1.6 | line-height: 1.6 |
| 角丸 12px | borderRadius: 12 | border-radius: 12px |
| 角丸 0.75rem | borderRadius: "0.75rem" | border-radius: 0.75rem |
| グラデ | backgroundImage: "linear-gradient(90deg, #f0f 0%, #0ff 100%)" | 文字列でOK |
ポイント
- 数値は多くのプロパティで px 自動付与。ただし
lineHeight・opacity・zIndexなどは単位なしが素直。remや%、vwなど px以外を使いたい時は文字列で書こう📝
よく使う camelCase 一覧(ミニ)🐪
backgroundColor/borderColor/borderRadius/boxShadow/fontSizefontWeight/letterSpacing/lineHeight/textAlign/textDecorationmarginTop/marginInline/paddingBlock(論理プロパティもそのまま!)WebkitLineClamp(ベンダープレフィックスは頭を大文字で)
条件でスタイルを切り替える 🌗
三項演算子で分岐
type Props = { danger?: boolean };
export default function Badge({ danger = false }: Props) {
return (
<span
style={{
color: "white",
padding: "4px 8px",
borderRadius: 999,
backgroundColor: danger ? "crimson" : "mediumseagreen",
}}
>
{danger ? "危険" : "OK"}バッジ
</span>
);
}
undefined をうまく使う(ある時だけ上書き)
const base: React.CSSProperties = { padding: 8, borderRadius: 12 };
const emphasize = true;
const style: React.CSSProperties = {
...base,
boxShadow: emphasize ? "0 4px 12px rgba(0,0,0,.15)" : undefined,
};
...isActive && objのように&&でオブジェクトを合体させるのはNG(falseをスプレッドできないため)☠️ 代わりに 三項 かundefinedを活用しよう💡
className と style の使い分け 🎯
- **基本はCSS(またはCSS Modules)**で見た目を作り、
- **その時々で変わる“数値・色”**などを
style={{}}で差し込むのがコツ🪄 - 注意:
style(インライン)は強いので、クラスで上書きしづらいことがあるよ⚠️
Hover/Media/疑似要素は?🧐
:hoverや@media、::beforeなどはstyleでは書けない- そういう 状態やレスポンシブは CSS/Modules でやるのが王道🐾
- どうしてもJSでやるなら、状態を持って
onMouseEnter/onMouseLeaveで色を変えるなど(学習の先でまた✨)
便利レシピ集 🍳
1) アイコンサイズをまとめて指定(currentColor で色合わせ)
const iconStyle: React.CSSProperties = { width: 20, height: 20, color: "hotpink" };
export function IconHeart() {
return (
<svg viewBox="0 0 24 24" style={iconStyle}>
<path fill="currentColor" d="M12 21s-8-5.33-8-10a5 5 0 0 1 9-3 5 5 0 0 1 9 3c0 4.67-8 10-8 10z" />
</svg>
);
}
2) カードのガラス風スタイル(モダンUIっぽさ💎)
const glass: React.CSSProperties = {
background: "rgba(255,255,255,0.6)",
backdropFilter: "blur(8px)",
WebkitBackdropFilter: "blur(8px)",
borderRadius: 16,
border: "1px solid rgba(255,255,255,0.4)",
boxShadow: "0 10px 30px rgba(0,0,0,.08)",
};
export function GlassCard({ children }: { children: React.ReactNode }) {
return <div style={glass}>{children}</div>;
}
3) CSSカスタムプロパティを受け取って反映(上級)
// TypeScriptでCSS変数を渡す時は型を少し広げる
type VarStyle = React.CSSProperties & Record<string, string>;
const style: VarStyle = { ["--accent"]: "#ff69b4" };
export function AccentBox() {
return (
<div style={style} className="box">
アクセント: var(--accent) をCSS側で参照するよ🌈
</div>
);
}
ハンズオン①:サイズと色をライブ切り替え 🌈
import { useState } from "react";
export default function Playground() {
const [size, setSize] = useState(24);
const [pink, setPink] = useState(true);
const style: React.CSSProperties = {
width: size,
height: size,
borderRadius: 8,
backgroundColor: pink ? "#ff69b4" : "#4fd1c5",
transition: "all .2s ease",
};
return (
<section>
<h3>Style Playground 🎮</h3>
<div style={style} />
<div style={{ marginTop: 12 }}>
<button onClick={() => setSize((s) => Math.min(s + 8, 128))}>大きく⬆️</button>
<button onClick={() => setSize((s) => Math.max(s - 8, 16))} style={{ marginLeft: 8 }}>
小さく⬇️
</button>
<button onClick={() => setPink((p) => !p)} style={{ marginLeft: 8 }}>
色チェンジ🎨
</button>
</div>
</section>
);
}
ハンズオン②:Buttonの“状態別”スタイルを一箇所で管理 🧰
type Variant = "primary" | "ghost" | "danger";
const base: React.CSSProperties = {
padding: "10px 16px",
borderRadius: 12,
border: "1px solid transparent",
fontWeight: 600,
cursor: "pointer",
};
const styles: Record<Variant, React.CSSProperties> = {
primary: { ...base, backgroundColor: "#6b46c1", color: "white" },
ghost: { ...base, backgroundColor: "transparent", color: "#6b46c1", borderColor: "#6b46c1" },
danger: { ...base, backgroundColor: "crimson", color: "white" },
};
export function Button({ variant = "primary", children }: { variant?: Variant; children: React.ReactNode }) {
return <button style={styles[variant]}>{children}</button>;
}
状態ごとの辞書にしておくと、のちのち拡張しやすい&型で安全🍀
トラブルシュート 🧯
Type 'string' is not assignable to type 'number'→ 数値プロパティに"12"を渡してない?12か"12px"にしよう...isActive && objで落ちる →falseをオブジェクト展開できない!...(isActive ? obj : {})に置換background-colorがエラー →backgroundColorにする(camelCase!)- hoverしたいのにできない
→
styleでは無理。CSS/Modulesで:hoverを書こう
3分チェック ✅(ミニテスト)
style={{}}の外カッコと内カッコはそれぞれ何?padding: 8を渡したら実際のCSSは?lineHeightの 1.6 は文字列?数値?- プロパティ名はハイフン?camelCase?
- 条件でスタイルを合体するとき、
...isActive && sの代わりにどう書く?
こたえ
- 外=JSXの式、内=JSオブジェクト
padding: 8px- 数値(単位なし)
- camelCase(例:
backgroundColor) ...(isActive ? s : {})もしくはprop: isActive ? "値" : undefined
まとめチートシート 🧾💨
style={{ ... }}=JSX式の中にオブジェクト- camelCase・値は数値(px)/文字列を使い分け
- TSは
React.CSSPropertiesで超安心 - 動的な差分にインライン、土台はCSSで🐱🏍
- 疑似クラス・メディアは CSSで書く
次の章の予告 🎬
第16章は「部品(コンポーネント)の作り方」! 小さく分けて、読みやすい・直せる構造にしていくよ〜🧩💖