responsive-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Responsive Patterns

响应式设计模式

Modern responsive design patterns using Container Queries, fluid typography, and mobile-first strategies for React applications (2026 best practices).
适用于React应用的现代化响应式设计模式,采用Container Queries、流体排版和移动优先策略(2026最佳实践)。

Overview

概述

  • Building reusable components that adapt to their container
  • Implementing fluid typography that scales smoothly
  • Creating responsive layouts without media query overload
  • Building design system components for multiple contexts
  • Optimizing for variable container sizes (sidebars, modals, grids)
  • 构建可适配容器的可复用组件
  • 实现平滑缩放的流体排版
  • 无需大量媒体查询即可创建响应式布局
  • 为多场景构建设计系统组件
  • 针对可变容器尺寸(侧边栏、模态框、网格)进行优化

Core Concepts

核心概念

Container Queries vs Media Queries

容器查询 vs 媒体查询

FeatureMedia QueriesContainer Queries
Responds toViewport sizeContainer size
Component reuseContext-dependentTruly portable
Browser supportUniversalBaseline 2023+
Use casePage layoutsComponent layouts
特性媒体查询容器查询
响应依据视口尺寸容器尺寸
组件复用性依赖上下文真正可移植
浏览器支持全兼容2023年基线版本+
使用场景页面布局组件布局

CSS Patterns

CSS设计模式

1. Container Query Basics

1. 容器查询基础

css
/* Define a query container */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* Style based on container width */
@container card (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}

@container card (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}
css
/* 定义查询容器 */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* 根据容器宽度设置样式 */
@container card (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}

@container card (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}

2. Container Query Units (cqi, cqb)

2. 容器查询单位(cqi, cqb)

css
/* Use cqi (container query inline) over cqw */
.card-title {
  /* 5% of container's inline size */
  font-size: clamp(1rem, 5cqi, 2rem);
}

.card-content {
  /* Responsive padding based on container */
  padding: 2cqi;
}

/* cqb for block dimension (height-aware containers) */
.sidebar-item {
  height: 10cqb;
}
css
/* 使用cqi(容器查询内联单位)替代cqw */
.card-title {
  /* 容器内联尺寸的5% */
  font-size: clamp(1rem, 5cqi, 2rem);
}

.card-content {
  /* 基于容器的响应式内边距 */
  padding: 2cqi;
}

/* cqb用于块级维度(感知高度的容器) */
.sidebar-item {
  height: 10cqb;
}

3. Fluid Typography with clamp()

3. 结合clamp()的流体排版

css
/* Accessible fluid typography */
:root {
  /* Base font respects user preferences (rem) */
  --font-size-base: 1rem;

  /* Fluid scale with min/max bounds */
  --font-size-sm: clamp(0.875rem, 0.8rem + 0.25vw, 1rem);
  --font-size-md: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
  --font-size-lg: clamp(1.25rem, 1rem + 1vw, 2rem);
  --font-size-xl: clamp(1.5rem, 1rem + 2vw, 3rem);
  --font-size-2xl: clamp(2rem, 1rem + 3vw, 4rem);
}

h1 { font-size: var(--font-size-2xl); }
h2 { font-size: var(--font-size-xl); }
h3 { font-size: var(--font-size-lg); }
p { font-size: var(--font-size-md); }
small { font-size: var(--font-size-sm); }
css
/* 符合无障碍标准的流体排版 */
:root {
  /* 基础字体尊重用户偏好(rem单位) */
  --font-size-base: 1rem;

  /* 带最小/最大限制的流体缩放 */
  --font-size-sm: clamp(0.875rem, 0.8rem + 0.25vw, 1rem);
  --font-size-md: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
  --font-size-lg: clamp(1.25rem, 1rem + 1vw, 2rem);
  --font-size-xl: clamp(1.5rem, 1rem + 2vw, 3rem);
  --font-size-2xl: clamp(2rem, 1rem + 3vw, 4rem);
}

h1 { font-size: var(--font-size-2xl); }
h2 { font-size: var(--font-size-xl); }
h3 { font-size: var(--font-size-lg); }
p { font-size: var(--font-size-md); }
small { font-size: var(--font-size-sm); }

4. Container-Based Fluid Typography

