빠른 선택: 에서 Expo, 사용하세요 expo-linear-gradient. bare React Native의 경우, 사용하세요 react-native-linear-gradient. 스택에 맞는 것을 설치한 후, 다음을 렌더링하세요: LinearGradient 포함 colors 와 크기를 지정한 style (보통 flex: 1 는 배경으로 사용합니다).
Expo
bunx expo install expo-linear-gradient
Bare React Native
bun add react-native-linear-gradient
최소 사용법 (두 라이브러리 모두 같은 개념: Expo에서는 named export, bare에서는 default import).
import { LinearGradient } from 'expo-linear-gradient';
// Bare: import LinearGradient from 'react-native-linear-gradient';
<LinearGradient colors={['#0f172a', '#2563eb']} style={{ flex: 1 }} />;
네이티브 스택과 웹 퍼스트 셸 중에서 선택해야 한다면, React Native vs Capacitor Capgo 팀이 중요하게 여기는 트레이드오프를 짚어봅니다. 이 글의 나머지에서는 배경, 버튼, 마스크, 모션, 문제 해결을 다룹니다.
목차
- React Native 앱에 그라데이션이 필요한 이유
- 경로 선택: Expo vs Bare React Native 설정
- UI 요소를 위한 핵심 그라데이션 기법
- 애니메이션으로 그라데이션에 생동감 불어넣기
- 성능, 접근성 및 플랫폼별 특이사항
- 트러블슈팅 및 최종 베스트 프랙티스
React Native 앱에 그라데이션이 필요한 이유
많은 모바일 UI가 동일한 이유로 실패합니다. 레이아웃은 정갈하고, 간격도 적절하며, 타이포그래피도 무난하지만 화면은 여전히 생동감이 없습니다. 단색 배경은 나머지 시각 시스템이 많은 일을 하지 않는 한 모든 것이 플레이스홀더처럼 보이게 만듭니다.
어떤 React Native linear gradient 이 컴포넌트는 code을 아주 적게 사용하여 이를 해결합니다. 깊이를 더하고 섹션 간 구분을 명확히 하며, 우선순위가 높은 요소에 뚜렷한 시각적 무게를 부여합니다. 잘 만든 그라데이션 배경은 로그인 화면에 의도된 느낌을 줄 수 있습니다. 잘 만든 그라데이션 버튼은 무거운 그림자나 과도하게 도드라지는 테두리 없이도 주요 액션을 명확히 보여줍니다.
작성자: 2019년, expo-linear-gradient와 react-native-linear-gradient는 React Native 프로젝트의 42% 이상에서 사용되었습니다.이는 그라데이션이 더 이상 틈새 효과가 아니라 프로덕션 앱의 표준 UI 도구이며, 나중에 덧붙이는 장식이 아니라는 강력한 신호입니다. 이에 대해서는 이 React Native 그라데이션 도입 사례 글에서도 언급합니다..
그라데이션의 강점
- 깊이감 만들기: 단색 배경 하나만 있는 화면은 종종 미완성처럼 보입니다. 위에서 아래로 이어지는 은은한 블렌드는 표면에 레이어감을 더해줍니다.
- 시선 유도: 주요 CTA, 온보딩 카드, 히어로 헤더가 시각적 노이즈 없이 돋보입니다.
- 이미지 에셋 대체: 많은 경우, 그라데이션만으로 추가 배경 이미지를 싣지 않고도 완성도를 높일 수 있습니다.
실무 원칙: 계층 구조가 중요한 곳에 그라데이션을 사용하세요. 배경, 히어로 카드, CTA 영역, 미디어 오버레이에 가장 효과적입니다. 폼 필드, 밀집된 리스트, 본문 텍스트 컨테이너에는 보통 효과가 없습니다.
제품 디자인 관점도 있습니다. 크로스 플랫폼으로 작업하는 팀은 이미 인터페이스 일관성을 유지하느라 시간을 쓰고 있습니다. 여러분 스택에 이게 포함된다면, 이러한 모바일 앱을 위한 크로스 플랫폼 UI/UX 프랙티스는 같은 사고방식과 잘 맞아떨어집니다: 에셋은 줄이고, 재사용 가능한 서피스는 늘리고, 여러 화면에서도 통하는 비주얼 시스템.
경로 선택: Expo vs Bare React Native 설정
대부분의 고통이 이 갈림길에서 시작됩니다. API 렌더링은 두 라이브러리에서 거의 동일하게 느껴지지만, 설정은 다릅니다.
Expo managed 앱을 쓰고 있다면, expo-linear-gradient를 사용하세요. bare React Native 앱을 쓰고 있다면, react-native-linear-gradient를 사용하세요. 왜 그렇게 하는지 정확히 알지 못한다면, 이 경계를 흐리지 마세요.

