CSS Container Style Queries represent a powerful evolution in responsive design, allowing components to adapt based on their container's properties rather than just the viewport. This approach enables truly modular and reusable components that can maintain their intended design across different contexts.
Understanding Container Style Queries
Container Style Queries extend beyond traditional media queries by allowing styles to respond to the properties of a containing element rather than just the viewport. This makes components more portable and maintainable.
Setting Up a Container
First, define a containment context:
.card-container {
container-type: inline-size;
container-name: card;
}
.card {
display: grid;
gap: 1rem;
padding: 1rem;
}
Basic Container Query
Create styles that respond to container width:
@container card (min-width: 400px) {
.card {
grid-template-columns: 200px 1fr;
}
}
@container card (max-width: 399px) {
.card {
grid-template-columns: 1fr;
}
}
Advanced Container Style Features
Style Queries
Style queries allow you to query the computed styles of the container:
.dynamic-section {
container: inline-size / section;
}
@container style(background-color: rgb(255, 255, 255)) {
.dynamic-text {
color: black;
}
}
@container style(background-color: rgb(0, 0, 0)) {
.dynamic-text {
color: white;
}
}
Nested Containers
Create hierarchical responsive layouts:
.outer-container {
container-type: inline-size;
container-name: outer;
}
.inner-container {
container-type: inline-size;
container-name: inner;
}
@container outer (min-width: 700px) {
.outer-content {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
}
@container inner (min-width: 300px) {
.inner-content {
display: flex;
gap: 1rem;
}
}
Practical Applications
Card Components
Create adaptive card layouts:
.card-grid {
container-type: inline-size;
display: grid;
gap: 1rem;
padding: 1rem;
}
.card {
background: white;
padding: 1rem;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
@container (min-width: 600px) {
.card-grid {
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.card {
display: grid;
grid-template-columns: auto 1fr;
gap: 1rem;
}
}
Navigation Components
Build responsive navigation systems:
.nav-container {
container-type: inline-size;
container-name: nav;
}
.nav-list {
display: flex;
flex-wrap: wrap;
gap: 1rem;
list-style: none;
padding: 0;
}
@container nav (max-width: 500px) {
.nav-list {
flex-direction: column;
}
.nav-item {
width: 100%;
text-align: center;
}
}
Form Layouts
Create adaptive form layouts:
.form-container {
container-type: inline-size;
container-name: form;
}
.form-group {
margin-bottom: 1rem;
}
@container form (min-width: 400px) {
.form-group {
display: grid;
grid-template-columns: 150px 1fr;
align-items: center;
gap: 1rem;
}
}
Best Practices
Performance Optimization
Optimize container query performance:
/* Limit containment scope */
.container {
container-type: inline-size;
content-visibility: auto;
}
/* Use logical properties */
@container (inline-size > 300px) {
.component {
margin-inline: auto;
padding-block: 1rem;
}
}
Fallback Support
Implement graceful fallbacks:
/* Base styles */
.component {
display: block;
width: 100%;
}
/* @supports fallback */
@supports not (container-type: inline-size) {
.component {
/* Fallback styles */
max-width: 600px;
margin: 0 auto;
}
}
/* Container query styles */
@container (min-width: 400px) {
.component {
display: grid;
grid-template-columns: 2fr 1fr;
}
}
Advanced Techniques
Combining with Custom Properties
Use CSS variables for dynamic values:
.container {
container-type: inline-size;
--spacing: 1rem;
}
@container (min-width: 600px) {
.container {
--spacing: 2rem;
}
}
.content {
padding: var(--spacing);
gap: calc(var(--spacing) / 2);
}
State-Based Container Queries
Respond to container states:
.expandable-container {
container-type: inline-size;
container-name: expandable;
}
.expandable-container[data-state="expanded"] {
/* Expanded state styles */
}
@container expandable (min-width: 500px) {
.expandable-container[data-state="expanded"] .content {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
}
Real-World Examples
Product Card
Create an adaptive product card component:
.product-container {
container-type: inline-size;
container-name: product;
}
.product-card {
display: grid;
gap: 1rem;
padding: 1rem;
background: white;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
@container product (min-width: 300px) {
.product-card {
grid-template-columns: 150px 1fr;
}
.product-image {
aspect-ratio: 1;
object-fit: cover;
}
}
@container product (min-width: 400px) {
.product-details {
display: grid;
grid-template-columns: 1fr auto;
align-items: start;
}
}
Container Style Queries provide a powerful tool for creating truly responsive and maintainable components. By understanding and implementing these techniques, you can build more flexible and robust web applications that adapt seamlessly to their container context rather than just the viewport size.