おそらく、次のどちらかの状況に直面しているはずです。
画面が平坦で未完成に見え、単なる雛形ではなく製品らしい背景やボタンを作りたい。あるいは、すでにReact Nativeのグラデーションを追加しようとしたものの、解説の半分がExpo用で、残りの半分がBareプロジェクト前提であるために、セットアップで詰まっている状態です。
この分断こそが、多くのチュートリアルが役に立たなくなる原因です。APIコンポーネント自体はシンプルですが、環境の選択はそうではありません。React Nativeで整った線形グラデーションをセットアップできるかどうかは、 colors propsよりも、Expo管理ワークフローを使っているか、あるいはネイティブのリンキングやPods、テスト用のモックを自分で扱う必要があるかによって決まります。
目次
- React Nativeアプリにグラデーションが必要な理由
- ExpoとBare React Native、どちらのセットアップを選ぶ?
- UI要素向けグラデーションの基本テクニック
- アニメーションでグラデーションを動かす
- パフォーマンス、アクセシビリティ、プラットフォーム固有のクセ
- トラブルシューティングと最終的なベストプラクティス
React Nativeアプリにグラデーションが必要な理由
モバイルUIが失敗する理由は、多くの場合共通しています。レイアウトや余白、タイポグラフィに問題がなくても、画面がどこか「死んでいる」ように感じられることがあります。単色塗り(Solid fill)だけでは、他のビジュアル要素が非常に作り込まれていない限り、すべてがプレースホルダーのように見えてしまいます。
ある React Nativeでの線形グラデーション をcodeで最小限に抑えつつ解決するコンポーネントがあります。グラデーションは奥行きを与え、セクション間の区切りを作り、優先度の高い要素に明確な視覚的ウェイトをもたらします。優れたグラデーション背景はログイン画面に意図を感じさせ、優れたグラデーションボタンは、重いシャドウや派手すぎるボーダーを使わずに、主要なアクションを直感的に伝えます。
著者: 2019年までに、expo-linear-gradient と react-native-linear-gradient は React Native プロジェクトの42%以上で使用されていました。これは、グラデーションがもはやニッチなエフェクトではないことを示す強力な指標です。これらは、後付けの装飾ではなく、プロダクションアプリにおける標準的なUIツールとなっています。詳細は こちらの React Native グラデーション採用に関する記事.
グラデーションが得意なこと
- 奥行きを作る: 単色のフラットな背景だけの画面は、未完成に見えがちです。上から下への微妙なブレンドを加えるだけで、表面にレイヤー感(層)が生まれます。
- 視覚的な誘導: メインのCTA、オンボーディングカード、ヒーローヘッダーが、ノイズを増やさずに際立ちます。
- 画像アセットの置き換え: 多くの場合、グラデーションを使えば、追加の背景画像を配信することなく洗練された見た目を実現できます。
実践的なルール: 階層が重要なところにグラデーションを使いましょう。背景、ヒーローカード、CTAサーフェス、メディアオーバーレイが特に効果的です。フォームフィールド、密度の高いリスト、本文コピーのコンテナには通常不要です。
ここにはプロダクトデザインの観点もあります。クロスプラットフォームで開発するチームは、すでにインターフェースの一貫性を保つことに時間をかけています。それが自分のスタックの一部なら、これらも モバイルアプリ向けのクロスプラットフォームUI/UXプラクティスは、 同じ考え方とうまく噛み合います。アセットを減らし、再利用可能なサーフェスを増やし、どの画面でも通用するビジュアルシステムを築くことです。
ExpoとBare React Native、どちらのセットアップを選ぶ?
ここが最も苦労する分岐点です。API のレンダリング結果は両方のライブラリでほぼ同じに見えますが、セットアップは異なります。
Expo管理のアプリなら、 expo-linear-gradientを使用してください。Bare React Nativeアプリなら、 react-native-linear-gradientを使用してください。明確な理由がない限り、その線引きを曖昧にしないでください。