Expo 설정
Expo가 더 수월한 경로입니다. 설치가 간단하고, 버전 매칭은 자동으로 처리되며, 네이티브 링킹은 신경 쓸 필요가 없습니다.
다음과 같이 설치하세요:
bunx 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 is the right choice when you want fast setup, sane defaults, and fewer native edges. That’s also why teams exploring advanced Expo workflows often compare Capgo와 Expo EAS의 라이브 업데이트 비교 관리형 경로가 더 이상 앱 요구사항을 충족하지 못할 때.
Bare React Native 설정
Bare React Native는 네이티브 모듈에 직접 접근할 수 있지만, 복잡한 부분은 직접 처리해야 합니다.
패키지를 설치하세요:
bun add 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 환경에서의 native module 오류와 관련되어 있으며동일한 출처에 따르면 Jest mocking 및 iOS CocoaPods 충돌 문제도 반복적으로 발생하고 있습니다.
bare 앱에서 Jest를 사용하는 경우, 다음과 같이 mock을 명시적으로 추가하세요:
// jest.setup.js
import mockRNLinearGradient from 'react-native-linear-gradient/jest/linear-gradient-mock';
jest.mock('react-native-linear-gradient', () => mockRNLinearGradient);
그리고 Jest config에서 해당 setup 파일을 참조하세요:
module.exports = {
preset: 'react-native',
setupFiles: ['<rootDir>/jest.setup.js'],
};
bare React Native에서도 그라데이션은 잘 작동합니다. 다만 설정이 불완전한 건 용납하지 않죠. 대부분의 실패는 시각적 버그가 아니라 linking, pods 또는 테스트 환경 문제입니다.
실무적인 판단 표는 다음과 같습니다:
| 프로젝트 유형 | 라이브러리 | 가장 적합 |
|---|---|---|
| Expo-managed 앱 | expo-linear-gradient |
가장 빠른 방법, 최소한의 설정 |
| Bare React Native 앱 | react-native-linear-gradient |
완전한 네이티브 제어 |
| Jest가 포함된 Bare 앱 | react-native-linear-gradient + mock |
테스트 안정성을 유지하는 데 필수 |
UI 요소를 위한 핵심 그라데이션 기법
흔한 접근법은 같은 소수의 그라디언트 패턴을 계속 재사용하는 것입니다. 배경, 버튼, 헤드라인. 이 세 가지가 탄탄하면 많은 화면에서 재사용할 수 있습니다.

유용한 멘탈 모델은 다음과 같습니다:
colors팔레트를 제어합니다start및end방향을 제어합니다locations전환이 일어나는 위치를 제어합니다
스플래시 또는 온보딩 진입 화면에 그라디언트를 사용한다면, 이 가이드에서 설명하는 더 넓은 시작 시퀀스 패턴과 자연스럽게 어울립니다. 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에서 보기 좋았던 팔레트도 콘텐츠가 올라가면 즉시 실패할 수 있습니다.
버튼 기능이 유지되는 그라데이션 버튼
여기서 흔히 하는 실수는 터치 동작을 그라데이션에 직접 적용하고, 비활성 상태나 프레스 피드백, 패딩 일관성을 놓치는 것입니다. 버튼은 시맨틱하게 유지하고, 그라데이션은 시각적 레이어로만 사용하세요.
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.
bun add @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 한 색상이 다른 색상보다 더 많은 시각적 공간을 차지하게 하고 싶을 때 가장 중요합니다. 블렌드가 탁하게 느껴진다면 색상 수를 먼저 줄여보세요. 보통 각 stop을 하나하나 조정하는 것보다 훨씬 빠르게 문제를 해결할 수 있습니다.
애니메이션으로 그라데이션에 생동감 불어넣기
정적인 그라데이션은 완성도를 높여주고, 애니메이션 그라데이션은 피드백을 줍니다.
가장 실용적인 용도는 화려한 배경이 아니라 쉬머(shimmer) 로더입니다. 이 효과는 앱이 작동 중이고, 데이터를 불러오는 중이며, 지금 보이는 레이아웃이 오류가 아닌 의도된 상태임을 사용자에게 알려줍니다.

