0Pricing
React Native Academy · 강의

Flexbox 방향, JustifyContent, AlignItems

flexDirection, justifyContent, alignItems를 사용해 View 안에서 자식 요소를 가운데 배치하고 간격을 조정하며 정렬하는 방식을 제어합니다.

Flexbox 방향, JustifyContent, AlignItems은(는) CoddyKit의 무료 React Native Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 React Native Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

Flexbox Is the Default Layout System

React Native uses Flexbox as its layout algorithm for every View component — there is no block or inline layout like in CSS. Every View is automatically a Flex container, meaning its children are positioned according to Flexbox rules by default. The key difference from web CSS Flexbox is that React Native's default flexDirection is 'column', not 'row' like on the web. This means children stack vertically by default, which matches how most mobile screens are laid out.

import { View, StyleSheet } from 'react-native';

export default function DefaultFlex() {
  return (
    // No flexDirection needed — 'column' is the default
    <View style={styles.container}>
      <View style={styles.box1} />
      <View style={styles.box2} />
      <View style={styles.box3} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: '#f5f5f5', padding: 16 },
  box1: { height: 60, backgroundColor: '#ff6b6b', marginBottom: 8 },
  box2: { height: 60, backgroundColor: '#4f86f7', marginBottom: 8 },
  box3: { height: 60, backgroundColor: '#51cf66' },
});

flexDirection: row vs column

flexDirection sets the main axis of the Flex container. With 'column' (default), children stack top to bottom. With 'row', children sit left to right. The values 'column-reverse' and 'row-reverse' reverse the order. Changing flexDirection also changes which axis justifyContent and alignItems affect — justifyContent always works along the main axis, and alignItems along the cross axis. This is the single most impactful Flexbox property to understand.

import { View, StyleSheet } from 'react-native';

export default function DirectionDemo() {
  return (
    <View style={{ flex: 1, gap: 16, padding: 16 }}>
      {/* Column: children stack vertically (default) */}
      <View style={{ flexDirection: 'column', height: 120, backgroundColor: '#f0f0f0' }}>
        <View style={styles.box} />
        <View style={styles.box} />
      </View>

      {/* Row: children sit side by side */}
      <View style={{ flexDirection: 'row', height: 60, backgroundColor: '#f0f0f0' }}>
        <View style={styles.box} />
        <View style={styles.box} />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  box: { width: 50, height: 50, backgroundColor: '#4f86f7', margin: 4 },
});

justifyContent: Aligning Along the Main Axis

justifyContent controls how children are distributed along the main axis (vertical for column, horizontal for row). The most useful values are: 'flex-start' (pack at start, default), 'flex-end' (pack at end), 'center' (center the group), 'space-between' (first and last touch the edges, equal gaps between others), 'space-around' (equal space around each child), and 'space-evenly' (equal space including edges). 'space-between' is particularly common for navigation bars and action button rows.

import { View, Text, StyleSheet } from 'react-native';

export default function SpaceBetween() {
  return (
    <View style={styles.row}>
      <Text style={styles.tab}>Home</Text>
      <Text style={styles.tab}>Search</Text>
      <Text style={styles.tab}>Profile</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
    justifyContent: 'space-between', // distribute across full width
    paddingHorizontal: 24,
    paddingVertical: 16,
    backgroundColor: '#fff',
    borderTopWidth: 1,
    borderTopColor: '#eee',
  },
  tab: { fontSize: 14, color: '#666' },
});

alignItems: Aligning Along the Cross Axis

alignItems controls how children are positioned on the cross axis (perpendicular to the main axis). For a column container it aligns children horizontally; for a row container it aligns them vertically. Values: 'flex-start' (default for column on Android, items hug the start), 'flex-end', 'center', and 'stretch' (items expand to fill the cross axis — this is the default on iOS and makes sense for column layouts where you want full-width children). 'baseline' aligns text baselines of children.

import { View, Text, StyleSheet } from 'react-native';

export default function AlignDemo() {
  return (
    <View style={styles.container}>
      {/* Row: alignItems centers children vertically */}
      <View style={styles.row}>
        <Text style={styles.smallText}>Small</Text>
        <Text style={styles.largeText}>LARGE</Text>
        <Text style={styles.smallText}>Small</Text>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20 },
  row: {
    flexDirection: 'row',
    alignItems: 'center', // vertically center all items
    backgroundColor: '#e8f0fe',
    padding: 16,
    borderRadius: 8,
  },
  smallText: { fontSize: 12, color: '#666', marginHorizontal: 8 },
  largeText: { fontSize: 28, fontWeight: 'bold', color: '#111', marginHorizontal: 8 },
});

Centering Content with flex, justify, and align

