---
description: 响应式设计和媒体资源优化
globs: ["**/*.vue", "**/*.css", "**/components/**/*", "**/assets/**/*"]
alwaysApply: false
---

# 响应式设计和媒体资源规范

## 📱 响应式适配

### 断点设计
```css
/* ✅ 实现多端适配，支持以下断点 */
/* 移动端优先设计 */
.container {
  width: 100%;
  padding: 16px;
}

/* 小屏手机 */
@media (min-width: 375px) {
  .container {
    padding: 20px;
  }
}

/* 平板 */
@media (min-width: 768px) {
  .container {
    max-width: 768px;
    padding: 24px;
    margin: 0 auto;
  }
}

/* 桌面端 */
@media (min-width: 1024px) {
  .container {
    max-width: 1024px;
    padding: 32px;
  }
}

/* 大屏 */
@media (min-width: 1280px) {
  .container {
    max-width: 1280px;
  }
}
```

### Tailwind CSS 响应式
```vue
<template>
  <!-- ✅ 使用 Tailwind CSS 响应式前缀 -->
  <div class="w-full px-4 sm:px-6 md:px-8 lg:max-w-4xl lg:mx-auto">
    <h1 class="text-2xl sm:text-3xl md:text-4xl font-bold text-center">
      响应式标题
    </h1>
    
    <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
      <!-- 网格内容 -->
    </div>
  </div>
</template>
```

## 🖼️ 图片与媒体资源

### 图片优化要求
```vue
<template>
  <!-- ✅ 图片优化实现 -->
  <picture>
    <!-- WebP 格式优先 -->
    <source 
      srcset="
        /images/hero-320.webp 320w, 
        /images/hero-640.webp 640w, 
        /images/hero-1280.webp 1280w
      " 
      type="image/webp"
    >
    
    <!-- JPEG/PNG 降级方案 -->
    <img 
      src="/images/hero-640.jpg"
      srcset="
        /images/hero-320.jpg 320w, 
        /images/hero-640.jpg 640w, 
        /images/hero-1280.jpg 1280w
      "
      sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw"
      alt="产品展示图"
      loading="lazy"
      class="w-full h-auto object-cover"
    >
  </picture>

  <!-- ✅ 图片懒加载组件 -->
  <LazyImage
    :src="imageSrc"
    :alt="imageAlt"
    :placeholder="placeholderSrc"
    class="w-full h-64 object-cover"
  />
</template>

<script setup lang="ts">
// ✅ 图片懒加载 Composable
export function useLazyImage() {
  const observer = ref<IntersectionObserver | null>(null);
  const isLoaded = ref(false);
  const isInView = ref(false);

  const observeElement = (element: HTMLElement) => {
    if (!observer.value) {
      observer.value = new IntersectionObserver(
        (entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
              isInView.value = true;
              observer.value?.unobserve(entry.target);
            }
          });
        },
        { threshold: 0.1 }
      );
    }
    observer.value.observe(element);
  };

  const loadImage = (src: string): Promise<void> => {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => {
        isLoaded.value = true;
        resolve();
      };
      img.onerror = reject;
      img.src = src;
    });
  };

  onUnmounted(() => {
    observer.value?.disconnect();
  });

  return {
    isLoaded,
    isInView,
    observeElement,
    loadImage,
  };
}
</script>
```

### 响应式图片配置
```typescript
// ✅ 图片配置管理
interface ImageConfig {
  src: string;
  srcset: string;
  sizes: string;
  alt: string;
  loading: 'lazy' | 'eager';
}

const getResponsiveImage = (baseName: string): ImageConfig => {
  return {
    src: `/images/${baseName}-640.jpg`,
    srcset: `
      /images/${baseName}-320.jpg 320w,
      /images/${baseName}-640.jpg 640w,
      /images/${baseName}-1280.jpg 1280w
    `,
    sizes: '(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw',
    alt: `${baseName} 图片`,
    loading: 'lazy',
  };
};
```

## 🎬 动画与交互

### 缓动函数规范
```css
/* ✅ 遵循设计稿动画规范 */
:root {
  /* 缓动函数 */
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

/* ✅ 过渡时长 */
.transition-fast { 
  transition-duration: 150ms; 
}

.transition-normal { 
  transition-duration: 300ms; 
}

.transition-slow { 
  transition-duration: 500ms; 
}
```

### 常用动画实现
```css
/* ✅ 淡入淡出动画 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s var(--ease-in-out);
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

/* ✅ 滑入动画 */
.slide-up-enter-active,
.slide-up-leave-active {
  transition: all 0.3s var(--ease-in-out);
}

.slide-up-enter-from {
  opacity: 0;
  transform: translateY(20px);
}

.slide-up-leave-to {
  opacity: 0;
  transform: translateY(-20px);
}

/* ✅ 缩放动画 */
.scale-enter-active,
.scale-leave-active {
  transition: all 0.2s var(--ease-out);
}

.scale-enter-from,
.scale-leave-to {
  opacity: 0;
  transform: scale(0.95);
}
```

### 交互状态设计
```vue
<template>
  <!-- ✅ 完整的交互状态 -->
  <button 
    class="
      px-4 py-2 
      bg-blue-500 text-white 
      rounded-lg 
      transition-all duration-200 
      hover:bg-blue-600 
      focus:ring-2 focus:ring-blue-300 
      active:scale-95 
      disabled:opacity-50 disabled:cursor-not-allowed
    "
    :disabled="loading"
    @click="handleClick"
  >
    <span v-if="loading" class="inline-block animate-spin mr-2">⟳</span>
    {{ loading ? '处理中...' : '提交' }}
  </button>
</template>
```

## 🎯 响应式设计最佳实践

### 必需配置项
- ✅ 移动端优先设计
- ✅ 使用响应式断点
- ✅ 实现图片懒加载和优化
- ✅ 配置动画和交互状态
- ✅ 支持多设备适配

### 参考文件
- `styles/responsive.css` - 响应式样式
- `components/LazyImage.vue` - 懒加载图片组件
- `utils/image-config.ts` - 图片配置工具
- `composables/useLazyImage.ts` - 懒加载组合式函数