CSS Container Queries 入门
Container Queries 终于来了,这是 CSS 的重大突破。
为什么需要 Container Queries?
Media Queries 基于视口大小,但有时我们需要基于容器大小:
/* Media Query: 基于视口 */
@media (min-width: 768px) {
.card {
display: flex;
}
}
/* Container Query: 基于容器 */
@container (min-width: 400px) {
.card {
display: flex;
}
}
基本用法
定义容器
/* 定义查询容器 */
.card-container {
container-type: inline-size;
container-name: card;
}
/* 简写 */
.sidebar {
container: sidebar / inline-size;
}
使用容器查询
/* 默认样式 */
.card {
display: block;
}
/* 当容器宽度 >= 400px */
@container (min-width: 400px) {
.card {
display: flex;
gap: 1rem;
}
.card-image {
width: 200px;
}
}
/* 更宽时 */
@container (min-width: 600px) {
.card {
padding: 2rem;
}
.card-title {
font-size: 2rem;
}
}
容器类型
inline-size
基于行内方向尺寸查询:
.container {
container-type: inline-size;
}
@container (min-width: 500px) {
/* 基于容器 inline-size */
}
size
基于两个方向尺寸查询:
.container {
container-type: size;
}
@container (min-width: 500px) and (min-height: 300px) {
/* 需要两个方向都满足 */
}
命名容器
当嵌套多个容器时,可以指定容器名称:
/* 定义命名容器 */
.card-wrapper {
container: card / inline-size;
}
.sidebar {
container: sidebar / inline-size;
}
/* 指定容器查询 */
@container card (min-width: 400px) {
.card-title {
font-size: 1.5rem;
}
}
@container sidebar (min-width: 300px) {
.widget {
padding: 1rem;
}
}
实战案例
响应式卡片组件
<div class="grid">
<div class="card-container">
<article class="card">
<img src="image.jpg" class="card-image" />
<div class="card-content">
<h2 class="card-title">标题</h2>
<p class="card-desc">描述</p>
</div>
</article>
</div>
</div>
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
}
.card-container {
container-type: inline-size;
}
/* 默认:垂直布局 */
.card {
display: flex;
flex-direction: column;
}
.card-image {
width: 100%;
aspect-ratio: 16/9;
object-fit: cover;
}
/* 容器 >= 400px:水平布局 */
@container (min-width: 400px) {
.card {
flex-direction: row;
}
.card-image {
width: 200px;
aspect-ratio: 1;
}
}
/* 容器 >= 600px:更大的间距 */
@container (min-width: 600px) {
.card {
gap: 2rem;
padding: 2rem;
}
.card-title {
font-size: 1.75rem;
}
}
响应式导航
.nav-container {
container-type: inline-size;
}
.nav {
display: flex;
flex-direction: column;
}
@container (min-width: 500px) {
.nav {
flex-direction: row;
justify-content: space-between;
}
.nav-menu {
display: flex;
gap: 1rem;
}
}
与 Media Queries 对比
/* Media Query: 全局响应式 */
@media (min-width: 768px) {
.main-content {
display: grid;
grid-template-columns: 300px 1fr;
}
}
/* Container Query: 组件级响应式 */
@container (min-width: 300px) {
.sidebar-widget {
padding: 1rem;
}
}
查询单位
cqw / cqh
容器查询宽高单位:
.element {
/* 容器宽度的 10% */
width: 10cqw;
/* 容器高度的 50% */
height: 50cqh;
}
/* 响应式字体大小 */
.title {
font-size: clamp(1rem, 5cqw, 2rem);
}
其他单位
/* 容器 inline 方向 */
font-size: 3cqi;
/* 容器 block 方向 */
padding: 2cqb;
/* min(inline, block) */
gap: 5cqmin;
/* max(inline, block) */
width: 80cqmax;
浏览器支持
/* 渐进增强 */
@supports (container-type: inline-size) {
.container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
flex-direction: row;
}
}
}
/* 降级方案 */
@supports not (container-type: inline-size) {
@media (min-width: 768px) {
.card {
flex-direction: row;
}
}
}
最佳实践
- 合理选择容器: 确定合适的查询边界
- 避免过度嵌套: 减少容器层级
- 渐进增强: 提供降级方案
- 性能考虑: 避免过多容器查询
小结
Container Queries 要点:
- 基于容器而非视口查询
- 定义 container-type
- 使用 @container 规则
这是组件级响应式设计的重大进步。
CSS
返回首页