Skip to content

Latest commit

 

History

History
966 lines (792 loc) · 17 KB

File metadata and controls

966 lines (792 loc) · 17 KB

Responsive Design 响应式设计文档

概述

响应式设计系统定义了项目在不同设备和屏幕尺寸下的适配规则,包括断点定义、布局适配、组件响应式行为等。

文件位置: src/styles/responsive.css

断点系统

1. 断点定义

/* 断点变量定义 */
:root {
  --breakpoint-xs: 480px;   /* 超小屏幕 */
  --breakpoint-sm: 768px;   /* 小屏幕 */
  --breakpoint-md: 1024px;  /* 中等屏幕 */
  --breakpoint-lg: 1280px;  /* 大屏幕 */
  --breakpoint-xl: 1536px;  /* 超大屏幕 */
}

/* 媒体查询断点 */
@media (max-width: 479px) {
  /* 超小屏幕样式 */
}

@media (min-width: 480px) and (max-width: 767px) {
  /* 小屏幕样式 */
}

@media (min-width: 768px) and (max-width: 1023px) {
  /* 中等屏幕样式 */
}

@media (min-width: 1024px) and (max-width: 1279px) {
  /* 大屏幕样式 */
}

@media (min-width: 1280px) and (max-width: 1535px) {
  /* 超大屏幕样式 */
}

@media (min-width: 1536px) {
  /* 极大屏幕样式 */
}

2. 设备类型断点

/* 移动设备 */
@media (max-width: 767px) {
  .mobile-only {
    display: block;
  }
  
  .desktop-only {
    display: none;
  }
  
  .container {
    padding: 0 16px;
  }
  
  .grid-responsive {
    grid-template-columns: 1fr;
    gap: 16px;
  }
}

/* 平板设备 */
@media (min-width: 768px) and (max-width: 1023px) {
  .tablet-only {
    display: block;
  }
  
  .container {
    padding: 0 24px;
  }
  
  .grid-responsive {
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
  }
}

/* 桌面设备 */
@media (min-width: 1024px) {
  .mobile-only {
    display: none;
  }
  
  .desktop-only {
    display: block;
  }
  
  .container {
    padding: 0 32px;
  }
  
  .grid-responsive {
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
  }
}

响应式布局

1. 容器系统

/* 响应式容器 */
.container {
  width: 100%;
  margin: 0 auto;
  padding: 0 16px;
}

@media (min-width: 480px) {
  .container {
    max-width: 480px;
    padding: 0 20px;
  }
}

@media (min-width: 768px) {
  .container {
    max-width: 768px;
    padding: 0 24px;
  }
}

@media (min-width: 1024px) {
  .container {
    max-width: 1024px;
    padding: 0 32px;
  }
}

@media (min-width: 1280px) {
  .container {
    max-width: 1280px;
    padding: 0 40px;
  }
}

@media (min-width: 1536px) {
  .container {
    max-width: 1536px;
    padding: 0 48px;
  }
}

/* 流体容器 */
.container-fluid {
  width: 100%;
  padding: 0 16px;
}

@media (min-width: 768px) {
  .container-fluid {
    padding: 0 24px;
  }
}

@media (min-width: 1024px) {
  .container-fluid {
    padding: 0 32px;
  }
}

2. 网格系统

/* 响应式网格 */
.grid {
  display: grid;
  gap: 16px;
}

/* 移动端:单列 */
@media (max-width: 767px) {
  .grid-cols-responsive {
    grid-template-columns: 1fr;
  }
  
  .grid-cols-auto-responsive {
    grid-template-columns: 1fr;
  }
}

/* 平板端:双列 */
@media (min-width: 768px) and (max-width: 1023px) {
  .grid-cols-responsive {
    grid-template-columns: repeat(2, 1fr);
  }
  
  .grid-cols-auto-responsive {
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  }
  
  .grid {
    gap: 20px;
  }
}