4. 基于容器的流体排版

css
/* For component-scoped fluid text */
.widget {
  container-type: inline-size;
}

.widget-title {
  /* Fluid within container, respecting user rem */
  font-size: clamp(1rem, 0.5rem + 5cqi, 2rem);
}

.widget-body {
  font-size: clamp(0.875rem, 0.5rem + 3cqi, 1.125rem);
}
css
/* 组件作用域内的流体文本 */
.widget {
  container-type: inline-size;
}

.widget-title {
  /* 在容器内流体缩放,同时尊重用户的rem设置 */
  font-size: clamp(1rem, 0.5rem + 5cqi, 2rem);
}

.widget-body {
  font-size: clamp(0.875rem, 0.5rem + 3cqi, 1.125rem);
}

5. Mobile-First Breakpoints

5. 移动优先断点

css
/* Mobile-first: start small, add complexity */
.layout {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Tablet and up */
@media (min-width: 768px) {
  .layout {
    flex-direction: row;
  }
}

/* Desktop */
@media (min-width: 1024px) {
  .layout {
    max-width: 1200px;
    margin-inline: auto;
  }
}
css
/* 移动优先:从简单布局开始,逐步增加复杂度 */
.layout {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* 平板及以上设备 */
@media (min-width: 768px) {
  .layout {
    flex-direction: row;
  }
}

/* 桌面设备 */
@media (min-width: 1024px) {
  .layout {
    max-width: 1200px;
    margin-inline: auto;
  }
}

6. CSS Grid Responsive Patterns

6. CSS网格响应式模式

css
/* Auto-fit grid (fills available space) */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.5rem;
}

/* Auto-fill grid (maintains minimum columns) */
.icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  gap: 1rem;
}

/* Subgrid for nested alignment */
.card {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3;
}
css
/* 自动适配网格(填充可用空间) */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.5rem;
}

/* 自动填充网格(保持最小列数) */
.icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  gap: 1rem;
}

/* 用于嵌套对齐的子网格 */
.card {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3;
}

7. Container Scroll-Queries (Chrome 126+)

7. 容器滚动查询(Chrome 126+)

css
/* Query based on scroll state */
.scroll-container {
  container-type: scroll-state;
  container-name: scroller;
}

@container scroller scroll-state(scrollable: top) {
  .scroll-indicator-top {
    opacity: 0;
  }
}

@container scroller scroll-state(scrollable: bottom) {
  .scroll-indicator-bottom {
    opacity: 0;
  }
}
css
/* 根据滚动状态查询 */
.scroll-container {
  container-type: scroll-state;
  container-name: scroller;
}

@container scroller scroll-state(scrollable: top) {
  .scroll-indicator-top {
    opacity: 0;
  }
}

@container scroller scroll-state(scrollable: bottom) {
  .scroll-indicator-bottom {
    opacity: 0;
  }
}

React Patterns

React设计模式

Responsive Component with Container Queries

结合容器查询的响应式组件

tsx
import { cn } from '@/lib/utils';

interface CardProps {
  title: string;
  description: string;
  image: string;
}

export function ResponsiveCard({ title, description, image }: CardProps) {
  return (
    <div className="@container">
      <article className={cn(
        "flex flex-col gap-4",
        "@md:flex-row @md:gap-6" // Container query breakpoints
      )}>
        <img
          src={image}
          alt=""
          className="w-full @md:w-48 aspect-video object-cover rounded-lg"
        />
        <div className="flex flex-col gap-2">
          <h3 className="text-[clamp(1rem,0.5rem+3cqi,1.5rem)] font-semibold">
            {title}
          </h3>
          <p className="text-[clamp(0.875rem,0.5rem+2cqi,1rem)] text-muted-foreground">
            {description}
          </p>
        </div>
      </article>
    </div>
  );
}
tsx
import { cn } from '@/lib/utils';

interface CardProps {
  title: string;
  description: string;
  image: string;
}

