Containers & Padding
In CSS every HTML element is a box with padding, margin, border, width, and height. Flutter does not have a CSS box model — instead it has dedicated widgets for each concern. This sounds verbose at first, but it makes the layout intent explicit and composable.
The three widgets you will reach for most often are Container (all-in-one box), Padding (spacing only), and SizedBox (fixed dimensions or gaps).
The Flutter box vocabulary
Section titled “The Flutter box vocabulary”| CSS property | Flutter widget / property |
|---|---|
padding: 16px | Padding(padding: EdgeInsets.all(16)) |
padding: 8px 16px | EdgeInsets.symmetric(vertical: 8, horizontal: 16) |
padding: 4px 8px 12px 16px | EdgeInsets.only(top: 4, right: 8, bottom: 12, left: 16) |
margin: 8px | Wrap parent in Padding, or use Container(margin: ...) |
width: 200px; height: 100px | SizedBox(width: 200, height: 100) |
width: 100% | SizedBox(width: double.infinity) |
background-color, border-radius, box-shadow, border | Container(decoration: BoxDecoration(...)) |
width: 200px; background: blue; border-radius: 8px | Container(width: 200, decoration: BoxDecoration(color: Colors.blue, borderRadius: ...)) |
Three box widgets and when to use each
Section titled “Three box widgets and when to use each”Padding — use when you only need spacing around a child. It is lighter than Container because it has no painting cost.
SizedBox — use when you need a fixed size, or as a gap between widgets (SizedBox(height: 16) is idiomatic vertical spacing).
Container — use when you need multiple visual properties at once: color, padding, margin, border, border-radius, or shadow. Do not use Container just for padding — use Padding instead.
Runnable example
Section titled “Runnable example”import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFFF5F5F5),
appBar: AppBar(title: const Text('Containers & Padding')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16), // Padding on ScrollView
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: 16,
children: [
// ------- Padding only -------
const _Label('Padding — all sides 16px'),
Padding(
padding: const EdgeInsets.all(16),
child: Container(color: Colors.blue[100],
child: const Text('Content with padding')),
),
// ------- SizedBox as gap + fixed size -------
const _Label('SizedBox — fixed 200x60'),
Center(
child: SizedBox(
width: 200, height: 60,
child: Container(color: Colors.green[200],
alignment: Alignment.center,
child: const Text('200 x 60')),
),
),
// ------- Container — full box model -------
const _Label('Container — color + border-radius + shadow'),
Container(
padding: const EdgeInsets.all(20),
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.08),
blurRadius: 10, offset: const Offset(0, 4)),
],
),
child: const Text('This card uses BoxDecoration'),
),
// ------- EdgeInsets.only -------
const _Label('EdgeInsets.only — asymmetric padding'),
Container(
color: Colors.orange[100],
padding: const EdgeInsets.only(
top: 4, right: 8, bottom: 12, left: 24),
child: const Text('top:4 right:8 bottom:12 left:24'),
),
],
),
),
),
);
}
}
class _Label extends StatelessWidget {
final String text;
const _Label(this.text);
@override
Widget build(BuildContext context) => Text(text,
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12,
color: Colors.grey));
}