第7章 React Nativeのスタイリング
StyleSheet APIの書き方に加えて、FlexboxのデフォルトがcolumnであることやSafeAreaの扱いなど、Webとずれる部分を確認します。
本章では、コアコンポーネントに見た目を与える方法を扱います。React NativeはCSSを直接使えませんが、JavaScriptオブジェクトとしてスタイルを書けるStyleSheet APIが標準で用意されています。本書ではこれを基本方針とします。最後にコラムとして、Tailwindライクな選択肢にも触れます。
StyleSheet API
最もよく使う書き方を見ます。
import { View, Text, StyleSheet } from "react-native";
function Card() {
return (
<View style={styles.card}>
<Text style={styles.title}>タイトル</Text>
<Text style={styles.body}>本文</Text>
</View>
);
}
const styles = StyleSheet.create({
card: {
padding: 16,
borderRadius: 8,
backgroundColor: "#fff",
gap: 8,
},
title: {
fontSize: 18,
fontWeight: "bold",
},
body: {
fontSize: 14,
color: "#666",
},
});
StyleSheet.createに渡すのは、CSSプロパティ名をキャメルケースに直したオブジェクトです。background-colorはbackgroundColor、font-weightはfontWeightになります。
StyleSheet.createを使う利点は、
- TypeScriptで型補完が効く
- スタイルオブジェクトに対する内部的な最適化が効く
の2点です。インラインで<View style={{ padding: 16 }}>と書いても動きますが、よく使うスタイルはStyleSheet.createにまとめておくのが定石です。
配列でスタイルを合成する
スタイルを複数組み合わせたい場合は、配列にして渡します。
function Card({ isSelected }: { isSelected: boolean }) {
return <View style={[styles.card, isSelected && styles.cardSelected]} />;
}
後ろに書いたスタイルが優先されます。条件付きスタイルも、配列の中で&&や三項演算子を使えば素直に書けます。
値の単位
第3章で触れたとおり、数値はそのままdpとして扱われます。padding: 16は16dpを意味し、デバイスの密度に応じて自動で実ピクセルに変換されます。
色は"#fff"、"red"、"rgba(0, 0, 0, 0.5)"などの文字列です。Webの感覚と同じです。
Flexboxの挙動の違い
第3章でも触れましたが、ここでもう少し具体的に整理します。
デフォルトがcolumn
すべての<View>は最初からdisplay: flex相当で、flex-directionのデフォルトはcolumnです。Webと逆向きなので、横に並べたい時は明示的にrowを指定します。
// 縦に並ぶ(デフォルト)
<View>
<Text>1</Text>
<Text>2</Text>
</View>
// 横に並べたい
<View style={{ flexDirection: "row" }}>
<Text>1</Text>
<Text>2</Text>
</View>
「縦スクロールが基本のモバイル画面」に最適化された結果です。慣れると縦が基本のほうが楽な場面が多いです。
よく使うプロパティ
レイアウトでよく使うのは次のあたりです。Webと書き方は同じです。
flex: 1― 親の余白を埋めるflexDirection: "row" | "column"justifyContent: "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | "space-evenly"― 主軸方向の配置alignItems: "flex-start" | "center" | "flex-end" | "stretch" | "baseline"― 交差軸方向の配置gap: 8― 子要素間のすき間(row-gap/column-gapもあります)
ない・限定されているプロパティ
参考までに、Webでは使えるけれどReact Nativeでは使えない/限定的なものを挙げておきます。
display: grid系 ― CSS Gridは現状サポートされていません(2026年に向けて議論中)position: fixed― 存在しない。absoluteとrelativeは使えるinline-block/inline― displayは基本flexのみbackground-image― 直接は指定できない。画像は<Image>で配置する
「Webと同じプロパティ名で書ける範囲はそのまま使える、そうでないものは別の方法で組む」と覚えておけば十分です。
SafeAreaの扱い
モバイル特有の概念として、SafeArea(ノッチや角丸、ホームインジケータの領域を避ける範囲)があります。
iPhoneの上部のノッチ、Dynamic Island、下部のホームインジケータと重なる位置に重要なUIを置くと、見えなくなったり操作しにくくなったりします。これを避けるためにSafeAreaの概念があります。

SafeAreaの外側は表示できない領域ではありませんが、重要な情報や操作UIを置くのには向きません。