Expoでのセットアップ
Expoの方がスムーズです。インストールは簡単で、バージョンの整合性も自動で管理され、ネイティブリンキングを意識する必要もありません。
インストール方法:
npx expo install expo-linear-gradient
使い方は以下の通りです:
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
export default function App() {
return (
<LinearGradient
colors={['#0f172a', '#1d4ed8']}
style={styles.container}
>
<Text style={styles.text}>Hello gradient</Text>
</LinearGradient>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
text: {
color: '#fff',
fontSize: 24,
fontWeight: '700',
},
});
素早いセットアップ、合理的なデフォルト設定、ネイティブ特有の複雑さの少なさを求めるなら、Expoが最適な選択肢です。そのため、高度なExpoワークフローを検討しているチームは、よく次を比較します。 live updates のための Capgo と Expo EAS マネージドな開発手法ではアプリの要件を満たせなくなった場合です。
Bare React Nativeでのセットアップ
Bare React Native はネイティブモジュールへの直接アクセスが可能ですが、その分、複雑な管理も自分たちで行う必要があります。
パッケージをインストール:
npm install react-native-linear-gradient
iOS の場合は、pods をインストールしてください:
cd ios && pod install
基本的な使い方:
import React from 'react';
import { StyleSheet, Text } from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
export default function App() {
return (
<LinearGradient
colors={['#111827', '#7c3aed']}
style={styles.container}
>
<Text style={styles.text}>Hello gradient</Text>
</LinearGradient>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
text: {
color: '#fff',
fontSize: 24,
fontWeight: '700',
},
});
Bareプロジェクトがよく壊れるポイント
多くのチュートリアルで不足しているのは、テストとネイティブのセットアップです。これによると このStack Overflowディスカッションの要約, 2024年から2025年にかけて、このトピックに関するStack Overflowのスレッドの68%が、bare React Native環境でのネイティブモジュールの失敗に関連していますまた、同ソースではJestのモックやiOS CocoaPodsの競合に関する問題も繰り返し指摘されています。
bareアプリでJestを使う場合は、モックを明示的に追加してください:
// jest.setup.js
import mockRNLinearGradient from 'react-native-linear-gradient/jest/linear-gradient-mock';
jest.mock('react-native-linear-gradient', () => mockRNLinearGradient);
そして、Jestの設定でそのセットアップファイルを参照してください:
module.exports = {
preset: 'react-native',
setupFiles: ['<rootDir>/jest.setup.js'],
};
bare React Nativeはグラデーションを問題なく扱えます。ただ、不完全なセットアップには寛容ではありません。ほとんどの失敗は表示上のバグではなく、linking、pods、またはテスト環境の問題です。
実用的な判断表はこちらです:
| プロジェクトタイプ | ライブラリ | 最適 |
|---|---|---|
| Expo管理アプリ | expo-linear-gradient |
最短ルート、最小限のセットアップ |
| Bare React Native アプリ | react-native-linear-gradient |
ネイティブ機能をフル活用 |
| Jest を使用した Bare アプリ | react-native-linear-gradient + mock |
テストの安定性を維持するために必要 |
UI要素向けグラデーションの基本テクニック
よくある手法は、少数のグラデーションパターンを使い回すことです。背景、ボタン、見出し。この3つをしっかり作り込めば、多くの画面で再利用できます。

