Skip to content

10.3 CSS Grid和Flexbox

关键词: CSS Grid, Flexbox, 网格布局, 弹性布局, 网格系统, 布局组合, 浏览器兼容性, 现代布局

学习目标

  • 深入理解CSS Grid布局的核心概念和应用
  • 掌握Flexbox布局的完整使用方法
  • 学会设计和实现响应式网格系统
  • 掌握Grid和Flexbox的组合使用技巧
  • 了解浏览器兼容性问题和解决方案

10.3.1 CSS Grid布局

CSS Grid基础概念

CSS Grid是一个二维布局系统,可以同时处理行和列的布局。它提供了强大的布局能力,是现代网页布局的重要工具。

html
<!-- CSS Grid基础示例 -->
<div class="grid-container">
    <div class="grid-item item-1">1</div>
    <div class="grid-item item-2">2</div>
    <div class="grid-item item-3">3</div>
    <div class="grid-item item-4">4</div>
    <div class="grid-item item-5">5</div>
    <div class="grid-item item-6">6</div>
</div>

<style>
    .grid-container {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-template-rows: repeat(2, 100px);
        gap: 20px;
        padding: 20px;
        background: #f5f5f5;
    }
    
    .grid-item {
        background: #2196F3;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 24px;
        font-weight: bold;
        border-radius: 8px;
    }
    
    /* 响应式调整 */
    @media (max-width: 768px) {
        .grid-container {
            grid-template-columns: 1fr;
            grid-template-rows: repeat(6, 80px);
        }
    }
</style>

Grid容器属性

html
<!-- Grid容器属性详解 -->
<div class="advanced-grid">
    <div class="grid-item header">Header</div>
    <div class="grid-item nav">Navigation</div>
    <div class="grid-item main">Main Content</div>
    <div class="grid-item sidebar">Sidebar</div>
    <div class="grid-item footer">Footer</div>
</div>

<style>
    .advanced-grid {
        display: grid;
        grid-template-columns: 200px 1fr 200px;
        grid-template-rows: auto 1fr auto;
        grid-template-areas: 
            "header header header"
            "nav main sidebar"
            "footer footer footer";
        gap: 20px;
        min-height: 100vh;
        padding: 20px;
    }
    
    .header {
        grid-area: header;
        background: #e3f2fd;
    }
    
    .nav {
        grid-area: nav;
        background: #f3e5f5;
    }
    
    .main {
        grid-area: main;
        background: #e8f5e8;
    }
    
    .sidebar {
        grid-area: sidebar;
        background: #fff3e0;
    }
    
    .footer {
        grid-area: footer;
        background: #fce4ec;
    }
    
    .grid-item {
        padding: 20px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 8px;
    }
    
    /* 响应式布局 */
    @media (max-width: 768px) {
        .advanced-grid {
            grid-template-columns: 1fr;
            grid-template-areas: 
                "header"
                "nav"
                "main"
                "sidebar"
                "footer";
        }
    }
</style>

Grid项目属性

html
<!-- Grid项目属性示例 -->
<div class="grid-items-demo">
    <div class="item item-a">A</div>
    <div class="item item-b">B</div>
    <div class="item item-c">C</div>
    <div class="item item-d">D</div>
    <div class="item item-e">E</div>
</div>

<style>
    .grid-items-demo {
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        grid-template-rows: repeat(3, 100px);
        gap: 15px;
        padding: 20px;
        background: #f9f9f9;
    }
    
    .item {
        background: #FF9800;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 20px;
        font-weight: bold;
        border-radius: 8px;
    }
    
    .item-a {
        grid-column: 1 / 3;
        grid-row: 1 / 2;
        background: #4CAF50;
    }
    
    .item-b {
        grid-column: 3 / 5;
        grid-row: 1 / 3;
        background: #2196F3;
    }
    
    .item-c {
        grid-column: 1 / 2;
        grid-row: 2 / 4;
        background: #9C27B0;
    }
    
    .item-d {
        grid-column: 2 / 3;
        grid-row: 2 / 3;
        background: #FF5722;
    }
    
    .item-e {
        grid-column: 2 / 4;
        grid-row: 3 / 4;
        background: #607D8B;
    }
</style>

自动填充和自适应

html
<!-- 自动填充和自适应示例 -->
<div class="auto-grid">
    <div class="card">卡片 1</div>
    <div class="card">卡片 2</div>
    <div class="card">卡片 3</div>
    <div class="card">卡片 4</div>
    <div class="card">卡片 5</div>
    <div class="card">卡片 6</div>
    <div class="card">卡片 7</div>
    <div class="card">卡片 8</div>