export function ResponsiveCard({ title, description, image }: CardProps) {
  return (
    <div className="@container">
      <article className={cn(
        "flex flex-col gap-4",
        "@md:flex-row @md:gap-6" // 容器查询断点
      )}>
        <img
          src={image}
          alt=""
          className="w-full @md:w-48 aspect-video object-cover rounded-lg"
        />
        <div className="flex flex-col gap-2">
          <h3 className="text-[clamp(1rem,0.5rem+3cqi,1.5rem)] font-semibold">
            {title}
          </h3>
          <p className="text-[clamp(0.875rem,0.5rem+2cqi,1rem)] text-muted-foreground">
            {description}
          </p>
        </div>
      </article>
    </div>
  );
}

Tailwind CSS Container Queries

Tailwind CSS容器查询

tsx
// @container enables container query variants (@sm, @md, @lg, etc.)
<div className="@container">
  <div className="flex flex-col @lg:flex-row @xl:gap-8">
    <div className="@sm:p-4 @md:p-6 @lg:p-8">
      Content adapts to container
    </div>
  </div>
</div>
tsx
// @container 启用容器查询变体(@sm, @md, @lg等)
<div className="@container">
  <div className="flex flex-col @lg:flex-row @xl:gap-8">
    <div className="@sm:p-4 @md:p-6 @lg:p-8">
      内容将适配容器尺寸
    </div>
  </div>
</div>

useContainerQuery Hook

useContainerQuery钩子

tsx
import { useRef, useState, useEffect } from 'react';

function useContainerQuery(breakpoint: number) {
  const ref = useRef<HTMLDivElement>(null);
  const [isAbove, setIsAbove] = useState(false);

  useEffect(() => {
    const element = ref.current;
    if (!element) return;

    const observer = new ResizeObserver(([entry]) => {
      setIsAbove(entry.contentRect.width >= breakpoint);
    });

    observer.observe(element);
    return () => observer.disconnect();
  }, [breakpoint]);

  return [ref, isAbove] as const;
}

// Usage
function AdaptiveCard() {
  const [containerRef, isWide] = useContainerQuery(400);

  return (
    <div ref={containerRef}>
      {isWide ? <HorizontalLayout /> : <VerticalLayout />}
    </div>
  );
}
tsx
import { useRef, useState, useEffect } from 'react';

function useContainerQuery(breakpoint: number) {
  const ref = useRef<HTMLDivElement>(null);
  const [isAbove, setIsAbove] = useState(false);

  useEffect(() => {
    const element = ref.current;
    if (!element) return;

    const observer = new ResizeObserver(([entry]) => {
      setIsAbove(entry.contentRect.width >= breakpoint);
    });

    observer.observe(element);
    return () => observer.disconnect();
  }, [breakpoint]);

  return [ref, isAbove] as const;
}

// 使用示例
function AdaptiveCard() {
  const [containerRef, isWide] = useContainerQuery(400);

  return (
    <div ref={containerRef}>
      {isWide ? <HorizontalLayout /> : <VerticalLayout />}
    </div>
  );
}

Responsive Images Pattern

响应式图片模式

tsx
function ResponsiveImage({
  src,
  alt,
  sizes = "(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
}: {
  src: string;
  alt: string;
  sizes?: string;
}) {
  return (
    <picture>
      {/* Art direction with different crops */}
      <source
        media="(max-width: 640px)"
        srcSet={`${src}?w=640&aspect=1:1`}
      />
      <source
        media="(max-width: 1024px)"
        srcSet={`${src}?w=800&aspect=4:3`}
      />
      <img
        src={`${src}?w=1200`}
        alt={alt}
        sizes={sizes}
        loading="lazy"
        decoding="async"
        className="w-full h-auto object-cover"
      />
    </picture>
  );
}
tsx
function ResponsiveImage({
  src,
  alt,
  sizes = "(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
}: {
  src: string;
  alt: string;
  sizes?: string;
}) {
  return (
    <picture>
      {/* 按场景调整图片裁剪 */}
      <source
        media="(max-width: 640px)"
        srcSet={`${src}?w=640&aspect=1:1`}
      />
      <source
        media="(max-width: 1024px)"
        srcSet={`${src}?w=800&aspect=4:3`}
      />
      <img
        src={`${src}?w=1200`}
        alt={alt}
        sizes={sizes}
        loading="lazy"
        decoding="async"
        className="w-full h-auto object-cover"
      />
    </picture>
  );
}

Accessibility Considerations