/* 桌面端:多列 */
@media (min-width: 1024px) {
  .grid-cols-responsive {
    grid-template-columns: repeat(3, 1fr);
  }
  
  .grid-cols-auto-responsive {
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  }
  
  .grid {
    gap: 24px;
  }
}

@media (min-width: 1280px) {
  .grid-cols-responsive {
    grid-template-columns: repeat(4, 1fr);
  }
  
  .grid-cols-auto-responsive {
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  }
}

3. Flexbox响应式

/* 响应式Flex布局 */
.flex-responsive {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

/* 移动端:垂直排列 */
@media (max-width: 767px) {
  .flex-responsive {
    flex-direction: column;
  }
  
  .flex-responsive > * {
    flex: 1 1 100%;
  }
}

/* 平板端:水平排列,自动换行 */
@media (min-width: 768px) and (max-width: 1023px) {
  .flex-responsive {
    flex-direction: row;
    gap: 20px;
  }
  
  .flex-responsive > * {
    flex: 1 1 calc(50% - 10px);
  }
}

/* 桌面端:水平排列 */
@media (min-width: 1024px) {
  .flex-responsive {
    flex-direction: row;
    gap: 24px;
  }
  
  .flex-responsive > * {
    flex: 1 1 calc(33.333% - 16px);
  }
}

组件响应式

1. 导航组件

/* 响应式导航 */
.navbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  height: 64px;
}

/* 移动端导航 */
@media (max-width: 767px) {
  .navbar {
    height: 56px;
    padding: 0 12px;
  }
  
  .navbar-menu {
    display: none;
    position: fixed;
    top: 56px;
    left: 0;
    right: 0;
    bottom: 0;
    background: white;
    z-index: 1000;
    padding: 20px;
  }
  
  .navbar-menu.active {
    display: block;
  }
  
  .navbar-toggle {
    display: block;
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
  }
}

/* 桌面端导航 */
@media (min-width: 768px) {
  .navbar {
    padding: 0 24px;
  }
  
  .navbar-menu {
    display: flex;
    align-items: center;
    gap: 24px;
  }
  
  .navbar-toggle {
    display: none;
  }
}

2. 卡片组件

/* 响应式卡片 */
.card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
}

/* 移动端卡片 */
@media (max-width: 767px) {
  .card {
    margin: 8px;
    border-radius: 6px;
  }
  
  .card-header {
    padding: 16px;
    font-size: 16px;
  }
  
  .card-body {
    padding: 16px;
    font-size: 14px;
  }
  
  .card-footer {
    padding: 12px 16px;
  }
}

/* 平板端卡片 */
@media (min-width: 768px) and (max-width: 1023px) {
  .card {
    margin: 12px;
    border-radius: 8px;
  }
  
  .card-header {
    padding: 20px;
    font-size: 18px;
  }
  
  .card-body {
    padding: 20px;
    font-size: 14px;
  }
  
  .card-footer {
    padding: 16px 20px;
  }
}

/* 桌面端卡片 */
@media (min-width: 1024px) {
  .card {
    margin: 16px;
    border-radius: 10px;
  }
  
  .card-header {
    padding: 24px;
    font-size: 20px;
  }
  
  .card-body {
    padding: 24px;
    font-size: 16px;
  }
  
  .card-footer {
    padding: 20px 24px;
  }
}

3. 表格组件

/* 响应式表格 */
.table-responsive {
  width: 100%;
  overflow-x: auto;
}

/* 移动端表格 */
@media (max-width: 767px) {
  .table-responsive {
    border-radius: 6px;
  }
  
  .table {
    font-size: 12px;
  }
  
  .table th,
  .table td {
    padding: 8px 4px;
    white-space: nowrap;
  }
  
  /* 卡片式表格 */
  .table-card {
    display: block;
  }
  
  .table-card thead {
    display: none;
  }
  
  .table-card tbody {
    display: block;
  }
  
  .table-card tr {
    display: block;
    margin-bottom: 16px;
    background: white;
    border-radius: 8px;
    padding: 16px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }
  
  .table-card td {
    display: block;
    text-align: left;
    padding: 4px 0;
    border: none;
  }
  
  .table-card td:before {
    content: attr(data-label) ": ";
    font-weight: bold;
    color: #666;
  }
}

