发布于

现代CSS布局技巧集锦:Grid、Flexbox与Container Queries

作者

现代CSS布局技巧集锦:Grid、Flexbox与Container Queries

现代CSS为我们提供了强大的布局工具,本文将分享CSS Grid、Flexbox和Container Queries等现代布局技术的实战技巧和最佳实践。

CSS Grid高级应用

复杂网格布局

/* 响应式网格布局系统 */
.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  grid-template-rows: masonry; /* 实验性功能 */
  gap: 2rem;
  padding: 2rem;
}

/* 不规则网格布局 */
.magazine-layout {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: repeat(4, 200px);
  gap: 1rem;
}

.magazine-layout .featured {
  grid-column: 1 / 4;
  grid-row: 1 / 3;
}

.magazine-layout .sidebar {
  grid-column: 4 / 7;
  grid-row: 1 / 2;
}

.magazine-layout .article-1 {
  grid-column: 4 / 6;
  grid-row: 2 / 4;
}

.magazine-layout .article-2 {
  grid-column: 6 / 7;
  grid-row: 2 / 3;
}

.magazine-layout .ads {
  grid-column: 6 / 7;
  grid-row: 3 / 4;
}

.magazine-layout .footer {
  grid-column: 1 / 7;
  grid-row: 4 / 5;
}

/* 动态网格布局 */
.dynamic-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  grid-auto-rows: minmax(200px, auto);
  gap: 1rem;
}

.dynamic-grid .item {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 8px;
  padding: 1rem;
  color: white;
}

/* 特殊尺寸项目 */
.dynamic-grid .item.large {
  grid-column: span 2;
  grid-row: span 2;
}

.dynamic-grid .item.wide {
  grid-column: span 2;
}

.dynamic-grid .item.tall {
  grid-row: span 2;
}

/* 网格区域命名 */
.app-layout {
  display: grid;
  grid-template-areas: 
    "header header header"
    "nav main aside"
    "nav footer aside";
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: 60px 1fr 60px;
  min-height: 100vh;
  gap: 1rem;
}

.app-layout .header { grid-area: header; }
.app-layout .nav { grid-area: nav; }
.app-layout .main { grid-area: main; }
.app-layout .aside { grid-area: aside; }
.app-layout .footer { grid-area: footer; }

/* 响应式网格区域 */
@media (max-width: 768px) {
  .app-layout {
    grid-template-areas: 
      "header"
      "nav"
      "main"
      "aside"
      "footer";
    grid-template-columns: 1fr;
    grid-template-rows: 60px auto 1fr auto 60px;
  }
}

Grid子网格(Subgrid)

/* 子网格布局 */
.parent-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(3, 200px);
  gap: 1rem;
}

.child-grid {
  grid-column: 2 / 4;
  grid-row: 1 / 3;
  
  /* 使用子网格 */
  display: grid;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
  gap: inherit;
}

/* 卡片网格对齐 */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}