쉬머 컴포넌트는 다른 모션 패턴과도 잘 어우러집니다. 앱에서 이미 애니메이션 아이콘이나 로더를 사용 중이라면, 이 방식이 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'이 없으면 시머가 둥근 모서리 밖으로 새어 나갑니다. - 밴드를 좁게 유지하세요: 전체 표면을 애니메이션하는 것보다 작은 애니메이션 레이어를 조정하는 것이 더 쉽습니다.
- 기본 색상을 화면에 맞추세요: 스켈레톤 로더는 별도 위젯처럼 보이지 않고 주변 레이아웃에 어울려야 합니다.
애니메이션 그라디언트는 사용자가 거의 인지하지 못할 때 가장 효과적입니다. 시머 효과가 화면에서 가장 눈에 띄는 요소가 된다면, 과한 것입니다.
성능, 접근성 및 플랫폼별 특이사항
그라디언트가 데모 화면을 넘어 프로덕션으로 넘어가면 고려 사항이 달라집니다. code는 여전히 단순해 보이지만, 렌더링 동작, 가독성, 플랫폼 일관성이 초기 효과보다 중요해지기 시작합니다.
앱 반응성을 전반적으로 개선하고 있다면, 이 모바일 앱 성능 최적화 가이드 가 같은 마인드셋을 따릅니다: 불필요한 작업을 줄이고, 실제 디바이스에서 측정하며, 사용자가 가장 많이 보는 영역을 최적화하세요.
성능 체크리스트
네이티브 그라디언트는 일반적으로 효율적이지만, 잘못 사용할 수 있습니다.
- 큰 장식용 이미지보다 그라디언트를 우선하세요: 배포가 더 깔끔하고, 다양한 화면 크기에 적응하기 쉽습니다.
- 여러 개의 전체 화면 레이어를 겹치지 마세요: 배경 그라디언트 하나면 충분합니다. 여러 겹의 반투명 그라디언트에 블러와 무거운 애니메이션을 더하면 비용이 크게 증가할 수 있습니다.
- 재사용 가능한 컴포넌트 메모이제이션: 그라디언트 카드가 리스트에 사용된다면 props를 안정적으로 유지하고, 관련 없는 부모 상태 때문에 리렌더링되지 않도록 하세요.
좋은 원칙은 그라디언트를 구조적으로만 쓰고 과하게 쓰지 않는 것입니다. 밀집된 피드의 모든 행이 아니라 표면을 정의하는 데 사용하세요.
접근성 체크리스트
표면 전체에서 대비가 변하기 때문에 그라디언트는 가독성을 빠르게 떨어뜨릴 수 있습니다.
- 가장 밝은 영역에서 텍스트를 테스트하세요: 흰색 텍스트가 블렌드의 어두운 쪽에서만 읽힌다면, 잘못된 것입니다.
- 필요하면 스크림을 추가하세요: 전체 색상을 바꾸는 것보다 배경과 텍스트 사이에 은은한 다크 오버레이를 넣는 것이 더 효과적일 때가 많습니다.
- 그라데이션 텍스트는 큰 디스플레이 카피에만 사용하세요: 헤드라인에는 잘 어울리지만, 작은 라벨이나 도움말 텍스트, 또는 작업 완료에 중요한 요소에는 적합하지 않습니다.
가장 예쁜 지점이 아니라, 그라데이션에서 가장 보기 안 좋은 지점을 확인하세요.
플랫폼별 특이사항 체크리스트
iOS와 Android는 보통 같은 그라데이션을 비슷하게 렌더링하지만, 항상 완벽하게 일치하지는 않습니다.
| 문제 | 보통 도움이 되는 방법 |
|---|---|
| 플랫폼마다 그라데이션이 다르게 보일 때 | 색상 수를 줄이고 컬러 스톱 간의 대비를 명확하게 하세요 |
| 둥근 모서리에서 그라데이션이 잘리지 않는지 확인하세요 | 넣기 overflow: 'hidden' 컨테이너에 |
| 그라데이션이 전혀 보이지 않음 | 너비, 높이를 확인하거나 flex: 1 먼저 |
상태 표시줄과 safe area 처리도 확인하세요. 시뮬레이터에서는 균형 잡혀 보여도, 노치가 있는 기기에서는 콘텐츠와 배경이 그 여백을 고려하지 않으면 상단이 너무 무거워 보일 수 있습니다.
트러블슈팅 및 최종 베스트 프랙티스
프로젝트 노트에 남겨둘 핵심 요약입니다.
- 워크플로우에 맞춰 라이브러리 선택:
expo-linear-gradientExpo managed 앱의 경우,react-native-linear-gradientBare React Native의 경우. - 그라데이션은 목적에 맞게 사용하세요: 배경, CTA, 오버레이, 히어로 텍스트 등에 활용하기 좋습니다.
- 의도적으로 방향을 제어하세요: 버튼은 수평, 장식용 배경은 대각선, 큰 텍스트에만 마스크를 적용하세요.
- 빈 상태가 아니라 콘텐츠를 기준으로 디자인하세요: 실제 텍스트, 아이콘, 상태 바 처리로 테스트하세요.
- 기본 세팅을 네이티브 세팅처럼 취급하세요: Pods, 링크, Jest 목은 선택 사항이 아닙니다.
반복적으로 발생하는 3가지 일반적인 실패 사례가 있습니다.
그라데이션이 나타나지 않는 경우
원인: 컴포넌트에 가시적인 크기가 없습니다.
해결: flex: 1, 명시적인 높이, 또는 차원(크기)이 있는 부모 요소를 지정하세요. 레이아웃 박스가 없는 그라디언트는 의미 있게 렌더링되지 않습니다.
설치 후 iOS 빌드 실패
원인: pods가 설치되지 않았거나 native dependency graph가 동기화되지 않았습니다.
해결 방법: 실행 pod install 에서 ios하고, 필요하면 build folder를 clean한 뒤 앱을 다시 빌드하세요. bare 프로젝트에서는 package install만으로는 충분하지 않은 경우가 많습니다.
native module 에러로 인한 테스트 실패
원인: Jest가 실제 native module을 로드하려고 시도하기 때문입니다.
해결 방법: mock react-native-linear-gradient 포함 react-native-linear-gradient/jest/linear-gradient-mock 을 Jest setup file에 추가하세요.
이 가이드에서 딱 한 가지만 기억해야 한다면 이것입니다. gradient 구현 자체는 쉽습니다. 진짜 핵심은 프로덕션 환경에 적합한 setup을 구축하는 것입니다. 앱 아키텍처에 맞는 라이브러리를 선택하고 나면, 그 이후의 과정은 훨씬 예측 가능해집니다.
팀에서 하이브리드 모바일 앱을 배포하며, 스토어 심사를 기다리지 않고 JavaScript, CSS, 카피, 설정 및 에셋 업데이트를 즉시 반영하고 싶다면, Capgo 한 번 살펴볼 가치가 있습니다. CapacitorJS와 Electron 팀에게 제어 가능한 Live Update, 롤아웃 채널, 롤백 보호, 릴리스 가시성을 제공하여 배포 프로세스가 블랙박스가 되지 않도록 합니다.