/* 桌面端表格 */
@media (min-width: 768px) {
  .table {
    font-size: 14px;
  }
  
  .table th,
  .table td {
    padding: 12px 16px;
  }
  
  .table-card {
    display: table;
  }
  
  .table-card thead {
    display: table-header-group;
  }
  
  .table-card tbody {
    display: table-row-group;
  }
  
  .table-card tr {
    display: table-row;
    margin: 0;
    background: transparent;
    border-radius: 0;
    padding: 0;
    box-shadow: none;
  }
  
  .table-card td {
    display: table-cell;
    padding: 12px 16px;
    border-bottom: 1px solid #eee;
  }
  
  .table-card td:before {
    display: none;
  }
}

字体响应式

1. 响应式字体大小

/* 基础字体大小 */
html {
  font-size: 14px;
}

/* 移动端字体 */
@media (max-width: 767px) {
  html {
    font-size: 13px;
  }
  
  .text-xs { font-size: 0.7rem; }
  .text-sm { font-size: 0.8rem; }
  .text-base { font-size: 0.9rem; }
  .text-lg { font-size: 1rem; }
  .text-xl { font-size: 1.1rem; }
  .text-2xl { font-size: 1.3rem; }
  .text-3xl { font-size: 1.5rem; }
}

/* 平板端字体 */
@media (min-width: 768px) and (max-width: 1023px) {
  html {
    font-size: 14px;
  }
  
  .text-xs { font-size: 0.75rem; }
  .text-sm { font-size: 0.875rem; }
  .text-base { font-size: 1rem; }
  .text-lg { font-size: 1.125rem; }
  .text-xl { font-size: 1.25rem; }
  .text-2xl { font-size: 1.5rem; }
  .text-3xl { font-size: 1.875rem; }
}

/* 桌面端字体 */
@media (min-width: 1024px) {
  html {
    font-size: 16px;
  }
  
  .text-xs { font-size: 0.75rem; }
  .text-sm { font-size: 0.875rem; }
  .text-base { font-size: 1rem; }
  .text-lg { font-size: 1.125rem; }
  .text-xl { font-size: 1.25rem; }
  .text-2xl { font-size: 1.5rem; }
  .text-3xl { font-size: 1.875rem; }
  .text-4xl { font-size: 2.25rem; }
  .text-5xl { font-size: 3rem; }
}

2. 行高响应式

/* 响应式行高 */
@media (max-width: 767px) {
  body {
    line-height: 1.4;
  }
  
  .leading-tight { line-height: 1.2; }
  .leading-normal { line-height: 1.4; }
  .leading-relaxed { line-height: 1.5; }
}

@media (min-width: 768px) {
  body {
    line-height: 1.6;
  }
  
  .leading-tight { line-height: 1.25; }
  .leading-normal { line-height: 1.6; }
  .leading-relaxed { line-height: 1.75; }
}

间距响应式

1. 响应式边距

/* 响应式外边距 */
@media (max-width: 767px) {
  .m-responsive { margin: 8px; }
  .mx-responsive { margin-left: 8px; margin-right: 8px; }
  .my-responsive { margin-top: 8px; margin-bottom: 8px; }
  .mt-responsive { margin-top: 8px; }
  .mb-responsive { margin-bottom: 8px; }
}

@media (min-width: 768px) and (max-width: 1023px) {
  .m-responsive { margin: 16px; }
  .mx-responsive { margin-left: 16px; margin-right: 16px; }
  .my-responsive { margin-top: 16px; margin-bottom: 16px; }
  .mt-responsive { margin-top: 16px; }
  .mb-responsive { margin-bottom: 16px; }
}