役立つメンタルモデルは以下の通りです:
colorsカラーパレットを制御startとend方向を制御locations色の変化(遷移)する場所を制御
スプラッシュ画面や onboarding のエントリー画面にグラデーションを使用する場合、こちらの記事で解説しているスタートアップシーケンスのパターンと自然に組み合わせることができます。 React Native スプラッシュ画面ガイド.
フルスクリーンの背景グラデーション
これは最もシンプルで再利用性の高いパターンです。
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
// For bare RN, switch to:
// import LinearGradient from 'react-native-linear-gradient';
export default function WelcomeScreen() {
return (
<LinearGradient
colors={['#0f172a', '#1e293b', '#2563eb']}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={styles.container}
>
<View style={styles.content}>
<Text style={styles.title}>Welcome back</Text>
<Text style={styles.subtitle}>Your workspace is ready.</Text>
</View>
</LinearGradient>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 24,
},
title: {
color: '#fff',
fontSize: 32,
fontWeight: '800',
marginBottom: 8,
},
subtitle: {
color: 'rgba(255,255,255,0.8)',
fontSize: 16,
},
});
斜めのブレンドは、デフォルトの垂直方向よりもダイナミックな印象を与えます。そのため、 start={{ x: 0, y: 0 }} と end={{ x: 1, y: 1 }} 画面の大部分が装飾的な場合には、良いデフォルト設定になります。
色を単体で選ばないでください。実際のテキスト、アイコン、ステータスバーのスタイルと組み合わせてテストしましょう。Figmaで綺麗に見えても、コンテンツを重ねた瞬間に使いにくくなることがあります。
ボタンとしての挙動を維持したグラデーションボタン
よくある間違いは、グラデーション自体に直接タッチ動作を設定し、disabled状態やプレス時のフィードバック、パディングの一貫性を忘れてしまうことです。ボタンのセマンティクスを保ち、グラデーションはあくまで視覚レイヤーとして扱いましょう。
import React from 'react';
import {
Pressable,
StyleSheet,
Text,
ViewStyle,
StyleProp,
} from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
type Props = {
title: string;
onPress: () => void;
disabled?: boolean;
style?: StyleProp<ViewStyle>;
};
export function GradientButton({
title,
onPress,
disabled = false,
style,
}: Props) {
return (
<Pressable onPress={onPress} disabled={disabled} style={style}>
{({ pressed }) => (
<LinearGradient
colors={
disabled
? ['#94a3b8', '#94a3b8']
: pressed
? ['#7c3aed', '#2563eb']
: ['#8b5cf6', '#3b82f6']
}
start={{ x: 0, y: 0.5 }}
end={{ x: 1, y: 0.5 }}
style={styles.button}
>
<Text style={styles.label}>{title}</Text>
</LinearGradient>
)}
</Pressable>
);
}
const styles = StyleSheet.create({
button: {
minHeight: 52,
borderRadius: 14,
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 20,
},
label: {
color: '#fff',
fontSize: 16,
fontWeight: '700',
},
});
ボタンの場合、斜めよりも水平方向のグラデーションの方が読みやすいことが多いです。ラベルが安定し、コントロールが傾いているような違和感を避けることができます。
マスクを使用したグラデーションテキスト
これは最も目を引くパターンですが、控えめに使うのがコツです。ヒーロータイトル、アップグレードバナー、空状態(empty-state)の見出しなどが適しています。段落テキストには向きません。
必要なもの: @react-native-masked-view/masked-view.
npm install @react-native-masked-view/masked-view
次に、テキストマスクを作成します:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import MaskedView from '@react-native-masked-view/masked-view';
import { LinearGradient } from 'expo-linear-gradient';
export default function GradientHeadline() {
return (
<View style={styles.container}>
<MaskedView
maskElement={
<View style={styles.maskWrapper}>
<Text style={styles.title}>Premium analytics</Text>
</View>
}
>
<LinearGradient
colors={['#22c55e', '#06b6d4', '#3b82f6']}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
locations={[0, 0.5, 1]}
>
<Text style={[styles.title, styles.hiddenText]}>Premium analytics</Text>
</LinearGradient>
</MaskedView>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 24,
},
maskWrapper: {
backgroundColor: 'transparent',
},
title: {
fontSize: 34,
fontWeight: '800',
letterSpacing: -1,
},
hiddenText: {
opacity: 0,
},
});
locations ある色を別の色よりも強調したい場合に重要になります。色が濁って見える場合は、まず色の数を減らしてみてください。各カラーストップを微調整するよりも、その方が早くデザインが改善されます。
アニメーションでグラデーションに命を吹き込む
静的なグラデーションは洗練さを与え、アニメーション付きのグラデーションはフィードバックを与えます。
最も実用的な使い道は、派手な背景ではなく「シマーローダー」です。このエフェクトは、アプリが動作中であること、データが読み込み中であること、そして表示されているレイアウトがバグではなく意図的なものであることをユーザーに伝えます。