无障碍设计注意事项

css
/* IMPORTANT: Always include rem in fluid typography */
/* This ensures user font preferences are respected */

/* ❌ WRONG: Viewport-only ignores user preferences */
font-size: 5vw;

/* ✅ CORRECT: Include rem to respect user settings */
font-size: clamp(1rem, 0.5rem + 2vw, 2rem);

/* User zooming must still work */
@media (min-width: 768px) {
  /* Use em/rem, not px, for breakpoints in ideal world */
  /* (browsers still use px, but consider user zoom) */
}
css
/* 重要提示:流体排版中务必包含rem单位 */
/* 这能确保尊重用户的字体偏好设置 */

/* ❌ 错误:仅使用视口单位会忽略用户偏好 */
font-size: 5vw;

/* ✅ 正确:包含rem以尊重用户设置 */
font-size: clamp(1rem, 0.5rem + 2vw, 2rem);

/* 用户缩放功能必须正常工作 */
@media (min-width: 768px) {
  /* 理想情况下使用em/rem,而非px作为断点 */
  /* (浏览器仍支持px,但需考虑用户缩放) */
}

Anti-Patterns (FORBIDDEN)

反模式(禁止使用)

css
/* ❌ NEVER: Use only viewport units for text */
.title {
  font-size: 5vw; /* Ignores user font preferences! */
}

/* ❌ NEVER: Use cqw/cqh (use cqi/cqb instead) */
.card {
  padding: 5cqw; /* cqw = container width, not logical */
}
/* ✅ CORRECT: Use logical units */
.card {
  padding: 5cqi; /* Container inline = logical direction */
}

/* ❌ NEVER: Container queries without container-type */
@container (min-width: 400px) {
  /* Won't work without container-type on parent! */
}