@media (min-width: 1024px) {
  .m-responsive { margin: 24px; }
  .mx-responsive { margin-left: 24px; margin-right: 24px; }
  .my-responsive { margin-top: 24px; margin-bottom: 24px; }
  .mt-responsive { margin-top: 24px; }
  .mb-responsive { margin-bottom: 24px; }
}

2. 响应式内边距

/* 响应式内边距 */
@media (max-width: 767px) {
  .p-responsive { padding: 12px; }
  .px-responsive { padding-left: 12px; padding-right: 12px; }
  .py-responsive { padding-top: 12px; padding-bottom: 12px; }
  .pt-responsive { padding-top: 12px; }
  .pb-responsive { padding-bottom: 12px; }
}

@media (min-width: 768px) and (max-width: 1023px) {
  .p-responsive { padding: 20px; }
  .px-responsive { padding-left: 20px; padding-right: 20px; }
  .py-responsive { padding-top: 20px; padding-bottom: 20px; }
  .pt-responsive { padding-top: 20px; }
  .pb-responsive { padding-bottom: 20px; }
}

@media (min-width: 1024px) {
  .p-responsive { padding: 32px; }
  .px-responsive { padding-left: 32px; padding-right: 32px; }
  .py-responsive { padding-top: 32px; padding-bottom: 32px; }
  .pt-responsive { padding-top: 32px; }
  .pb-responsive { padding-bottom: 32px; }
}

工具类

1. 显示/隐藏工具类

/* 响应式显示隐藏 */
.hidden-xs { display: none; }
.hidden-sm { display: block; }
.hidden-md { display: block; }
.hidden-lg { display: block; }
.hidden-xl { display: block; }

@media (min-width: 480px) {
  .hidden-xs { display: block; }
  .hidden-sm { display: none; }
}

@media (min-width: 768px) {
  .hidden-sm { display: block; }
  .hidden-md { display: none; }
}

@media (min-width: 1024px) {
  .hidden-md { display: block; }
  .hidden-lg { display: none; }
}

@media (min-width: 1280px) {
  .hidden-lg { display: block; }
  .hidden-xl { display: none; }
}

@media (min-width: 1536px) {
  .hidden-xl { display: block; }
}

/* 仅在特定断点显示 */
.visible-xs { display: block; }
.visible-sm { display: none; }
.visible-md { display: none; }
.visible-lg { display: none; }
.visible-xl { display: none; }

@media (min-width: 480px) {
  .visible-xs { display: none; }
  .visible-sm { display: block; }
}

@media (min-width: 768px) {
  .visible-sm { display: none; }
  .visible-md { display: block; }
}

@media (min-width: 1024px) {
  .visible-md { display: none; }
  .visible-lg { display: block; }
}

@media (min-width: 1280px) {
  .visible-lg { display: none; }
  .visible-xl { display: block; }
}

2. 文本对齐工具类

/* 响应式文本对齐 */
@media (max-width: 767px) {
  .text-center-mobile { text-align: center; }
  .text-left-mobile { text-align: left; }
  .text-right-mobile { text-align: right; }
}

@media (min-width: 768px) {
  .text-center-desktop { text-align: center; }
  .text-left-desktop { text-align: left; }
  .text-right-desktop { text-align: right; }
}

JavaScript响应式工具

1. 断点检测

/**
 * 响应式断点检测工具
 */
export const breakpoints = {
  xs: 480,
  sm: 768,
  md: 1024,
  lg: 1280,
  xl: 1536
}

/**
 * 获取当前断点
 * @returns {String} 当前断点名称
 */
export function getCurrentBreakpoint() {
  const width = window.innerWidth
  
  if (width < breakpoints.xs) return 'xs'
  if (width < breakpoints.sm) return 'sm'
  if (width < breakpoints.md) return 'md'
  if (width < breakpoints.lg) return 'lg'
  if (width < breakpoints.xl) return 'xl'
  return 'xxl'
}