</div>

<style>
    .auto-grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
        gap: 20px;
        padding: 20px;
    }
    
    .card {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 30px;
        border-radius: 12px;
        text-align: center;
        box-shadow: 0 4px 15px rgba(0,0,0,0.2);
        transition: transform 0.3s ease;
    }
    
    .card:hover {
        transform: translateY(-5px);
    }
    
    /* 移动端优化 */
    @media (max-width: 480px) {
        .auto-grid {
            grid-template-columns: 1fr;
            gap: 15px;
            padding: 15px;
        }
    }
</style>

10.3.2 Flexbox布局

Flexbox基础概念

Flexbox是一维布局系统,主要用于处理行或列的布局。它提供了强大的对齐和分布能力。

html
<!-- Flexbox基础示例 -->
<div class="flex-container">
    <div class="flex-item">项目 1</div>
    <div class="flex-item">项目 2</div>
    <div class="flex-item">项目 3</div>
    <div class="flex-item">项目 4</div>
</div>

<style>
    .flex-container {
        display: flex;
        gap: 20px;
        padding: 20px;
        background: #f0f0f0;
        border-radius: 8px;
    }
    
    .flex-item {
        background: #4CAF50;
        color: white;
        padding: 20px;
        border-radius: 8px;
        text-align: center;
        flex: 1;
    }
    
    /* 响应式调整 */
    @media (max-width: 768px) {
        .flex-container {
            flex-direction: column;
        }
    }
</style>

Flex容器属性

html
<!-- Flex容器属性详解 -->
<div class="flex-demos">
    <!-- justify-content 示例 -->
    <div class="demo-section">
        <h3>justify-content: space-between</h3>
        <div class="flex-demo demo-justify">
            <div class="flex-box">1</div>
            <div class="flex-box">2</div>
            <div class="flex-box">3</div>
        </div>
    </div>
    
    <!-- align-items 示例 -->
    <div class="demo-section">
        <h3>align-items: center</h3>
        <div class="flex-demo demo-align">
            <div class="flex-box">1</div>
            <div class="flex-box tall">2</div>
            <div class="flex-box">3</div>
        </div>
    </div>
    
    <!-- flex-wrap 示例 -->
    <div class="demo-section">
        <h3>flex-wrap: wrap</h3>
        <div class="flex-demo demo-wrap">
            <div class="flex-box">1</div>
            <div class="flex-box">2</div>
            <div class="flex-box">3</div>
            <div class="flex-box">4</div>
            <div class="flex-box">5</div>
            <div class="flex-box">6</div>
        </div>
    </div>
</div>

<style>
    .flex-demos {
        padding: 20px;
    }
    
    .demo-section {
        margin-bottom: 30px;
    }
    
    .demo-section h3 {
        margin-bottom: 10px;
        color: #333;
    }
    
    .flex-demo {
        display: flex;
        background: #f8f9fa;
        border: 2px solid #dee2e6;
        border-radius: 8px;
        padding: 20px;
        min-height: 80px;
    }
    
    .demo-justify {
        justify-content: space-between;
    }
    
    .demo-align {
        align-items: center;
    }
    
    .demo-wrap {
        flex-wrap: wrap;
        gap: 10px;
    }
    
    .flex-box {
        background: #007bff;
        color: white;
        padding: 15px;
        border-radius: 6px;
        min-width: 60px;
        text-align: center;
        font-weight: bold;
    }
    
    .flex-box.tall {
        padding: 25px 15px;
    }
    
    /* 响应式调整 */
    @media (max-width: 768px) {
        .flex-demo {
            flex-direction: column;
            align-items: stretch;
        }
        
        .demo-justify {
            justify-content: center;
        }
    }
</style>

Flex项目属性

html
<!-- Flex项目属性示例 -->
<div class="flex-items-demo">
    <div class="flex-item-container">
        <div class="flex-item-1">flex: 1</div>
        <div class="flex-item-2">flex: 2</div>
        <div class="flex-item-3">flex: 1</div>
    </div>
    
    <div class="flex-item-container">
        <div class="flex-item-grow">flex-grow: 1</div>
        <div class="flex-item-shrink">flex-shrink: 2</div>
        <div class="flex-item-basis">flex-basis: 200px</div>
    </div>
</div>