A very common pattern is centering content both vertically and horizontally — for splash screens, empty states, or loading indicators. Set the container to flex: 1 so it fills available space, then apply justifyContent: 'center' and alignItems: 'center'. Since the default flexDirection is column, this centers children in the middle of the screen both vertically and horizontally. This three-property combination is probably the most-used layout recipe in React Native.

import { View, Text, StyleSheet } from 'react-native';

export default function CenteredScreen() {
  return (
    <View style={styles.container}>
      <Text style={styles.emoji}>🎯</Text>
      <Text style={styles.title}>Nothing here yet</Text>
      <Text style={styles.subtitle}>Add your first item to get started</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center', // vertical center (column main axis)
    alignItems: 'center',     // horizontal center (column cross axis)
    backgroundColor: '#f8f9fa',
  },
  emoji: { fontSize: 56, marginBottom: 16 },
  title: { fontSize: 22, fontWeight: 'bold', color: '#333' },
  subtitle: { fontSize: 14, color: '#999', marginTop: 8, textAlign: 'center' },
});

alignSelf: Overriding Cross-Axis Alignment

alignSelf overrides the parent's alignItems for a specific child. It accepts the same values as alignItems: 'auto' (use parent's setting), 'flex-start', 'flex-end', 'center', and 'stretch'. This is useful when most siblings share one alignment but one child needs different treatment — for example, a row of icons where one is larger and should align to the top while the others center. Use alignSelf sparingly; it's more maintainable to adjust the parent's alignItems and use wrapper Views when needed.

import { View, Text, StyleSheet } from 'react-native';

export default function AlignSelfExample() {
  return (
    <View style={styles.row}>
      <View style={styles.boxSmall} />
      {/* This box aligns to flex-end independently */}
      <View style={[styles.boxSmall, { alignSelf: 'flex-end', backgroundColor: 'red' }]} />
      <View style={styles.boxSmall} />
    </View>
  );
}

const styles = StyleSheet.create({
  row: {
    flexDirection: 'row',
    alignItems: 'center', // default for siblings
    height: 100,
    backgroundColor: '#e8f0fe',
    padding: 8,
    gap: 8,
  },
  boxSmall: { width: 50, height: 50, backgroundColor: '#4f86f7', borderRadius: 6 },
});

gap, rowGap, and columnGap

Instead of adding margin to each child, use gap on the container to set uniform spacing between flex children. gap sets both row and column gaps, while rowGap and columnGap control them independently. This eliminates the need for marginBottom on all but the last child, or the hack of adding negative margin to the container. Gap support was added in React Native 0.71 (available in Expo SDK 48+), so check your RN version before using it in older projects.

import { View, StyleSheet } from 'react-native';

export default function GapExample() {
  return (
    <View style={styles.container}>
      {[1, 2, 3, 4].map(n => (
        <View key={n} style={styles.card} />
      ))}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    flexWrap: 'wrap',
    gap: 12,           // equal gap between all children
    padding: 16,
    backgroundColor: '#f5f5f5',
  },
  card: {
    width: '47%',      // two columns
    height: 100,
    backgroundColor: '#4f86f7',
    borderRadius: 10,
  },
});

flexWrap: Wrapping Children to Next Lines

By default, flex children shrink to fit in a single line and never wrap. Set flexWrap: 'wrap' on the container to let children wrap to the next row (for row direction) or next column (for column direction) when they run out of space. This is the foundation for tag clouds, grid-like layouts with percentage widths, and any UI where items should flow onto the next line naturally. 'nowrap' is the default; 'wrap-reverse' wraps in the opposite direction.

import { View, Text, StyleSheet } from 'react-native';

const tags = ['React Native', 'Mobile', 'iOS', 'Android', 'JavaScript', 'Flexbox', 'Expo'];

export default function TagCloud() {
  return (
    <View style={styles.container}>
      {tags.map(tag => (
        <View key={tag} style={styles.tag}>
          <Text style={styles.tagText}>{tag}</Text>
        </View>
      ))}
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flexDirection: 'row', flexWrap: 'wrap', gap: 8, padding: 16 },
  tag: { backgroundColor: '#e8f0fe', paddingHorizontal: 12, paddingVertical: 6, borderRadius: 16 },
  tagText: { color: '#4f86f7', fontSize: 13, fontWeight: '500' },
});

A Practical Header Layout

Apply your Flexbox knowledge to build a common mobile app pattern: a navigation header with a back button on the left, a centered title, and a menu icon on the right. Use flexDirection: 'row' and alignItems: 'center' on the header container. Give the title flex: 1 so it expands to fill the remaining space and centers itself between the fixed-width side icons. This is cleaner than using position: 'absolute' for centering and handles varying title lengths correctly.