/**
 * 检查是否为移动设备
 * @returns {Boolean} 是否为移动设备
 */
export function isMobile() {
  return window.innerWidth < breakpoints.sm
}

/**
 * 检查是否为平板设备
 * @returns {Boolean} 是否为平板设备
 */
export function isTablet() {
  const width = window.innerWidth
  return width >= breakpoints.sm && width < breakpoints.lg
}

/**
 * 检查是否为桌面设备
 * @returns {Boolean} 是否为桌面设备
 */
export function isDesktop() {
  return window.innerWidth >= breakpoints.lg
}

2. Vue 3 响应式组合式API

import { ref, onMounted, onBeforeUnmount } from 'vue'

/**
 * 响应式断点组合式API
 */
export function useBreakpoint() {
  const currentBreakpoint = ref(getCurrentBreakpoint())
  const isMobileDevice = ref(isMobile())
  const isTabletDevice = ref(isTablet())
  const isDesktopDevice = ref(isDesktop())
  
  const updateBreakpoint = () => {
    currentBreakpoint.value = getCurrentBreakpoint()
    isMobileDevice.value = isMobile()
    isTabletDevice.value = isTablet()
    isDesktopDevice.value = isDesktop()
  }
  
  onMounted(() => {
    window.addEventListener('resize', updateBreakpoint)
    updateBreakpoint()
  })
  
  onBeforeUnmount(() => {
    window.removeEventListener('resize', updateBreakpoint)
  })
  
  return {
    currentBreakpoint: readonly(currentBreakpoint),
    isMobile: readonly(isMobileDevice),
    isTablet: readonly(isTabletDevice),
    isDesktop: readonly(isDesktopDevice)
  }
}

使用示例

1. 响应式布局

<template>
  <div class="container">
    <div class="grid-responsive">
      <div class="card">卡片1</div>
      <div class="card">卡片2</div>
      <div class="card">卡片3</div>
    </div>
  </div>
</template>

<style scoped>
.grid-responsive {
  display: grid;
  gap: 16px;
}

@media (max-width: 767px) {
  .grid-responsive {
    grid-template-columns: 1fr;
  }
}

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

@media (min-width: 1024px) {
  .grid-responsive {
    grid-template-columns: repeat(3, 1fr);
  }
}
</style>

2. 条件渲染

<template>
  <div>
    <!-- 移动端显示 -->
    <div v-if="isMobile" class="mobile-menu">
      <button @click="toggleMenu">菜单</button>
    </div>
    
    <!-- 桌面端显示 -->
    <nav v-else class="desktop-nav">
      <a href="#home">首页</a>
      <a href="#about">关于</a>
      <a href="#contact">联系</a>
    </nav>
  </div>
</template>

<script setup>
import { useBreakpoint } from '@/utils/responsive'

const { isMobile } = useBreakpoint()

const toggleMenu = () => {
  // 切换移动端菜单
}
</script>

3. 响应式组件属性

<template>
  <el-table
    :data="tableData"
    :size="tableSize"
    :height="tableHeight"
  >
    <!-- 表格列 -->
  </el-table>
</template>

<script setup>
import { computed } from 'vue'
import { useBreakpoint } from '@/utils/responsive'

const { isMobile, isTablet } = useBreakpoint()

const tableSize = computed(() => {
  if (isMobile.value) return 'small'
  if (isTablet.value) return 'default'
  return 'large'
})

const tableHeight = computed(() => {
  if (isMobile.value) return 300
  if (isTablet.value) return 400
  return 500
})
</script>

注意事项

  1. 性能优化: 避免过多的媒体查询,合理组织CSS结构
  2. 触摸友好: 移动端确保足够的触摸目标大小
  3. 内容优先: 优先考虑内容的可读性和可访问性
  4. 测试覆盖: 在不同设备和屏幕尺寸下充分测试
  5. 渐进增强: 从移动端开始设计,逐步增强桌面端体验

相关文档


最后更新时间:2025-09-19