<style>
    .flex-items-demo {
        padding: 20px;
    }
    
    .flex-item-container {
        display: flex;
        gap: 15px;
        margin-bottom: 20px;
        padding: 20px;
        background: #f8f9fa;
        border-radius: 8px;
    }
    
    .flex-item-container > div {
        background: #6c757d;
        color: white;
        padding: 20px;
        border-radius: 6px;
        text-align: center;
        min-width: 0;
    }
    
    .flex-item-1 {
        flex: 1;
        background: #28a745 !important;
    }
    
    .flex-item-2 {
        flex: 2;
        background: #007bff !important;
    }
    
    .flex-item-3 {
        flex: 1;
        background: #dc3545 !important;
    }
    
    .flex-item-grow {
        flex-grow: 1;
        background: #17a2b8 !important;
    }
    
    .flex-item-shrink {
        flex-shrink: 2;
        background: #ffc107 !important;
        color: #212529;
    }
    
    .flex-item-basis {
        flex-basis: 200px;
        background: #6f42c1 !important;
    }
    
    /* 响应式调整 */
    @media (max-width: 768px) {
        .flex-item-container {
            flex-direction: column;
        }
        
        .flex-item-basis {
            flex-basis: auto;
        }
    }
</style>

10.3.3 网格系统

12列网格系统

html
<!-- 12列网格系统 -->
<div class="grid-system">
    <div class="row">
        <div class="col-12">col-12</div>
    </div>
    <div class="row">
        <div class="col-6">col-6</div>
        <div class="col-6">col-6</div>
    </div>
    <div class="row">
        <div class="col-4">col-4</div>
        <div class="col-4">col-4</div>
        <div class="col-4">col-4</div>
    </div>
    <div class="row">
        <div class="col-3">col-3</div>
        <div class="col-3">col-3</div>
        <div class="col-3">col-3</div>
        <div class="col-3">col-3</div>
    </div>
</div>

<style>
    .grid-system {
        max-width: 1200px;
        margin: 0 auto;
        padding: 20px;
    }
    
    .row {
        display: flex;
        flex-wrap: wrap;
        margin: 0 -10px 20px -10px;
    }
    
    [class*="col-"] {
        padding: 0 10px;
        background: #e9ecef;
        border: 1px solid #dee2e6;
        text-align: center;
        padding: 15px 10px;
        margin-bottom: 10px;
    }
    
    .col-1 { flex: 0 0 8.333333%; }
    .col-2 { flex: 0 0 16.666667%; }
    .col-3 { flex: 0 0 25%; }
    .col-4 { flex: 0 0 33.333333%; }
    .col-5 { flex: 0 0 41.666667%; }
    .col-6 { flex: 0 0 50%; }
    .col-7 { flex: 0 0 58.333333%; }
    .col-8 { flex: 0 0 66.666667%; }
    .col-9 { flex: 0 0 75%; }
    .col-10 { flex: 0 0 83.333333%; }
    .col-11 { flex: 0 0 91.666667%; }
    .col-12 { flex: 0 0 100%; }
    
    /* 响应式网格 */
    @media (max-width: 768px) {
        [class*="col-"] {
            flex: 0 0 100%;
        }
    }
</style>

响应式网格系统

html
<!-- 响应式网格系统 -->
<div class="responsive-grid">
    <div class="container">
        <div class="row">
            <div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
                <div class="card">响应式卡片 1</div>
            </div>
            <div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
                <div class="card">响应式卡片 2</div>
            </div>
            <div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
                <div class="card">响应式卡片 3</div>
            </div>
            <div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
                <div class="card">响应式卡片 4</div>
            </div>
        </div>
    </div>
</div>

<style>
    .responsive-grid {
        padding: 20px;
    }
    
    .container {
        max-width: 1200px;
        margin: 0 auto;
    }
    
    .row {
        display: flex;
        flex-wrap: wrap;
        margin: 0 -15px;
    }
    
    [class*="col-"] {
        padding: 0 15px;
        margin-bottom: 20px;
    }
    
    .card {
        background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
        color: white;
        padding: 30px;
        border-radius: 12px;
        text-align: center;
        box-shadow: 0 4px 15px rgba(0,0,0,0.1);
        transition: transform 0.3s ease;
    }
    
    .card:hover {
        transform: translateY(-5px);
    }
    
    /* 大屏幕 (1200px+) */
    @media (min-width: 1200px) {
        .col-lg-3 { flex: 0 0 25%; }
    }
    
    /* 中等屏幕 (768px-1199px) */
    @media (min-width: 768px) and (max-width: 1199px) {
        .col-md-4 { flex: 0 0 33.333333%; }
    }
    
    /* 小屏幕 (576px-767px) */
    @media (min-width: 576px) and (max-width: 767px) {
        .col-sm-6 { flex: 0 0 50%; }
    }
    
    /* 超小屏幕 (<576px) */
    @media (max-width: 575px) {
        .col-xs-12 { flex: 0 0 100%; }
    }