.card {
  display: grid;
  grid-template-rows: auto 1fr auto;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

.card-header {
  padding: 1rem;
  background: #f5f5f5;
}

.card-content {
  padding: 1rem;
  /* 自动填充剩余空间 */
}

.card-footer {
  padding: 1rem;
  background: #f5f5f5;
  border-top: 1px solid #ddd;
}

/* 网格线命名 */
.named-lines {
  display: grid;
  grid-template-columns: 
    [sidebar-start] 200px 
    [sidebar-end main-start] 1fr 
    [main-end aside-start] 200px 
    [aside-end];
  grid-template-rows: 
    [header-start] 60px 
    [header-end content-start] 1fr 
    [content-end footer-start] 60px 
    [footer-end];
}

.named-lines .header {
  grid-column: sidebar-start / aside-end;
  grid-row: header-start / header-end;
}

.named-lines .sidebar {
  grid-column: sidebar-start / sidebar-end;
  grid-row: content-start / content-end;
}

.named-lines .main {
  grid-column: main-start / main-end;
  grid-row: content-start / content-end;
}

Flexbox高级技巧

复杂Flex布局

/* 自适应导航栏 */
.navbar {
  display: flex;
  align-items: center;
  padding: 0 2rem;
  background: white;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.navbar .logo {
  flex-shrink: 0;
  margin-right: 2rem;
}

.navbar .nav-links {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: 2rem;
}

.navbar .nav-actions {
  margin-left: auto;
  display: flex;
  gap: 1rem;
  align-items: center;
}

/* 响应式导航 */
@media (max-width: 768px) {
  .navbar {
    flex-wrap: wrap;
  }
  
  .navbar .nav-links {
    order: 3;
    flex-basis: 100%;
    flex-direction: column;
    background: white;
    padding: 1rem 0;
    border-top: 1px solid #eee;
  }
}

/* 等高卡片布局 */
.card-container {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
  align-items: stretch; /* 等高 */
}

.card-item {
  flex: 1 1 300px; /* 最小宽度300px */
  display: flex;
  flex-direction: column;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

.card-item .content {
  flex: 1; /* 占据剩余空间 */
  padding: 1rem;
}

.card-item .actions {
  padding: 1rem;
  background: #f5f5f5;
  border-top: 1px solid #ddd;
}

/* 圣杯布局 */
.holy-grail {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.holy-grail .header,
.holy-grail .footer {
  flex-shrink: 0;
  background: #333;
  color: white;
  padding: 1rem;
}

.holy-grail .content {
  flex: 1;
  display: flex;
}

.holy-grail .sidebar {
  flex: 0 0 200px;
  background: #f5f5f5;
  padding: 1rem;
}

.holy-grail .main {
  flex: 1;
  padding: 1rem;
}

.holy-grail .aside {
  flex: 0 0 200px;
  background: #f5f5f5;
  padding: 1rem;
}

/* 移动端调整 */
@media (max-width: 768px) {
  .holy-grail .content {
    flex-direction: column;
  }
  
  .holy-grail .sidebar,
  .holy-grail .aside {
    flex: none;
  }
}

/* 垂直居中技巧 */
.center-container {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}

.center-content {
  text-align: center;
  max-width: 500px;
  padding: 2rem;
}

/* 弹性间距 */
.flexible-spacing {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
}

.flexible-spacing .item:not(:last-child) {
  margin-right: auto;
}

/* 自动换行网格 */
.flex-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin: -0.5rem; /* 抵消gap */
}

.flex-grid .item {
  flex: 1 1 calc(33.333% - 1rem);
  min-width: 250px;
  margin: 0.5rem;
}

@media (max-width: 768px) {
  .flex-grid .item {
    flex: 1 1 calc(50% - 1rem);
  }
}

@media (max-width: 480px) {
  .flex-grid .item {
    flex: 1 1 100%;
  }
}

Flex高级属性应用

/* flex-grow, flex-shrink, flex-basis 详解 */
.flex-demo {
  display: flex;
  width: 600px;
  height: 200px;
  border: 2px solid #333;
}

.flex-demo .item-1 {
  flex: 1 1 200px; /* grow: 1, shrink: 1, basis: 200px */
  background: #ff6b6b;
}

.flex-demo .item-2 {
  flex: 2 1 100px; /* grow: 2, shrink: 1, basis: 100px */
  background: #4ecdc4;
}

.flex-demo .item-3 {
  flex: 1 2 150px; /* grow: 1, shrink: 2, basis: 150px */
  background: #45b7d1;
}

/* 自适应表单布局 */
.form-row {
  display: flex;
  gap: 1rem;
  margin-bottom: 1rem;
  align-items: flex-start;
}

.form-row .form-group {
  display: flex;
  flex-direction: column;
  flex: 1;
}

.form-row .form-group.narrow {
  flex: 0 0 120px; /* 固定宽度 */
}

.form-row .form-group.wide {
  flex: 2; /* 占据更多空间 */
}

.form-row label {
  margin-bottom: 0.5rem;
  font-weight: bold;
}

.form-row input,
.form-row select,
.form-row textarea {
  padding: 0.5rem;
  border: 1px solid #ddd;
  border-radius: 4px;
}

/* 响应式表单 */
@media (max-width: 768px) {
  .form-row {
    flex-direction: column;
  }
  
  .form-row .form-group.narrow,
  .form-row .form-group.wide {
    flex: none;
  }
}

/* 媒体对象布局 */
.media-object {
  display: flex;
  gap: 1rem;
  padding: 1rem;
  border-bottom: 1px solid #eee;
}

.media-object .media-figure {
  flex-shrink: 0;
}

.media-object .media-figure img {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  object-fit: cover;
}

.media-object .media-body {
  flex: 1;
  min-width: 0; /* 防止内容溢出 */
}

.media-object .media-body h4 {
  margin: 0 0 0.5rem 0;
  font-size: 1rem;
}

.media-object .media-body p {
  margin: 0;
  color: #666;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Container Queries

容器查询基础

/* 容器查询设置 */
.card-container {
  container-type: inline-size;
  container-name: card;
}

.card {
  padding: 1rem;
  border: 1px solid #ddd;
  border-radius: 8px;
}

/* 基于容器宽度的样式 */
@container card (min-width: 300px) {
  .card {
    display: flex;
    gap: 1rem;
  }
  
  .card .image {
    flex: 0 0 120px;
  }
  
  .card .content {
    flex: 1;
  }
}

@container card (min-width: 500px) {
  .card {
    padding: 2rem;
  }
  
  .card .image {
    flex: 0 0 200px;
  }
  
  .card h3 {
    font-size: 1.5rem;
  }
}

/* 复杂容器查询 */
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

.widget {
  margin-bottom: 1rem;
  padding: 1rem;
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

@container sidebar (max-width: 250px) {
  .widget {
    padding: 0.5rem;
  }
  
  .widget h4 {
    font-size: 0.9rem;
  }
  
  .widget .description {
    display: none;
  }
}

@container sidebar (min-width: 300px) {
  .widget {
    display: flex;
    align-items: center;
    gap: 1rem;
  }
  
  .widget .icon {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
  }
  
  .widget .content {
    flex: 1;
  }
}

/* 网格容器查询 */
.grid-container {
  container-type: inline-size;
  container-name: grid;
}

.grid {
  display: grid;
  gap: 1rem;
}

@container grid (min-width: 400px) {
  .grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@container grid (min-width: 600px) {
  .grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@container grid (min-width: 800px) {
  .grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

容器查询实战应用

/* 响应式卡片组件 */
.product-card {
  container-type: inline-size;
  container-name: product-card;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
  background: white;
}

.product-card .image {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.product-card .content {
  padding: 1rem;
}

.product-card .title {
  font-size: 1.1rem;
  font-weight: bold;
  margin-bottom: 0.5rem;
}

.product-card .price {
  font-size: 1.2rem;
  color: #e74c3c;
  font-weight: bold;
}

.product-card .description {
  color: #666;
  margin: 0.5rem 0;
  line-height: 1.4;
}

.product-card .actions {
  margin-top: 1rem;
}

/* 小尺寸容器样式 */
@container product-card (max-width: 200px) {
  .product-card .image {
    height: 120px;
  }
  
  .product-card .content {
    padding: 0.5rem;
  }
  
  .product-card .title {
    font-size: 0.9rem;
  }
  
  .product-card .description {
    display: none;
  }
  
  .product-card .actions button {
    width: 100%;
    font-size: 0.8rem;
  }
}

/* 中等尺寸容器样式 */
@container product-card (min-width: 300px) and (max-width: 400px) {
  .product-card {
    display: flex;
  }
  
  .product-card .image {
    width: 120px;
    height: 120px;
    flex-shrink: 0;
  }
  
  .product-card .content {
    flex: 1;
    display: flex;
    flex-direction: column;
  }
  
  .product-card .actions {
    margin-top: auto;
  }
}

/* 大尺寸容器样式 */
@container product-card (min-width: 400px) {
  .product-card .image {
    height: 250px;
  }
  
  .product-card .content {
    padding: 1.5rem;
  }
  
  .product-card .title {
    font-size: 1.3rem;
  }
  
  .product-card .description {
    font-size: 1rem;
    line-height: 1.6;
  }
  
  .product-card .actions {
    display: flex;
    gap: 1rem;
  }
  
  .product-card .actions button {
    flex: 1;
  }
}

/* 导航组件容器查询 */
.navigation {
  container-type: inline-size;
  container-name: navigation;
  background: #333;
  color: white;
}

.nav-list {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-item {
  position: relative;
}

.nav-link {
  display: block;
  padding: 1rem;
  color: white;
  text-decoration: none;
  transition: background-color 0.3s;
}

.nav-link:hover {
  background-color: rgba(255,255,255,0.1);
}

/* 窄容器:垂直导航 */
@container navigation (max-width: 600px) {
  .nav-list {
    flex-direction: column;
  }
  
  .nav-item {
    border-bottom: 1px solid rgba(255,255,255,0.1);
  }
  
  .nav-item:last-child {
    border-bottom: none;
  }
}

/* 宽容器:水平导航 */
@container navigation (min-width: 600px) {
  .nav-list {
    justify-content: center;
  }
  
  .nav-item:not(:last-child) {
    border-right: 1px solid rgba(255,255,255,0.1);
  }
}

现代CSS布局组合技巧

Grid + Flexbox 组合

/* Grid作为页面布局,Flexbox作为组件布局 */
.page-layout {
  display: grid;
  grid-template-areas: 
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 250px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
  gap: 1rem;
}

.page-header {
  grid-area: header;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
  background: white;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.page-sidebar {
  grid-area: sidebar;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1rem;
  background: #f5f5f5;
}

.page-main {
  grid-area: main;
  display: flex;
  flex-direction: column;
  gap: 2rem;
  padding: 2rem;
}

.page-footer {
  grid-area: footer;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 1rem;
  background: #333;
  color: white;
}

/* 内容区域使用Flexbox */
.content-section {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.content-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: 1rem;
  border-bottom: 2px solid #eee;
}

.content-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}

.content-card {
  display: flex;
  flex-direction: column;
  border: 1px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

.content-card .header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
  background: #f8f9fa;
  border-bottom: 1px solid #ddd;
}

.content-card .body {
  flex: 1;
  padding: 1rem;
}

.content-card .footer {
  display: flex;
  justify-content: flex-end;
  gap: 1rem;
  padding: 1rem;
  background: #f8f9fa;
  border-top: 1px solid #ddd;
}

响应式布局最佳实践

/* 移动优先的响应式设计 */
.responsive-layout {
  --sidebar-width: 250px;
  --header-height: 60px;
  --gap: 1rem;
  
  display: grid;
  grid-template-areas: 
    "header"
    "main"
    "sidebar"
    "footer";
  grid-template-rows: var(--header-height) 1fr auto auto;
  min-height: 100vh;
  gap: var(--gap);
}

/* 平板尺寸 */
@media (min-width: 768px) {
  .responsive-layout {
    grid-template-areas: 
      "header header"
      "sidebar main"
      "footer footer";
    grid-template-columns: var(--sidebar-width) 1fr;
    grid-template-rows: var(--header-height) 1fr auto;
  }
}

/* 桌面尺寸 */
@media (min-width: 1024px) {
  .responsive-layout {
    --sidebar-width: 300px;
    --gap: 2rem;
    
    grid-template-areas: 
      "header header header"
      "sidebar main aside"
      "footer footer footer";
    grid-template-columns: var(--sidebar-width) 1fr 250px;
  }
}

/* 大屏幕优化 */
@media (min-width: 1400px) {
  .responsive-layout {
    max-width: 1400px;
    margin: 0 auto;
  }
}

/* 容器查询增强响应式 */
.adaptive-component {
  container-type: inline-size;
  container-name: adaptive;
}

@container adaptive (min-width: 400px) {
  .adaptive-component .content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
  }
}

@container adaptive (min-width: 600px) {
  .adaptive-component .content {
    grid-template-columns: 1fr 2fr 1fr;
  }
}

/* 打印样式优化 */
@media print {
  .responsive-layout {
    grid-template-areas: 
      "header"
      "main"
      "footer";
    grid-template-columns: 1fr;
  }
  
  .page-sidebar,
  .page-aside {
    display: none;
  }
  
  .page-header,
  .page-footer {
    background: none !important;
    box-shadow: none !important;
  }
}

总结

现代CSS布局的核心要点:

  1. CSS Grid:适合二维布局,页面级别的整体结构
  2. Flexbox:适合一维布局,组件级别的内容排列
  3. Container Queries:基于容器尺寸的响应式设计
  4. 组合使用:Grid + Flexbox 实现复杂布局需求
  5. 响应式策略:移动优先,渐进增强

现代CSS布局技术为我们提供了前所未有的灵活性和控制力,合理运用这些技术可以创建出既美观又实用的用户界面。