CSS 屬性對照
內容: CSS 常用屬性與 Flutter Widget 屬性的逐一對照,每個部分都是可直接運行的 Widget demo。
涵蓋 10 個模塊:
| 模塊 | CSS | Flutter |
|---|---|---|
| 盒模型 | width/height/padding/margin/border/border-radius | Container + BoxDecoration |
| 文字樣式 | font-size/color/font-weight/letter-spacing/line-height/text-decoration | TextStyle |
| Flex 佈局 | display:flex/flex-direction/justify-content/align-items/flex-wrap/gap/flex:1 | Row/Column/Expanded/Wrap |
| 定位 | position:relative/absolute/fixed/top/left/z-index | Stack + Positioned |
| 尺寸約束 | width:100%/max-width/min-width/fit-content | SizedBox/ConstrainedBox/IntrinsicWidth |
| 變換 | transform:rotate/scale/translate | Transform.rotate/scale/translate |
| 顯示隱藏 | display:none/visibility:hidden/opacity:0 | Visibility/Opacity + 三元表達式 |
| 陰影 | box-shadow/text-shadow | BoxShadow/Shadow |
| 漸變 | linear-gradient/radial-gradient | LinearGradient/RadialGradient |
| 響應式 | @media (max-width: 600px) | MediaQuery.of(context).size.width |
运行
在线效果可以复制到:dartpad.dev/ 查看,更推荐本地flutter build web调试学习
效果图
学习代码
import 'package:flutter/material.dart';
// ============================================================
// CSS → Flutter 完整对照手册
// ============================================================
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: Scaffold(body: CssToFlutter()));
}
}
class CssToFlutter extends StatelessWidget {
const CssToFlutter({super.key});
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
_BoxModel(),
_TextStyle(),
_FlexLayout(),
_PositionLayout(),
_SizeConstraint(),
_Transform(),
_Visibility(),
_Shadow(),
_Gradient(),
_Responsive(),
],
),
);
}
}
// ============================================================
// 一、盒模型
// CSS: width / height / padding / margin / border / border-radius / background
// ============================================================
class _BoxModel extends StatelessWidget {
const _BoxModel();
@override
Widget build(BuildContext context) {
return Container(
// CSS: width: 200px
width: 200,
// CSS: height: 200px
height: 200,
// CSS: margin: 20px
margin: const EdgeInsets.all(20),
// CSS: padding: 16px
padding: const EdgeInsets.all(16),
// CSS: padding: 10px 20px → 上下10 左右20
// padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
// CSS: padding: 10px 20px 30px 40px → 上右下左
// padding: const EdgeInsets.fromLTRB(40, 10, 20, 30),
decoration: BoxDecoration(
// CSS: background: blue
color: Colors.blue,
// CSS: border-radius: 20px
borderRadius: BorderRadius.circular(20),
// CSS: border-radius: 10px 20px 30px 40px
// borderRadius: const BorderRadius.only(
// topLeft: Radius.circular(10),
// topRight: Radius.circular(20),
// bottomRight: Radius.circular(30),
// bottomLeft: Radius.circular(40),
// ),
// CSS: border: 3px solid yellow
border: Border.all(width: 3, color: Colors.yellow),
// CSS: border-top: 3px solid red → 单边边框
// border: const Border(top: BorderSide(width: 3, color: Colors.red)),
),
child: const Text('盒模型'),
);
}
}
// ============================================================
// 二、文字样式
// CSS: font-size / color / font-weight / font-style / letter-spacing /
// line-height / text-align / text-decoration / overflow
// ============================================================
class _TextStyle extends StatelessWidget {
const _TextStyle();
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'文字样式示例',
style: const TextStyle(
// CSS: font-size: 24px
fontSize: 24,
// CSS: color: red
color: Colors.red,
// CSS: font-weight: bold
fontWeight: FontWeight.bold,
// CSS: font-weight: 300
// fontWeight: FontWeight.w300,
// CSS: font-style: italic
fontStyle: FontStyle.italic,
// CSS: letter-spacing: 2px
letterSpacing: 2,
// CSS: line-height: 1.5
height: 1.5,
// CSS: text-decoration: underline
decoration: TextDecoration.underline,
// CSS: text-decoration: line-through
// decoration: TextDecoration.lineThrough,
),
// CSS: text-align: center
textAlign: TextAlign.center,
// CSS: overflow: hidden; white-space: nowrap; text-overflow: ellipsis
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
// CSS: text-transform: uppercase → Flutter 无内置,用 .toUpperCase()
Text('hello'.toUpperCase()),
],
);
}
}
// ============================================================
// 三、Flex 布局
// CSS: display:flex / flex-direction / justify-content /
// align-items / flex-wrap / gap / flex:1
// ============================================================
class _FlexLayout extends StatelessWidget {
const _FlexLayout();
@override
Widget build(BuildContext context) {
return Column(
children: [
// CSS: display:flex; flex-direction: row; justify-content: space-between; align-items: center
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // justify-content
crossAxisAlignment: CrossAxisAlignment.center, // align-items
children: const [
Text('左'),
Text('中'),
Text('右'),
],
),
// CSS: display:flex; flex-direction: column; align-items: center
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Text('上'),
Text('中'),
Text('下'),
],
),
// CSS: flex: 1(占满剩余空间)
Row(
children: [
Expanded(
child: Container(color: Colors.red, height: 40)), // flex: 1
Expanded(
child: Container(color: Colors.blue, height: 40)), // flex: 1
],
),
// CSS: flex: 2 / flex: 1(按比例)
Row(
children: [
Expanded(
flex: 2,
child: Container(color: Colors.green, height: 40)), // flex: 2
Expanded(
flex: 1,
child: Container(color: Colors.orange, height: 40)), // flex: 1
],
),
// CSS: flex-wrap: wrap; gap: 8px
Wrap(
spacing: 8, // CSS: column-gap
runSpacing: 8, // CSS: row-gap
children: List.generate(
6,
(i) => Container(
width: 80,
height: 40,
color: Colors.purple,
child: Center(child: Text('item $i')),
),
),
),
// justify-content 对照表:
// flex-start → MainAxisAlignment.start
// flex-end → MainAxisAlignment.end
// center → MainAxisAlignment.center
// space-between → MainAxisAlignment.spaceBetween
// space-around → MainAxisAlignment.spaceAround
// space-evenly → MainAxisAlignment.spaceEvenly
// align-items 对照表:
// flex-start → CrossAxisAlignment.start
// flex-end → CrossAxisAlignment.end
// center → CrossAxisAlignment.center
// stretch → CrossAxisAlignment.stretch
// baseline → CrossAxisAlignment.baseline
],
);
}
}
// ============================================================
// 四、定位
// CSS: position: relative/absolute/fixed、top/left/right/bottom、z-index
// ============================================================
class _PositionLayout extends StatelessWidget {
const _PositionLayout();
@override
Widget build(BuildContext context) {
return SizedBox(
width: 200,
height: 200,
// CSS: position: relative(父容器)
child: Stack(
children: [
// 普通流中的元素
Container(color: Colors.grey),
// CSS: position: absolute; top: 10px; left: 10px; z-index: 1
const Positioned(
top: 10,
left: 10,
child: Text('左上角'),
),
// CSS: position: absolute; bottom: 0; right: 0
const Positioned(
bottom: 0,
right: 0,
child: Text('右下角'),
),
// CSS: position: absolute; top:50%; left:50%; transform: translate(-50%,-50%)
const Positioned.fill(
child: Align(
alignment: Alignment.center,
child: Text('居中'),
),
),
// Stack 里越靠后的 child z-index 越高,对应 CSS z-index
],
),
);
}
}
// ============================================================
// 五、尺寸与约束
// CSS: width / height / max-width / min-width / max-height / min-height / box-sizing
// ============================================================
class _SizeConstraint extends StatelessWidget {
const _SizeConstraint();
@override
Widget build(BuildContext context) {
return Column(
children: [
// CSS: width: 200px; height: 50px
const SizedBox(width: 200, height: 50),
// CSS: width: 100%(撑满父级宽度)
const SizedBox(width: double.infinity, height: 50),
// CSS: max-width: 300px; min-width: 100px
ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 100,
maxWidth: 300,
minHeight: 40,
maxHeight: 100,
),
child: Container(color: Colors.teal),
),
// CSS: width: fit-content(包裹内容)
IntrinsicWidth(
child:
Container(color: Colors.amber, child: const Text('fit-content')),
),
],
);
}
}
// ============================================================
// 六、变换
// CSS: transform: rotate / scale / translate
// ============================================================
class _Transform extends StatelessWidget {
const _Transform();
@override
Widget build(BuildContext context) {
return Column(
children: [
// CSS: transform: rotate(0.05rad)
Transform.rotate(
angle: 0.05,
child: Container(width: 100, height: 50, color: Colors.blue),
),
// CSS: transform: scale(1.5)
Transform.scale(
scale: 1.5,
child: Container(width: 100, height: 50, color: Colors.green),
),
// CSS: transform: translate(20px, 10px)
Transform.translate(
offset: const Offset(20, 10),
child: Container(width: 100, height: 50, color: Colors.red),
),
],
);
}
}
// ============================================================
// 七、显示与隐藏
// CSS: display: none / visibility: hidden / opacity: 0
// ============================================================
class _Visibility extends StatelessWidget {
const _Visibility();
@override
Widget build(BuildContext context) {
return Column(
children: [
// CSS: display: none(不占位,从树中移除)
Visibility(
visible: false,
child: Container(width: 100, height: 50, color: Colors.red),
),
// CSS: visibility: hidden(占位,但不可见)
Visibility(
visible: false,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
child: Container(width: 100, height: 50, color: Colors.red),
),
// CSS: opacity: 0.5
Opacity(
opacity: 0.5,
child: Container(width: 100, height: 50, color: Colors.blue),
),
// 简单显隐:三元表达式(display:none 等价)
// condition ? MyWidget() : const SizedBox.shrink(),
],
);
}
}
// ============================================================
// 八、阴影
// CSS: box-shadow / text-shadow
// ============================================================
class _Shadow extends StatelessWidget {
const _Shadow();
@override
Widget build(BuildContext context) {
return Column(
children: [
// CSS: box-shadow: 4px 4px 8px rgba(0,0,0,0.3)
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color(0x4D000000), // rgba(0,0,0,0.3)
offset: Offset(4, 4), // x, y
blurRadius: 8, // blur
spreadRadius: 0, // spread
),
],
),
),
// CSS: text-shadow: 2px 2px 4px rgba(0,0,0,0.5)
const Text(
'文字阴影',
style: TextStyle(
shadows: [
Shadow(
color: Color(0x80000000),
offset: Offset(2, 2),
blurRadius: 4,
),
],
),
),
],
);
}
}
// ============================================================
// 九、渐变
// CSS: background: linear-gradient / radial-gradient
// ============================================================
class _Gradient extends StatelessWidget {
const _Gradient();
@override
Widget build(BuildContext context) {
return Column(
children: [
// CSS: background: linear-gradient(to right, red, blue)
Container(
width: 200,
height: 60,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft, // to left
end: Alignment.centerRight, // to right
colors: [Colors.red, Colors.blue],
),
),
),
// CSS: background: linear-gradient(135deg, red, blue)
Container(
width: 200,
height: 60,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Colors.red, Colors.blue],
),
),
),
// CSS: background: radial-gradient(circle, red, blue)
Container(
width: 200,
height: 60,
decoration: const BoxDecoration(
gradient: RadialGradient(
colors: [Colors.red, Colors.blue],
),
),
),
],
);
}
}
// ============================================================
// 十、响应式
// CSS: @media (max-width: 600px)
// ============================================================
class _Responsive extends StatelessWidget {
const _Responsive();
@override
Widget build(BuildContext context) {
// CSS: @media 等价于读取屏幕尺寸
final screenWidth = MediaQuery.of(context).size.width;
final screenHeight = MediaQuery.of(context).size.height;
final isSmall = screenWidth < 600;
return Column(
children: [
// CSS: @media (max-width: 600px) { font-size: 14px } else { font-size: 20px }
Text(
'响应式文字',
style: TextStyle(fontSize: isSmall ? 14 : 20),
),
// CSS: @media (max-width: 600px) { flex-direction: column }
isSmall
? const Column(children: [Text('A'), Text('B')])
: const Row(children: [Text('A'), Text('B')]),
Text('屏幕宽: $screenWidth, 高: $screenHeight'),
],
);
}
}