</style>

10.3.4 布局组合使用

Grid + Flexbox组合

html
<!-- Grid + Flexbox组合示例 -->
<div class="combined-layout">
    <header class="header">
        <div class="header-content">
            <div class="logo">Logo</div>
            <nav class="nav">
                <a href="#">首页</a>
                <a href="#">产品</a>
                <a href="#">服务</a>
                <a href="#">联系</a>
            </nav>
        </div>
    </header>
    
    <main class="main-content">
        <section class="hero">
            <h1>英雄区域</h1>
            <p>这里使用Flexbox进行居中对齐</p>
        </section>
        
        <section class="features">
            <div class="feature">功能 1</div>
            <div class="feature">功能 2</div>
            <div class="feature">功能 3</div>
        </section>
    </main>
    
    <footer class="footer">
        <p>&copy; 2024 公司名称. 保留所有权利.</p>
    </footer>
</div>

<style>
    .combined-layout {
        display: grid;
        grid-template-rows: auto 1fr auto;
        min-height: 100vh;
    }
    
    .header {
        background: #2c3e50;
        color: white;
        padding: 20px;
    }
    
    .header-content {
        display: flex;
        justify-content: space-between;
        align-items: center;
        max-width: 1200px;
        margin: 0 auto;
    }
    
    .logo {
        font-size: 24px;
        font-weight: bold;
    }
    
    .nav {
        display: flex;
        gap: 30px;
    }
    
    .nav a {
        color: white;
        text-decoration: none;
        transition: color 0.3s ease;
    }
    
    .nav a:hover {
        color: #3498db;
    }
    
    .main-content {
        padding: 40px 20px;
        max-width: 1200px;
        margin: 0 auto;
        width: 100%;
    }
    
    .hero {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 80px 20px;
        border-radius: 12px;
        margin-bottom: 40px;
        text-align: center;
    }
    
    .hero h1 {
        font-size: 48px;
        margin-bottom: 20px;
    }
    
    .features {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
        gap: 30px;
    }
    
    .feature {
        background: #f8f9fa;
        padding: 40px;
        border-radius: 12px;
        text-align: center;
        box-shadow: 0 4px 15px rgba(0,0,0,0.1);
        transition: transform 0.3s ease;
    }
    
    .feature:hover {
        transform: translateY(-5px);
    }
    
    .footer {
        background: #34495e;
        color: white;
        padding: 20px;
        text-align: center;
    }
    
    /* 响应式调整 */
    @media (max-width: 768px) {
        .header-content {
            flex-direction: column;
            gap: 20px;
        }
        
        .nav {
            flex-direction: column;
            gap: 15px;
            text-align: center;
        }
        
        .hero h1 {
            font-size: 32px;
        }
        
        .features {
            grid-template-columns: 1fr;
        }
    }
</style>

10.3.5 浏览器兼容性

兼容性检查和后备方案

html
<!-- 兼容性后备方案 -->
<div class="compatibility-demo">
    <div class="fallback-grid">
        <div class="item">项目 1</div>
        <div class="item">项目 2</div>
        <div class="item">项目 3</div>
        <div class="item">项目 4</div>
    </div>
</div>

<style>
    .compatibility-demo {
        padding: 20px;
    }
    
    .fallback-grid {
        /* 后备方案:浮动布局 */
        overflow: hidden;
    }
    
    .fallback-grid .item {
        float: left;
        width: 25%;
        padding: 20px;
        box-sizing: border-box;
        background: #007bff;
        color: white;
        text-align: center;
        border: 1px solid #0056b3;
    }
    
    /* 现代浏览器:Grid布局 */
    @supports (display: grid) {
        .fallback-grid {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 20px;
            overflow: visible;
        }
        
        .fallback-grid .item {
            float: none;
            width: auto;
            padding: 20px;
            border: none;
            border-radius: 8px;
        }
    }
    
    /* Flexbox后备方案 */
    @supports (display: flex) and (not (display: grid)) {
        .fallback-grid {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
        }
        
        .fallback-grid .item {
            flex: 1 1 calc(25% - 15px);
            min-width: 200px;
        }
    }
    
    /* 响应式处理 */
    @media (max-width: 768px) {
        .fallback-grid .item {
            width: 50%;
        }
        
        @supports (display: grid) {
            .fallback-grid {
                grid-template-columns: repeat(2, 1fr);
            }
        }
        
        @supports (display: flex) and (not (display: grid)) {
            .fallback-grid .item {
                flex: 1 1 calc(50% - 10px);
            }
        }
    }
    
    @media (max-width: 480px) {
        .fallback-grid .item {
            width: 100%;
        }
        
        @supports (display: grid) {
            .fallback-grid {
                grid-template-columns: 1fr;
            }
        }
        
        @supports (display: flex) and (not (display: grid)) {
            .fallback-grid .item {
                flex: 1 1 100%;
            }
        }
    }
