반응형 타이포그래피 및 구성 요소 테마
텍스트 크기를 조정하고 구성 요소 테마를 사용자 지정해 여러 기기에서 일관된 브랜드 표현을 유지합니다.
반응형 타이포그래피 및 구성 요소 테마은(는) CoddyKit의 무료 Flutter Mobile Development 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Flutter Mobile Development 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Flutter Mobile Development 강의에는 총 4개의 강의가 포함되어 있습니다.
이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.
Why Typography Scales
A design system keeps your app's look consistent across phones, foldables, and tablets. Two pillars hold it together: typography (how text looks at every size) and component theming (how buttons, cards, and inputs are styled once and reused everywhere).
In Material 3, both live inside ThemeData. Instead of styling each widget by hand, you define the rules centrally and let widgets inherit them. This lesson shows how to scale text responsively and customize component themes for consistent cross-device branding.
- TextTheme carries the type scale (display, headline, title, body, label).
- Component themes (e.g.
ElevatedButtonThemeData) shape each widget family.
The Material 3 Type Scale
Material 3 defines a type scale of 15 named styles grouped into 5 roles. Each role has Large, Medium, and Small variants:
displayLarge/Medium/Small— big, expressive hero text.headlineLarge/Medium/Small— section headers.titleLarge/Medium/Small— list and dialog titles.bodyLarge/Medium/Small— paragraphs and main content.labelLarge/Medium/Small— buttons, captions, chips.
You read these from context anywhere in your widget tree, so a heading always matches the same scale no matter where it appears.
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Welcome', style: textTheme.displaySmall),
Text('Your daily summary', style: textTheme.titleMedium),
Text('Here is what happened today.', style: textTheme.bodyMedium),
],
);
}Customizing the TextTheme
To brand your typography, override the textTheme on ThemeData. A clean approach is to start from a base text theme and copyWith only the styles you want to change. This keeps the rest of the Material defaults intact.
Notice how each style is a TextStyle with explicit fontSize, fontWeight, and letterSpacing. Defining them in one place guarantees consistency across every screen.
final ThemeData appTheme = ThemeData(
useMaterial3: true,
textTheme: const TextTheme(
displaySmall: TextStyle(
fontSize: 36,
fontWeight: FontWeight.w700,
letterSpacing: -0.5,
),
titleMedium: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
bodyMedium: TextStyle(
fontSize: 14,
height: 1.4,
),
),
);Responsive Sizing with MediaQuery
Hard-coded font sizes look great on one device but cramped or oversized on another. Use MediaQuery to read the screen width and pick a scale factor. A common pattern: clamp a base size between a minimum and a maximum so text never gets absurdly small or large.
Here we compute a responsive headline size from the available width, then apply it on top of the theme's style with copyWith.
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
// Scale headline between 24 and 40 based on width.
final headlineSize = (width / 14).clamp(24.0, 40.0);
final base = Theme.of(context).textTheme.headlineMedium;
return Text(
'Cross-device branding',
style: base?.copyWith(fontSize: headlineSize),
);
}Respecting the User's Text Scale
Accessibility matters: users can enlarge system text. In modern Flutter, read this via MediaQuery.textScalerOf(context), which returns a TextScaler. Avoid disabling it outright; instead clamp it so very large settings don't break your layout while still honoring the user's preference.
Wrap a subtree in MediaQuery with a clamped scaler to bound the growth.
Widget build(BuildContext context) {
final scaler = MediaQuery.textScalerOf(context)
.clamp(minScaleFactor: 1.0, maxScaleFactor: 1.6);
return MediaQuery(
data: MediaQuery.of(context).copyWith(textScaler: scaler),
child: const Text('Readable yet bounded'),
);
}A Pure-Dart Responsive Helper
The scaling logic itself is plain Dart and easy to unit-test in isolation, no Flutter needed. Below is a small function that maps a screen width to a font size with a linear ramp between two breakpoints, then clamps the result. Testing this pure logic separately keeps your widgets thin.
double responsiveFontSize(
double width, {
double minWidth = 320,
double maxWidth = 840,
double minSize = 14,
double maxSize = 22,
}) {
if (width <= minWidth) return minSize;
if (width >= maxWidth) return maxSize;
final t = (width - minWidth) / (maxWidth - minWidth);
return minSize + t * (maxSize - minSize);
}
void main() {
print(responsiveFontSize(300)); // 14.0 (clamped)
print(responsiveFontSize(580)); // ~17.0
print(responsiveFontSize(900)); // 22.0 (clamped)
}Introducing Component Themes
Beyond text, Material 3 lets you theme entire widget families centrally. Each has a dedicated *ThemeData slot on ThemeData:
elevatedButtonTheme,filledButtonTheme,textButtonThemecardTheme,chipTheme,appBarThemeinputDecorationThemefor text fields
Set them once and every matching widget inherits the styling. This is the heart of a design system: change the brand in one file, see it everywhere.
Theming Elevated Buttons
Use ElevatedButtonThemeData with a ButtonStyle to standardize padding, shape, and text style for every ElevatedButton in the app. Tying the button's label style back to labelLarge keeps it aligned with your type scale.
Because the theme supplies these defaults, individual buttons stay clean: ElevatedButton(onPressed: ..., child: Text('Save')) with no inline styling.
final elevatedButtonTheme = ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
),
),
);Theming Cards and Inputs
Cards and text fields are everywhere in mobile UIs, so theming them pays off fast. CardThemeData controls elevation, shape, and margin; InputDecorationTheme standardizes borders, fills, and label behavior for every TextField.
With these in place, a form looks consistent across the app without repeating decoration code on each field.
final cardTheme = CardThemeData(
elevation: 1,
margin: const EdgeInsets.all(8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
);
final inputDecorationTheme = InputDecorationTheme(
filled: true,
contentPadding: const EdgeInsets.all(16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
);Assembling the Full ThemeData
Now combine typography and component themes into a single ThemeData. Pairing it with a ColorScheme.fromSeed gives you a coherent Material 3 palette. Pass this theme to MaterialApp(theme: ...) and the whole app picks it up.
This one object is your design system's source of truth: brand colors, type scale, and component styling, all together.
ThemeData buildBrandTheme() {
return ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF6750A4)),
textTheme: const TextTheme(
titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
bodyMedium: TextStyle(fontSize: 14, height: 1.4),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
cardTheme: CardThemeData(
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
);
}Reading the Theme in Widgets
Once the theme is set, widgets should pull styling from it rather than hard-coding values. Use Theme.of(context) to access the textTheme, colorScheme, and any component theme.
This makes your widgets theme-agnostic: switch to a dark theme or rebrand, and they update automatically because they never assumed a specific color or size.
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Account', style: theme.textTheme.titleMedium),
const SizedBox(height: 8),
Text(
'Manage your profile and settings.',
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
],
),
),
);
}Quick Check
You want every TextField in your app to share the same rounded, filled border without repeating decoration code on each field. Which approach fits a Material 3 design system best?
Recap
You built the typography and component foundation of a Material 3 design system:
- Type scale: the 15 named styles (display, headline, title, body, label) read via
Theme.of(context).textTheme. - Custom TextTheme: override fonts and sizes centrally with
copyWith. - Responsive sizing: derive sizes from
MediaQuerywidth andclampthem, and respect (but bound) the user'stextScalerfor accessibility. - Component themes:
ElevatedButtonThemeData,CardThemeData, andInputDecorationThemestyle entire widget families once. - Single source of truth: assemble everything into one
ThemeDatawithColorScheme.fromSeed, then read it in theme-agnostic widgets.
The result is consistent cross-device branding that adapts to screen size and user preferences without per-widget styling.
자주 묻는 질문
“반응형 타이포그래피 및 구성 요소 테마” 강의는 무료인가요?
네 — “반응형 타이포그래피 및 구성 요소 테마” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Flutter Mobile Development 강의 전체를 잠금 해제할 수 있습니다. Flutter Mobile Development 강의에는 총 4개의 강의가 포함되어 있습니다.
“반응형 타이포그래피 및 구성 요소 테마”에서 뭘 배우나요?
텍스트 크기를 조정하고 구성 요소 테마를 사용자 지정해 여러 기기에서 일관된 브랜드 표현을 유지합니다. 브라우저에서 직접 실행하는 실습 코드로 Flutter Mobile Development을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Flutter Mobile Development을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Flutter Mobile Development은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“반응형 타이포그래피 및 구성 요소 테마” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Flutter Mobile Development 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Flutter Mobile Development 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- Material 3 색 구성표 및 시드 색상
- 동적 색상 및 적응형 라이트·다크 테마
- 브랜드 토큰을 위한 사용자 지정 ThemeExtension
- 반응형 타이포그래피 및 구성 요소 테마