import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

export default function Header({ title, onBack, onMenu }) {
  return (
    <View style={styles.header}>
      <TouchableOpacity style={styles.sideBtn} onPress={onBack}>
        <Text style={styles.icon}>←</Text>
      </TouchableOpacity>

      <Text style={styles.title} numberOfLines={1}>{title}</Text>

      <TouchableOpacity style={styles.sideBtn} onPress={onMenu}>
        <Text style={styles.icon}>⋯</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingHorizontal: 16,
    paddingVertical: 12,
    backgroundColor: '#fff',
    borderBottomWidth: StyleSheet.hairlineWidth,
    borderBottomColor: '#ddd',
  },
  sideBtn: { width: 40, alignItems: 'center' },
  title: { flex: 1, fontSize: 18, fontWeight: '600', color: '#111', textAlign: 'center' },
  icon: { fontSize: 22, color: '#333' },
});

Debugging Flexbox Layouts

Flexbox bugs are common during layout development. Useful debugging techniques: add a temporary backgroundColor to each View to make its boundaries visible, use React DevTools to inspect the computed layout in the component tree, check whether flex: 1 is missing from ancestor containers (a container without flex: 1 collapses to zero height, making its children invisible), and verify that flexDirection is the value you intend (remember, React Native defaults to column, not row). Removing all styles and adding them back one by one is a reliable way to isolate layout bugs.

// Debug technique: color-code your Views temporarily
const debugStyles = StyleSheet.create({
  container: { flex: 1, backgroundColor: 'rgba(255,0,0,0.1)' }, // red tint
  inner: { backgroundColor: 'rgba(0,0,255,0.1)' },              // blue tint
  text: { backgroundColor: 'rgba(0,255,0,0.1)' },               // green tint
});

// Then you can see exactly where each View starts and ends
// Remove these debug colors before shipping!

Row with Icon, Text, and Action

One of the most common mobile UI patterns is a list row with an icon on the left, text in the middle, and an action button on the right. Implement it with flexDirection: 'row' on the container, alignItems: 'center' to vertically align all children, a fixed-size icon View on the left, a flex: 1 text area in the middle (so it expands to fill available space), and a fixed-size action button on the right. This pattern appears in settings screens, contact lists, and any data-dense table view in mobile apps.

import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

export default function SettingsRow({ icon, label, subtitle, onPress }) {
  return (
    <TouchableOpacity style={styles.row} onPress={onPress}>
      {/* Left: icon */}
      <View style={styles.iconContainer}>
        <Text style={{ fontSize: 22 }}>{icon}</Text>
      </View>

      {/* Middle: text content — flex: 1 fills space */}
      <View style={{ flex: 1 }}>
        <Text style={styles.label} numberOfLines={1}>{label}</Text>
        {subtitle && <Text style={styles.subtitle} numberOfLines={1}>{subtitle}</Text>}
      </View>

      {/* Right: chevron */}
      <Text style={styles.chevron}>›</Text>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  row: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingVertical: 12, backgroundColor: '#fff', gap: 12 },
  iconContainer: { width: 36, height: 36, borderRadius: 8, backgroundColor: '#f0f4ff', alignItems: 'center', justifyContent: 'center' },
  label: { fontSize: 16, color: '#222' },
  subtitle: { fontSize: 13, color: '#999', marginTop: 2 },
  chevron: { fontSize: 22, color: '#ccc', fontWeight: '300' },
});

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: flexDirection sets the main axis (column by default in React Native, not row), justifyContent distributes children along the main axis, and alignItems aligns children on the cross axis. Next up we explore the flex property and responsive sizing across screen dimensions.

자주 묻는 질문

“Flexbox 방향, JustifyContent, AlignItems” 강의는 무료인가요?

네 — “Flexbox 방향, JustifyContent, AlignItems” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 React Native Academy 강의 전체를 잠금 해제할 수 있습니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“Flexbox 방향, JustifyContent, AlignItems”에서 뭘 배우나요?

flexDirection, justifyContent, alignItems를 사용해 View 안에서 자식 요소를 가운데 배치하고 간격을 조정하며 정렬하는 방식을 제어합니다. 브라우저에서 직접 실행하는 실습 코드로 React Native Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

React Native Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 React Native Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“Flexbox 방향, JustifyContent, AlignItems” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 React Native Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 React Native Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. StyleSheet.create와 인라인 스타일
  2. Flexbox 방향, JustifyContent, AlignItems
  3. flex, flexGrow 및 반응형 크기 조정
  4. 반응형 카드 격자 만들기
← React Native Academy(으)로 돌아가기