</style>

渐进增强方案

html
<!-- 渐进增强示例 -->
<div class="progressive-enhancement">
    <div class="enhanced-layout">
        <div class="content-main">
            <h2>主要内容</h2>
            <p>这个布局使用渐进增强技术,在支持现代CSS的浏览器中显示更好的效果。</p>
        </div>
        <div class="content-sidebar">
            <h3>侧边栏</h3>
            <p>侧边栏内容</p>
        </div>
    </div>
</div>

<style>
    .progressive-enhancement {
        padding: 20px;
    }
    
    /* 基础布局 - 适用于所有浏览器 */
    .enhanced-layout {
        max-width: 1200px;
        margin: 0 auto;
    }
    
    .content-main,
    .content-sidebar {
        padding: 20px;
        margin-bottom: 20px;
        background: #f8f9fa;
        border-radius: 8px;
    }
    
    .content-main {
        background: #e3f2fd;
    }
    
    .content-sidebar {
        background: #f3e5f5;
    }
    
    /* 支持Flexbox的浏览器 */
    @supports (display: flex) {
        .enhanced-layout {
            display: flex;
            gap: 20px;
        }
        
        .content-main {
            flex: 2;
            margin-bottom: 0;
        }
        
        .content-sidebar {
            flex: 1;
            margin-bottom: 0;
        }
    }
    
    /* 支持Grid的浏览器 */
    @supports (display: grid) {
        .enhanced-layout {
            display: grid;
            grid-template-columns: 2fr 1fr;
            gap: 30px;
        }
    }
    
    /* 支持CSS变量的浏览器 */
    @supports (--css: variables) {
        :root {
            --main-color: #007bff;
            --sidebar-color: #6c757d;
            --border-radius: 12px;
        }
        
        .content-main {
            background: var(--main-color);
            color: white;
            border-radius: var(--border-radius);
        }
        
        .content-sidebar {
            background: var(--sidebar-color);
            color: white;
            border-radius: var(--border-radius);
        }
    }
    
    /* 响应式调整 */
    @media (max-width: 768px) {
        @supports (display: flex) {
            .enhanced-layout {
                flex-direction: column;
            }
        }
        
        @supports (display: grid) {
            .enhanced-layout {
                grid-template-columns: 1fr;
            }
        }
    }
</style>

本节要点回顾

  • CSS Grid布局:二维布局系统,适合复杂页面布局,提供强大的网格控制能力
  • Flexbox布局:一维布局系统,适合组件内部布局和对齐,提供灵活的空间分配
  • 网格系统:基于12列或其他列数的响应式布局框架,简化响应式设计
  • 布局组合:Grid和Flexbox可以相互配合,Grid处理页面级布局,Flexbox处理组件级布局
  • 兼容性处理:使用@supports查询和渐进增强技术确保跨浏览器兼容性

相关学习资源

常见问题FAQ

Q: 什么时候使用Grid,什么时候使用Flexbox?

A: Grid适合二维布局(行和列),如整个页面布局;Flexbox适合一维布局(行或列),如导航栏、按钮组等组件内部布局。它们可以结合使用。

Q: 如何处理老旧浏览器的兼容性?

A: 使用@supports查询检测浏览器支持情况,提供后备方案。可以使用浮动、表格布局或定位作为后备方案。

Q: 网格系统的列数如何选择?

A: 12列是最常用的,因为12可以被1、2、3、4、6、12整除,提供了灵活的布局选项。也可以根据设计需求使用其他列数。

Q: Grid和Flexbox的性能如何?

A: 两者性能都很好,在现代浏览器中没有明显差异。Grid在处理复杂布局时可能稍有优势,但差异通常可以忽略不计。

Q: 如何在项目中逐步引入现代布局技术?

A: 从简单的组件开始,逐步替换传统布局方法。使用渐进增强技术,确保在不支持的浏览器中仍有可用的后备方案。


下一节预览:下一节我们将学习响应式图像,深入了解响应式图像技术、picture元素、srcset属性、sizes属性和图像优化的实现方法。