Expo Routerを使ったプロジェクトでは、SafeAreaの土台(SafeAreaProvider)がアプリ全体に最初から仕込まれているので、各画面ではSafeAreaViewで囲むだけ、もしくはuseSafeAreaInsetsで値を取って自分で余白に反映するだけで使えます。
importするSafeAreaViewは必ず**react-native-safe-area-context**から取ってください。react-native本体にも同名のコンポーネントがありますが、こちらはiOSのみ対応で挙動が古く、Androidでは効きません。本書も以降はreact-native-safe-area-contextの方を使います。
import { SafeAreaView } from "react-native-safe-area-context";
function Screen() {
return (
<SafeAreaView style={{ flex: 1 }}>
{/* この中はSafeArea内に収まる */}
</SafeAreaView>
);
}
微調整が必要な場合は、useSafeAreaInsetsで「上下左右のSafeArea余白(insets)」を取り出して、自分でpadding等に反映します。
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { View } from "react-native";
function Screen() {
const insets = useSafeAreaInsets();
return <View style={{ paddingTop: insets.top }} />;
}
なお、Expo Routerを使わない構成では、自分でアプリ全体をSafeAreaProviderでラップする必要があります(react-native-safe-area-contextのドキュメント参照)。
プラットフォーム別スタイル
iOSとAndroidで微妙にUIを変えたい場面はよくあります。3つのやり方があります。
Platform.OS で分岐する
import { Platform } from "react-native";
const styles = StyleSheet.create({
header: {
paddingTop: Platform.OS === "ios" ? 44 : 24,
},
});
簡単に分岐できますが、複雑になると読みにくくなります。
Platform.select を使う
const styles = StyleSheet.create({
header: {
...Platform.select({
ios: { paddingTop: 44, fontFamily: "Helvetica" },
android: { paddingTop: 24, fontFamily: "Roboto" },
}),
},
});
オブジェクト単位で切り替えられます。同じプロパティを複数差し替える場合はこちらが読みやすいです。
.ios.tsx / .android.tsx でファイルごと分ける
ロジックレベルでまったく違う実装を出し分けたい場合は、ファイル名で分岐します。
HeaderBar.ios.tsx
HeaderBar.android.tsx
HeaderBar.tsx // フォールバック
import HeaderBar from "./HeaderBar"と書くと、Metroが自動で適切なファイルを選んでくれます。コードの差が大きい場合はこの方式が一番すっきりします。
(コラム) Tailwindライクなスタイリング ― NativeWindとUniwind
Web側でTailwind CSSを使い慣れていると、StyleSheet APIに少し物足りなさを感じるかもしれません。React Nativeでも、Tailwindライクな書き心地を提供するライブラリがいくつかあります。
代表的な選択肢は2つです。
NativeWind
Tailwind CSSをReact Nativeで使えるようにする老舗のライブラリです。
import { View, Text } from "react-native";
<View className="p-4 bg-white rounded-lg">
<Text className="text-lg font-bold">タイトル</Text>
</View>
Tailwindの構文をそのまま使えるので、Web開発の感覚に近いです。v5でTailwind CSS v4対応も進んでいます。Expo公式Skillsのexpo-tailwind-setupはNativeWind v5を扱っています。
Uniwind
Unistylesチームが新しく出している、パフォーマンスを重視したライブラリです。
import { View, Text } from "react-native";
<View tw="p-4 bg-white rounded-lg">
<Text tw="text-lg font-bold">タイトル</Text>
</View>
書き心地はNativeWindとほぼ同じですが、内部のスタイル解決方式が異なり、より高速で安定したパフォーマンスを出せると言われています。無料版でも十分使え、Pro版もあります。
著者としてはTailwindライクなスタイリングが好みならUniwindを推奨します。理由はパフォーマンスとアーキテクチャの素直さです。NativeWindがすでにチームに馴染んでいるなら無理に乗り換える必要はありません。Uniwindを実際に触った感触はNativeWindの対抗馬?ハイパフォーマンスのUniwindでReact Nativeをスタイリングに書いています。
ここに挙げた以外にもTamaguiなどの選択肢があります。それぞれを実運用したうえでの比較はTamagui を1年運用して分かった、React Native スタイリングの選び方【2025年版】にまとめてあるので、チームで方針を決める前に目を通しておくと判断材料が増えます。
本書の方針
本書のサンプルコードは、原則として標準のStyleSheet APIで進めます。理由は、
- 依存ライブラリを最小に保てる
- React Nativeのスタイル概念をそのまま学べる
- パフォーマンスが安定している
の3点です。Tailwindライクな書き方が好みであれば、各章のStyleSheetをUniwindで書き換える練習として読み替えてください。プロパティ名は同じなので、置き換えはそれほど難しくありません。
(コラム) スタイル定数を活かしたアプローチ ― ALF
NativeWindやUniwindとは別系統のアプローチとして、スタイル定数(atom)を集めた小さなフレームワークを自前で組み、それを使い回す流派もあります。代表例が、SNSアプリBlueskyが採用している**ALF (Application Layout Framework)**です。
ALFは、Tailwind的なUtility First思想をStyleSheet APIの上で表現するもので、atoms.flex_row、t.atoms.bgのような定数を組み合わせてスタイルを当てます。
import { atoms, useTheme } from "#/alf";
function Card() {
const t = useTheme();
return <View style={[atoms.flex_row, atoms.p_md, t.atoms.bg]} />;
}
ライブラリではなく、プロジェクト内に小さなフレームワークを作る発想なので、
- 依存ライブラリを増やさず、StyleSheet APIの素直な使い方の延長で組める
- テーマ(ライト/ダーク)、ブレークポイント、デザイントークンの管理を一箇所に集約できる
- ライブラリの破壊的変更に振り回されない
といった利点があります。NativeWindやUniwindほどシンタックスシュガーは強くありませんが、長期メンテナンスを重視するチームに合うアプローチです。実装の参考はBluesky側のソースや、ALFについての解説記事が良い入り口になります。
本章のまとめ
- StyleSheet APIが基本。プロパティ名はキャメルケース、単位は数値(dp)
- Flexboxは
columnがデフォルト。横に並べたい時は明示的にrow - SafeAreaは
react-native-safe-area-contextで対応 - プラットフォーム差はPlatform.OS / Platform.select /
.ios.tsx/.android.tsxの3通り - TailwindライクならUniwindが現時点の推奨。本書はStyleSheet API基本
次章では、ユーザーからの入力 ― タップとキーボード入力の扱いを見ていきます。