シマーコンポーネントは、他のモーションパターンとも相性が良いです。アプリですでにアニメーションアイコンやローダーを使用している場合、これは React NativeでのLottieガイド グラデーションのシマーで十分なケースと、よりリッチなアニメーションアセットを採用すべきケースを判断するのに役立ちます。
ネイティブ感のあるシマーローダー
最もシンプルで信頼できる実装は、 react-native-reanimated を使って、クリップしたプレースホルダー上でグラデーションの帯を動かすことです。
アプリにまだ Reanimated が入っていない場合はインストールし、次に以下でラッパーを作成します overflow: 'hidden'その中で、グラデーションレイヤーを左から右へアニメーションさせます。
import React, { useEffect } from 'react';
import { StyleSheet, View, ViewStyle, StyleProp } from 'react-native';
import { LinearGradient } from 'expo-linear-gradient';
import Animated, {
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
Easing,
} from 'react-native-reanimated';
const AnimatedView = Animated.createAnimatedComponent(View);
type Props = {
width?: number | string;
height?: number;
borderRadius?: number;
style?: StyleProp<ViewStyle>;
};
export function ShimmerPlaceholder({
width = '100%',
height = 16,
borderRadius = 8,
style,
}: Props) {
const translateX = useSharedValue(-220);
useEffect(() => {
translateX.value = withRepeat(
withTiming(220, {
duration: 1200,
easing: Easing.linear,
}),
-1,
false
);
}, [translateX]);
const animatedStyle = useAnimatedStyle(() => ({
transform: [{ translateX: translateX.value }],
}));
return (
<View
style={[
styles.container,
{ width, height, borderRadius },
style,
]}
>
<AnimatedView style={[styles.shimmer, animatedStyle]}>
<LinearGradient
colors={['rgba(255,255,255,0)', 'rgba(255,255,255,0.35)', 'rgba(255,255,255,0)']}
start={{ x: 0, y: 0.5 }}
end={{ x: 1, y: 0.5 }}
style={styles.gradient}
/>
</AnimatedView>
</View>
);
}
const styles = StyleSheet.create({
container: {
overflow: 'hidden',
backgroundColor: '#e5e7eb',
},
shimmer: {
...StyleSheet.absoluteFillObject,
width: 220,
},
gradient: {
flex: 1,
},
});
この手法のポイントは、グラデーションの定義そのものをアニメーションさせようとしないことです。静的なプレースホルダーの上でグラデーションレイヤーを動かします。これにより、実装がシンプルになり、ロジックが理解しやすくなり、デバイス間での安定性も向上します。
実際の動作イメージはこちらです:
アニメーションコンポーネント
実装時の注意点:
- クリッピングを使う: 親要素に
overflow: 'hidden'が必要です。そうしないと、シマーが角丸からはみ出してしまいます。 - 帯幅は狭く: 面全体をアニメーションさせるよりも、小さなレイヤーを動かす方が調整が容易です。
- ベースカラーを画面に合わせる: Skeleton loaderは、独立したウィジェットのように見せるのではなく、周囲のレイアウトに馴染ませるべきです。
アニメーション付きのグラデーションは、ユーザーがほとんど気づかない程度がベストです。シマーが画面内で最も目立ってしまうようでは、やりすぎです。
パフォーマンス、アクセシビリティ、プラットフォーム固有のクセ
グラデーションをデモ画面から本番環境へ移すと、考慮すべき点が変わります。code 自体はシンプルに見えますが、レンダリングの挙動、可読性、プラットフォーム間の一貫性が、初期のエフェクトよりも重要になってきます。
アプリ全体のレスポンスを高めたいなら、こちらが モバイルアプリのパフォーマンス最適化ガイド 同じ考え方に沿っています。不要な処理を減らし、実機で計測し、ユーザーが最もよく目にする部分を最適化しましょう。
パフォーマンスチェックリスト
Nativeのグラデーションは一般的に効率的ですが、それでも使い方を誤ることはあります。
- 大きな装飾画像よりグラデーションを推奨します: グラデーションの方が配信がシンプルで、さまざまな画面サイズにも適応しやすいです。
- フルスクリーンのレイヤーを重ねすぎないようにしましょう: 背景グラデーション1つなら問題ありません。半透明グラデーションの重ね掛けにBlur、重いアニメーションまで加わるとコストがかさみます。
- 再利用するコンポーネントはメモ化しましょう: リスト内でグラデーションカードを使う場合はpropsを安定させ、無関係な親の状態変化で再レンダリングしないようにしてください。
グラデーションは過剰にせず、構造的に使うのが基本です。密度の高いフィードの全行ではなく、サーフェス(面)の定義に使いましょう。
アクセシビリティチェックリスト
グラデーションは面の中でコントラストが変わるため、可読性をすぐに損ないがちです。
- 最も明るい領域に対してテキストをテストしてください: 白いテキストがブレンドの暗い側でしか読めないなら、そのデザインは成立していません。
- 必要に応じてScrim(半透明オーバーレイ)を追加しましょう: 配色全体を変えるよりも、背景とテキストの間に薄いダークオーバーレイを重ねる方が効果的な場合が多いです。
- グラデーションテキストは、大きなディスプレイコピーに限定しましょう: 見出しには適していますが、小さなラベルやヘルパーテキスト、タスク完了に不可欠な要素には不向きです。
グラデーションの中で最も美しい部分ではなく、最も視認性が悪くなる箇所を確認してください。
プラットフォームごとの注意点チェックリスト
iOSとAndroidは通常、同じグラデーションをほぼ同様にレンダリングしますが、常に完璧とは限りません。
| 問題 | 解決に役立つヒント |
|---|---|
| プラットフォーム間でグラデーションの見た目が異なる場合 | 色の数を減らし、カラーストップ間のコントラストを明確にする |
| 角丸でグラデーションが切り取られないようにする | を overflow: 'hidden' コンテナに適用する |
| グラデーションが全く表示されない場合 | 幅、高さ、または flex: 1 最初に |
ステータスバーとセーフエリアの扱いにも注意してください。シミュレーターでバランス良く見えても、ノッチのあるデバイスでは、コンテンツと背景がその余白を考慮していないと、上部に重すぎる印象を与えることがあります。
トラブルシューティングと最終的なベストプラクティス
プロジェクトのメモに残しておくべき要約です。
- ワークフローに合わせたライブラリの選択:
expo-linear-gradientExpo管理アプリの場合:react-native-linear-gradientBare React Nativeの場合: - グラデーションを効果的に使う: 背景、CTA、オーバーレイ、ヒーローテキストなどが主なユースケースです。
- 方向を意図的に制御する: ボタンには水平、装飾的な背景には斜め、大きなテキストにはマスクのみを使用します。
- 空の状態ではなく、コンテンツを想定して設計する: 実際のテキスト、アイコン、ステータスバーの表示でテストしてください。
- Bare環境のセットアップはネイティブ設定として扱う: Pods、リンキング、Jestのモックは省略できない重要な工程です。
よくある3つの失敗パターンを紹介します。
グラデーションが表示されない
原因: コンポーネントにサイズが指定されていません。
解決策: コンポーネントに flex: 1明示的な height を指定するか、親要素にサイズを持たせてください。レイアウトボックスがないグラデーションは正しくレンダリングされません。
インストール後に iOS ビルドが失敗する
原因: pods がインストールされていないか、ネイティブの依存関係グラフが同期されていません。
解決策: 次を実行してください。 pod install における ios必要に応じて build フォルダをクリーンアップしてから、アプリを再ビルドします。Bare プロジェクトでは、パッケージのインストールだけでは不十分な場合が多いです。
ネイティブモジュールのエラーでテストが失敗する
原因: Jest が実際のネイティブモジュールをロードしようとしています。
解決策: モックを作成してください react-native-linear-gradient を使用して react-native-linear-gradient/jest/linear-gradient-mock Jestのsetupファイルに。
このガイド全体で一つだけ持ち帰るなら、これです。グラデーション自体は簡単です。手間がかかるのは本番対応のセットアップです。アプリのアーキテクチャに合うライブラリを選べば、その後は格段に予測しやすくなります。
チームでハイブリッドモバイルアプリを提供していて、ストア審査を待たずにJavaScript、CSS、コピー、設定、アセットの更新を配信したいなら、 Capgo 一見の価値があります。CapacitorJSやElectronのチームに、デプロイプロセスをブラックボックス化することなく、制御されたLive Updates、ロールアウトチャネル、ロールバック保護、リリースの可視性を提供します。