/* ❌ NEVER: Desktop-first media queries */
.element {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
@media (max-width: 768px) {
  .element {
    grid-template-columns: 1fr; /* Overriding = more CSS */
  }
}

/* ❌ NEVER: Fixed pixel breakpoints for text */
@media (min-width: 768px) {
  body { font-size: 18px; } /* Use rem! */
}

/* ❌ NEVER: Over-nesting container queries */
@container a {
  @container b {
    @container c {
      /* Too complex, reconsider architecture */
    }
  }
}
css
/* ❌ 绝对禁止:仅使用视口单位设置文本大小 */
.title {
  font-size: 5vw; /* 忽略了用户的字体偏好设置! */
}

/* ❌ 绝对禁止:使用cqw/cqh(改用cqi/cqb) */
.card {
  padding: 5cqw; /* cqw = 容器宽度,不符合逻辑方向 */
}
/* ✅ 正确:使用逻辑单位 */
.card {
  padding: 5cqi; /* 容器内边距 = 逻辑方向 */
}

/* ❌ 绝对禁止:未设置container-type就使用容器查询 */
@container (min-width: 400px) {
  /* 父元素未设置container-type则无法生效! */
}

/* ❌ 绝对禁止:桌面优先的媒体查询 */
.element {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
@media (max-width: 768px) {
  .element {
    grid-template-columns: 1fr; /* 覆盖原有样式 = 更多CSS代码 */
  }
}

/* ❌ 绝对禁止:为文本使用固定像素断点 */
@media (min-width: 768px) {
  body { font-size: 18px; } /* 请使用rem! */
}

/* ❌ 绝对禁止:过度嵌套容器查询 */
@container a {
  @container b {
    @container c {
      /* 过于复杂,请重新考虑架构设计 */
    }
  }
}

Browser Support

浏览器支持

FeatureChromeSafariFirefoxEdge
Container Size Queries105+16+110+105+
Container Style Queries111+111+
Container Scroll-State126+126+
cqi/cqb units105+16+110+105+
clamp()79+13.1+75+79+
Subgrid117+16+71+117+
特性ChromeSafariFirefoxEdge
容器尺寸查询105+16+110+105+
容器样式查询111+111+
容器滚动状态查询126+126+
cqi/cqb单位105+16+110+105+
clamp()79+13.1+75+79+
子网格117+16+71+117+

Rules

规范

Each category has individual rule files in
rules/
loaded on-demand:
CategoryRuleImpactKey Pattern
PWA
rules/pwa-service-worker.md
HIGHWorkbox caching strategies, VitePWA, update management
PWA
rules/pwa-offline.md
HIGHOffline hooks, background sync, install prompts
Animation
rules/animation-motion.md
HIGHMotion presets, AnimatePresence, View Transitions
Animation
rules/animation-scroll.md
MEDIUMCSS scroll-driven animations, parallax, progressive enhancement
Total: 4 rules across 2 categories
每个分类的独立规范文件位于
rules/
目录,按需加载:
分类规范影响程度核心模式
PWA
rules/pwa-service-worker.md
Workbox缓存策略、VitePWA、更新管理
PWA
rules/pwa-offline.md
离线钩子、后台同步、安装提示
动画
rules/animation-motion.md
动效预设、AnimatePresence、视图过渡
动画
rules/animation-scroll.md
CSS滚动驱动动画、视差滚动、渐进式增强
总计:2个分类下的4条规范

Key Decisions

关键决策

DecisionOption AOption BRecommendation
Query typeMedia queriesContainer queriesContainer for components, Media for layout
Container unitscqw/cqhcqi/cqbcqi/cqb (logical, i18n-ready)
Fluid type basevw onlyrem + vwrem + vw (accessibility)
Mobile-firstYesDesktop-firstMobile-first (less CSS, progressive)
Grid patternauto-fitauto-fillauto-fit for cards, auto-fill for icons
决策项选项A选项B推荐方案
查询类型媒体查询容器查询容器查询用于组件,媒体查询用于页面布局
容器单位cqw/cqhcqi/cqbcqi/cqb(符合逻辑方向,支持国际化)
流体排版基准仅vwrem + vwrem + vw(符合无障碍设计)
优先策略移动优先桌面优先移动优先(更少CSS代码,渐进式增强)
网格模式auto-fitauto-fill卡片布局用auto-fit,图标布局用auto-fill

Related Skills

相关技能

  • design-system-starter
    - Building responsive design systems
  • performance
    - CLS, responsive images, and image optimization
  • i18n-date-patterns
    - RTL/LTR responsive considerations
  • design-system-starter
    - 构建响应式设计系统
  • performance
    - CLS优化、响应式图片、图片性能优化
  • i18n-date-patterns
    - 从右到左/从左到右布局的响应式考量

Capability Details

能力详情

container-queries

container-queries

Keywords: @container, container-type, inline-size, container-name Solves: Component-level responsive design
关键词: @container, container-type, inline-size, container-name 解决问题: 组件级别的响应式设计

fluid-typography

fluid-typography

Keywords: clamp(), fluid, vw, rem, scale, typography Solves: Smooth font scaling without breakpoints
关键词: clamp(), fluid, vw, rem, scale, typography 解决问题: 无需断点即可实现平滑的字体缩放

responsive-images

responsive-images

Keywords: srcset, sizes, picture, art direction Solves: Responsive images for different viewports
关键词: srcset, sizes, picture, art direction 解决问题: 为不同视口提供响应式图片

mobile-first-strategy

mobile-first-strategy

Keywords: min-width, mobile, progressive, breakpoints Solves: Efficient responsive CSS architecture
关键词: min-width, mobile, progressive, breakpoints 解决问题: 高效的响应式CSS架构

grid-flexbox-patterns

grid-flexbox-patterns

Keywords: auto-fit, auto-fill, subgrid, minmax Solves: Responsive grid and flexbox layouts
关键词: auto-fit, auto-fill, subgrid, minmax 解决问题: 响应式网格和弹性盒布局

container-units

container-units

Keywords: cqi, cqb, container width, container height Solves: Sizing relative to container dimensions
关键词: cqi, cqb, container width, container height 解决问题: 基于容器尺寸的元素 sizing

References

参考资料

  • references/container-queries.md
    - Container query patterns
  • references/fluid-typography.md
    - Accessible fluid type scales
  • scripts/responsive-card.tsx
    - Responsive card component
  • references/container-queries.md
    - 容器查询设计模式
  • references/fluid-typography.md
    - 符合无障碍标准的流体排版规范
  • scripts/responsive-card.tsx
    - 响应式卡片组件示例