CSS Grid and Flexbox Integration
1. Grid Template Generation with Loops
| Pattern | Technique | Output | Use Case |
|---|---|---|---|
| Column Classes | @for loop generation | .col-1 through .col-12 | Grid systems |
| Dynamic Templates | Interpolation in templates | repeat(#{$cols}, 1fr) | Responsive grids |
| Gap Utilities | Map iteration | .gap-1, .gap-2, etc. | Spacing system |
| Area Templates | String building | Named grid areas | Complex layouts |
| Auto-fit/fill | Mixin generation | Responsive columns | Flexible layouts |
Example: Generate grid column classes
// Basic grid system (12 columns)
@for $i from 1 through 12 {
.col-#{$i} {
grid-column: span $i;
}
}
// Output:
// .col-1 { grid-column: span 1; }
// .col-2 { grid-column: span 2; }
// ...
// .col-12 { grid-column: span 12; }
// Row span classes
@for $i from 1 through 6 {
.row-#{$i} {
grid-row: span $i;
}
}
// Column start positions
@for $i from 1 through 12 {
.col-start-#{$i} {
grid-column-start: $i;
}
.col-end-#{$i} {
grid-column-end: $i;
}
}
// Grid template variations
@for $cols from 1 through 6 {
.grid-cols-#{$cols} {
grid-template-columns: repeat($cols, 1fr);
}
}
// Output:
// .grid-cols-1 { grid-template-columns: repeat(1, 1fr); }
// .grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
// .grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
// ...
Example: Advanced grid template generation
// Gap utilities with spacing scale
$spacing-scale: (
0: 0,
1: 0.25rem,
2: 0.5rem,
3: 0.75rem,
4: 1rem,
5: 1.25rem,
6: 1.5rem,
8: 2rem,
10: 2.5rem,
12: 3rem,
16: 4rem
);
@each $key, $value in $spacing-scale {
.gap-#{$key} {
gap: $value;
}
.gap-x-#{$key} {
column-gap: $value;
}
.gap-y-#{$key} {
row-gap: $value;
}
}
// Responsive grid templates
$breakpoints: (
sm: 640px,
md: 768px,
lg: 1024px,
xl: 1280px
);
@each $name, $size in $breakpoints {
@media (min-width: $size) {
@for $cols from 1 through 12 {
.#{$name}\:grid-cols-#{$cols} {
grid-template-columns: repeat($cols, 1fr);
}
.#{$name}\:col-span-#{$cols} {
grid-column: span $cols;
}
}
}
}
// Usage:
// <div class="grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
Example: Complex grid area templates
// Grid area template builder
@mixin grid-areas($areas...) {
$template: '';
@each $row in $areas {
$template: $template + '"#{$row}" ';
}
grid-template-areas: #{$template};
}
// Usage
.layout {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
@include grid-areas(
'header header header',
'sidebar main aside',
'footer footer footer'
);
}
// Named grid lines
@mixin grid-lines($count: 12) {
$columns: ();
@for $i from 1 through $count + 1 {
$columns: append($columns, '[col-#{$i}] 1fr', comma);
}
grid-template-columns: $columns;
}
.grid-with-lines {
display: grid;
@include grid-lines(12);
}
// Generates:
// grid-template-columns: [col-1] 1fr [col-2] 1fr ... [col-13] 1fr;
// Dynamic grid based on item count
@mixin auto-grid($min-width: 250px, $max-cols: 4) {
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(min($min-width, 100%), 1fr)
);
gap: 1rem;
}
.card-grid {
@include auto-grid(300px);
}
2. Flexbox Utility Mixins and Functions
| Mixin | Properties | Use Case | Example |
|---|---|---|---|
| flex-center | justify + align center | Center content | Modal, cards |
| flex-between | justify space-between | Headers, toolbars | Logo + nav |
| flex-column | flex-direction column | Vertical layouts | Sidebars |
| flex-wrap | flex-wrap + gap | Tag clouds | Chip lists |
| flex-grow | Dynamic flex values | Flexible sizing | Form layouts |
Example: Comprehensive flexbox utility library
// Basic flex mixins
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin flex-between {
display: flex;
justify-content: space-between;
align-items: center;
}
@mixin flex-around {
display: flex;
justify-content: space-around;
align-items: center;
}
@mixin flex-evenly {
display: flex;
justify-content: space-evenly;
align-items: center;
}
@mixin flex-start {
display: flex;
justify-content: flex-start;
align-items: center;
}
@mixin flex-end {
display: flex;
justify-content: flex-end;
align-items: center;
}
// Column layouts
@mixin flex-column($gap: 0) {
display: flex;
flex-direction: column;
@if $gap != 0 {
gap: $gap;
}
}
@mixin flex-column-center {
@include flex-column;
align-items: center;
justify-content: center;
}
// Configurable flex
@mixin flex(
$direction: row,
$justify: flex-start,
$align: stretch,
$wrap: nowrap,
$gap: 0
) {
display: flex;
flex-direction: $direction;
justify-content: $justify;
align-items: $align;
flex-wrap: $wrap;
@if $gap != 0 {
gap: $gap;
}
}
// Usage
.header {
@include flex-between;
}
.card-content {
@include flex-column(1rem);
}
.toolbar {
@include flex(row, space-between, center, nowrap, 0.5rem);
}
Example: Advanced flexbox patterns
// Flex item utilities
@mixin flex-item($grow: 0, $shrink: 1, $basis: auto) {
flex: $grow $shrink $basis;
}
@mixin flex-grow($value: 1) {
flex-grow: $value;
flex-shrink: 1;
flex-basis: 0;
}
@mixin flex-shrink($value: 1) {
flex-shrink: $value;
}
@mixin flex-none {
flex: none; // Don't grow or shrink
}
// Holy grail layout
@mixin flex-holy-grail($sidebar-width: 250px) {
display: flex;
.sidebar {
@include flex-none;
width: $sidebar-width;
}
.main {
@include flex-grow;
}
}
// Flex wrap with gap fallback
@mixin flex-wrap($gap: 1rem) {
display: flex;
flex-wrap: wrap;
// Modern: use gap
gap: $gap;
// Fallback for older browsers
@supports not (gap: $gap) {
margin: calc(-#{$gap} / 2);
> * {
margin: calc(#{$gap} / 2);
}
}
}
// Responsive flex direction
@mixin flex-responsive(
$mobile-direction: column,
$desktop-direction: row,
$breakpoint: 768px
) {
display: flex;
flex-direction: $mobile-direction;
@media (min-width: $breakpoint) {
flex-direction: $desktop-direction;
}
}
// Usage
.card-list {
@include flex-wrap(1.5rem);
}
.feature-section {
@include flex-responsive(column, row, 768px);
}
// Equal height columns
@mixin flex-equal-height {
display: flex;
> * {
display: flex;
flex-direction: column;
flex: 1 1 0; // Equal width, equal height
}
}
Example: Flexbox utility class generator
// Generate flex utility classes
$flex-properties: (
'justify': (
'start': flex-start,
'end': flex-end,
'center': center,
'between': space-between,
'around': space-around,
'evenly': space-evenly
),
'align': (
'start': flex-start,
'end': flex-end,
'center': center,
'stretch': stretch,
'baseline': baseline
),
'direction': (
'row': row,
'row-reverse': row-reverse,
'col': column,
'col-reverse': column-reverse
),
'wrap': (
'wrap': wrap,
'nowrap': nowrap,
'wrap-reverse': wrap-reverse
)
);
@each $prop, $variants in $flex-properties {
@each $name, $value in $variants {
.#{$prop}-#{$name} {
@if $prop == 'justify' {
justify-content: $value;
} @else if $prop == 'align' {
align-items: $value;
} @else if $prop == 'direction' {
flex-direction: $value;
} @else if $prop == 'wrap' {
flex-wrap: $value;
}
}
}
}
// Flex grow/shrink classes
@for $i from 0 through 12 {
.flex-grow-#{$i} {
flex-grow: $i;
}
.flex-shrink-#{$i} {
flex-shrink: $i;
}
}
// Output:
// .justify-start { justify-content: flex-start; }
// .justify-center { justify-content: center; }
// .align-center { align-items: center; }
// .direction-row { flex-direction: row; }
// .flex-grow-1 { flex-grow: 1; }
// etc.
3. Layout Component Mixins
| Component | Layout Type | Features | Use Case |
|---|---|---|---|
| Card Grid | CSS Grid auto-fit | Responsive columns | Product listings |
| Sidebar Layout | Grid template areas | Named regions | Admin dashboards |
| Stack | Flexbox column + gap | Vertical spacing | Form fields |
| Cluster | Flexbox wrap + gap | Dynamic wrapping | Tags, badges |
| Split | Flexbox space-between | Push items apart | Headers |
| Center | Grid place-items | Perfect centering | Modals, heroes |
Example: Essential layout component mixins
// Stack - Vertical spacing
@mixin stack($gap: 1rem, $split-after: null) {
display: flex;
flex-direction: column;
gap: $gap;
@if $split-after {
> :nth-child(#{$split-after}) {
margin-bottom: auto;
}
}
}
// Cluster - Horizontal wrapping with gap
@mixin cluster($gap: 1rem, $justify: flex-start, $align: center) {
display: flex;
flex-wrap: wrap;
gap: $gap;
justify-content: $justify;
align-items: $align;
}
// Sidebar - Fixed sidebar + flexible content
@mixin sidebar(
$sidebar-width: 250px,
$gap: 1rem,
$side: left
) {
display: grid;
gap: $gap;
@if $side == left {
grid-template-columns: $sidebar-width 1fr;
} @else {
grid-template-columns: 1fr $sidebar-width;
}
@media (max-width: 768px) {
grid-template-columns: 1fr;
}
}
// Switcher - Switch from row to column at threshold
@mixin switcher($threshold: 768px, $gap: 1rem, $limit: 4) {
display: flex;
flex-wrap: wrap;
gap: $gap;
> * {
flex-grow: 1;
flex-basis: calc((#{$threshold} - 100%) * 999);
}
@if $limit {
> :nth-last-child(n + #{$limit + 1}),
> :nth-last-child(n + #{$limit + 1}) ~ * {
flex-basis: 100%;
}
}
}
// Cover - Centered content with header/footer
@mixin cover($gap: 1rem, $min-height: 100vh) {
display: flex;
flex-direction: column;
min-height: $min-height;
gap: $gap;
> * {
margin-block: 0;
}
> :first-child:not(.center) {
margin-block-start: 0;
}
> :last-child:not(.center) {
margin-block-end: 0;
}
> .center {
margin-block: auto;
}
}
// Usage
.tags {
@include cluster(0.5rem, flex-start, center);
}
.dashboard {
@include sidebar(300px, 2rem, left);
}
.card-stack {
@include stack(1.5rem);
}
.hero {
@include cover(2rem, 100vh);
}
Example: Grid-based layout components
// Auto-fit grid with minimum card width
@mixin auto-grid(
$min-width: 250px,
$gap: 1rem,
$max-cols: null
) {
display: grid;
gap: $gap;
@if $max-cols {
grid-template-columns: repeat(
auto-fit,
minmax(min($min-width, 100%), 1fr)
);
// Limit maximum columns
@supports (width: min($min-width, 100%)) {
grid-template-columns: repeat(
auto-fit,
minmax(min(#{$min-width}, calc(100% / #{$max-cols})), 1fr)
);
}
} @else {
grid-template-columns: repeat(
auto-fit,
minmax(min($min-width, 100%), 1fr)
);
}
}
// Reel - Horizontal scrolling container
@mixin reel($item-width: 300px, $gap: 1rem) {
display: flex;
gap: $gap;
overflow-x: auto;
overflow-y: hidden;
// Snap scroll
scroll-snap-type: x mandatory;
scroll-padding: $gap;
> * {
flex: 0 0 $item-width;
scroll-snap-align: start;
}
// Hide scrollbar
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
// Imposter - Centered overlay
@mixin imposter($fixed: false) {
@if $fixed {
position: fixed;
} @else {
position: absolute;
}
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
// Frame - Aspect ratio container
@mixin frame($ratio: 16/9) {
aspect-ratio: $ratio;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
// Fallback for browsers without aspect-ratio
@supports not (aspect-ratio: $ratio) {
position: relative;
padding-bottom: calc(100% / (#{$ratio}));
> * {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
}
// Usage
.product-grid {
@include auto-grid(280px, 1.5rem, 4);
}
.carousel {
@include reel(350px, 1rem);
}
.video-container {
@include frame(16/9);
}
.modal-overlay {
@include imposter(fixed);
}
Example: Complex layout patterns
// Holy Grail layout with header and footer
@mixin holy-grail(
$sidebar-width: 250px,
$aside-width: 200px,
$gap: 1rem
) {
display: grid;
grid-template-columns: $sidebar-width 1fr $aside-width;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
gap: $gap;
min-height: 100vh;
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
@media (max-width: 1024px) {
grid-template-columns: $sidebar-width 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
.aside {
display: none;
}
}
@media (max-width: 768px) {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"footer";
.sidebar {
display: none;
}
}
}
// Pancake stack - Header/Content/Footer
@mixin pancake-stack {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
// 12-column grid system
@mixin twelve-column-grid($gap: 1rem) {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: $gap;
// Span helpers
@for $i from 1 through 12 {
.span-#{$i} {
grid-column: span $i;
}
}
}
// Masonry-like layout (column approach)
@mixin masonry($columns: 3, $gap: 1rem) {
column-count: $columns;
column-gap: $gap;
> * {
break-inside: avoid;
margin-bottom: $gap;
}
@media (max-width: 1024px) {
column-count: $columns - 1;
}
@media (max-width: 768px) {
column-count: 1;
}
}
// Usage
.app-layout {
@include holy-grail(280px, 220px, 1.5rem);
}
.page {
@include pancake-stack;
}
.gallery {
@include masonry(4, 1rem);
}
4. Responsive Layout Patterns
| Pattern | Technique | Behavior | Best For |
|---|---|---|---|
| RAM Pattern | repeat(auto-fit, minmax()) | Auto-responsive columns | Card grids |
| Flex Wrap | flex-wrap with flex-basis | Natural wrapping | Navigation, tags |
| Container Query | @container rule | Component-aware layout | Reusable components |
| Grid Template Areas | Named areas + media queries | Layout reorganization | Complex pages |
| Clamp Width | clamp() for fluid sizing | Self-adjusting | Fluid typography, spacing |
Example: Responsive auto-grid (RAM pattern)
// RAM = Repeat, Auto-fit, Minmax
@mixin responsive-grid(
$min: 250px,
$max: 1fr,
$gap: 1rem
) {
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(min($min, 100%), $max)
);
gap: $gap;
}
// With breakpoint override
@mixin responsive-grid-breakpoint(
$min: 250px,
$gap: 1rem,
$mobile-cols: 1,
$tablet-cols: 2,
$desktop-cols: null
) {
display: grid;
gap: $gap;
// Mobile
grid-template-columns: repeat($mobile-cols, 1fr);
// Tablet
@media (min-width: 640px) {
grid-template-columns: repeat($tablet-cols, 1fr);
}
// Desktop - use auto-fit
@media (min-width: 1024px) {
@if $desktop-cols {
grid-template-columns: repeat($desktop-cols, 1fr);
} @else {
grid-template-columns: repeat(
auto-fit,
minmax(min($min, 100%), 1fr)
);
}
}
}
// Flexible columns based on content
@mixin intrinsic-grid($min: 200px, $gap: 1rem) {
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax($min, max-content)
);
gap: $gap;
justify-content: start;
}
// Usage
.product-grid {
@include responsive-grid(280px, 1fr, 1.5rem);
}
.feature-cards {
@include responsive-grid-breakpoint(300px, 2rem, 1, 2, 3);
}
.tag-cloud {
@include intrinsic-grid(100px, 0.5rem);
}
Example: Responsive flex patterns
// Flex that switches to column on mobile
@mixin responsive-flex(
$breakpoint: 768px,
$gap: 1rem,
$mobile-gap: null
) {
display: flex;
gap: $gap;
@media (max-width: $breakpoint - 1) {
flex-direction: column;
@if $mobile-gap {
gap: $mobile-gap;
}
}
}
// Equal-width items that stack on mobile
@mixin equal-flex-items($items: 3, $breakpoint: 768px, $gap: 1rem) {
display: flex;
flex-wrap: wrap;
gap: $gap;
> * {
flex: 1 1 calc((100% / #{$items}) - #{$gap});
min-width: calc((100% / #{$items}) - #{$gap});
}
@media (max-width: $breakpoint) {
> * {
flex: 1 1 100%;
min-width: 100%;
}
}
}
// Flex with minimum item width
@mixin flex-responsive-items(
$min-width: 250px,
$gap: 1rem
) {
display: flex;
flex-wrap: wrap;
gap: $gap;
> * {
flex: 1 1 $min-width;
max-width: 100%;
}
}
// Priority sidebar (sidebar collapses first)
@mixin priority-sidebar(
$sidebar-width: 300px,
$content-min: 60%,
$gap: 1rem
) {
display: flex;
gap: $gap;
flex-wrap: wrap;
.sidebar {
flex: 1 1 $sidebar-width;
}
.content {
flex: 999 1 $content-min;
min-width: $content-min;
}
}
// Usage
.hero-content {
@include responsive-flex(768px, 2rem, 1rem);
}
.feature-row {
@include equal-flex-items(3, 768px, 1.5rem);
}
.layout {
@include priority-sidebar(280px, 65%, 2rem);
}
Example: Grid template area reorganization
// Responsive grid areas
@mixin responsive-areas(
$desktop-areas,
$desktop-cols,
$desktop-rows,
$tablet-areas: null,
$tablet-cols: null,
$tablet-rows: null,
$mobile-areas: null,
$gap: 1rem
) {
display: grid;
gap: $gap;
// Desktop (default)
grid-template-columns: $desktop-cols;
grid-template-rows: $desktop-rows;
grid-template-areas: $desktop-areas;
// Tablet
@if $tablet-areas {
@media (max-width: 1024px) {
grid-template-columns: $tablet-cols;
grid-template-rows: $tablet-rows;
grid-template-areas: $tablet-areas;
}
}
// Mobile
@if $mobile-areas {
@media (max-width: 768px) {
grid-template-columns: 1fr;
grid-template-areas: $mobile-areas;
}
}
}
// Dashboard layout example
.dashboard {
@include responsive-areas(
// Desktop: 3 columns
$desktop-areas:
"header header header"
"nav main aside"
"nav main aside"
"footer footer footer",
$desktop-cols: 200px 1fr 250px,
$desktop-rows: auto 1fr auto auto,
// Tablet: 2 columns
$tablet-areas:
"header header"
"nav main"
"nav main"
"footer footer",
$tablet-cols: 180px 1fr,
$tablet-rows: auto 1fr auto auto,
// Mobile: 1 column
$mobile-areas:
"header"
"main"
"footer",
$gap: 1.5rem
);
.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
// Hide aside on tablet and mobile
@media (max-width: 1024px) {
.aside { display: none; }
}
// Hide nav on mobile
@media (max-width: 768px) {
.nav { display: none; }
}
}
5. CSS Subgrid and Advanced Grid Features
| Feature | Syntax | Browser Support | Use Case |
|---|---|---|---|
| Subgrid | grid-template: subgrid |
Modern browsers Modern | Nested grids aligned to parent |
| Grid Auto-flow | grid-auto-flow: dense |
All modern Good | Fill gaps automatically |
| Min/Max Content | min-content, max-content |
All modern Good | Intrinsic sizing |
| Fit-content | fit-content(max) |
All modern Good | Clamp to content size |
| Minmax | minmax(min, max) |
All modern Good | Flexible sizing with bounds |
Example: CSS Subgrid implementation
// Subgrid for aligned nested content
@mixin card-grid-subgrid($columns: 3, $gap: 1rem) {
display: grid;
grid-template-columns: repeat($columns, 1fr);
gap: $gap;
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3; // header, content, footer
.card-header { grid-row: 1; }
.card-content { grid-row: 2; }
.card-footer { grid-row: 3; }
}
}
// Subgrid with fallback
@mixin subgrid-columns($fallback-template: 1fr) {
display: grid;
// Fallback for browsers without subgrid
grid-template-columns: $fallback-template;
// Subgrid for supported browsers
@supports (grid-template-columns: subgrid) {
grid-template-columns: subgrid;
}
}
// Example usage
.product-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-auto-rows: auto auto auto;
gap: 2rem;
.product {
display: grid;
grid-row: span 3;
@supports (grid-template-rows: subgrid) {
grid-template-rows: subgrid;
// All product images align
.product-image { grid-row: 1; }
// All titles align
.product-title { grid-row: 2; }
// All prices align
.product-price { grid-row: 3; }
}
// Fallback
@supports not (grid-template-rows: subgrid) {
grid-template-rows: auto 1fr auto;
}
}
}
Example: Advanced grid techniques
// Dense packing with auto-flow
@mixin masonry-grid($columns: 4, $gap: 1rem) {
display: grid;
grid-template-columns: repeat($columns, 1fr);
grid-auto-rows: 10px; // Small row size
grid-auto-flow: dense; // Fill gaps
gap: $gap;
> * {
// Items span based on content height
grid-row: span var(--row-span, 10);
}
}
// Intrinsic sizing with min/max-content
@mixin intrinsic-columns {
display: grid;
grid-template-columns:
min-content // Smallest possible
max-content // Largest needed
fit-content(300px) // Clamp at 300px
1fr; // Flexible
gap: 1rem;
}
// Complex minmax patterns
@mixin flexible-grid(
$min: 200px,
$max: 1fr,
$count: auto-fit
) {
display: grid;
grid-template-columns: repeat(
$count,
minmax(min($min, 100%), $max)
);
gap: 1rem;
}
// Grid with auto-placement and spanning
@mixin featured-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-auto-rows: 200px;
gap: 1rem;
// Featured items span 2x2
.featured {
grid-column: span 2;
grid-row: span 2;
}
// Wide items span 2 columns
.wide {
grid-column: span 2;
}
// Tall items span 2 rows
.tall {
grid-row: span 2;
}
}
// Named lines for precise control
@mixin grid-with-named-lines {
display: grid;
grid-template-columns:
[full-start] 1fr
[content-start] minmax(0, 1200px)
[content-end] 1fr
[full-end];
// Full-width items
.full-width {
grid-column: full;
}
// Content-constrained items
.content {
grid-column: content;
}
}
// Usage
.gallery {
@include masonry-grid(4, 1.5rem);
}
.pinterest-layout {
@include featured-grid;
}
.page-wrapper {
@include grid-with-named-lines;
}
Example: Complex grid patterns
// Asymmetric grid layout
@mixin asymmetric-grid {
display: grid;
grid-template-columns:
2fr // Main content (larger)
1fr; // Sidebar (smaller)
grid-template-rows:
auto // Header
1fr // Content (flexible)
auto; // Footer
gap: 2rem;
min-height: 100vh;
}
// Magazine-style grid
@mixin magazine-layout {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-auto-rows: 100px;
gap: 1rem;
.hero {
grid-column: 1 / span 8;
grid-row: 1 / span 3;
}
.featured {
grid-column: 9 / span 4;
grid-row: 1 / span 2;
}
.sidebar {
grid-column: 9 / span 4;
grid-row: 3 / span 1;
}
.articles {
grid-column: 1 / span 8;
grid-row: 4 / span 2;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
}
// Overlapping grid items
@mixin overlap-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: repeat(4, 100px);
.background {
grid-column: 1 / -1;
grid-row: 1 / -1;
z-index: 0;
}
.content {
grid-column: 2 / 6;
grid-row: 2 / 4;
z-index: 1;
}
}
// Grid with implicit tracks
@mixin auto-grid-rows($min-height: 200px) {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-auto-rows: minmax($min-height, auto);
gap: 1rem;
}
6. Container Queries and Intrinsic Layouts
| Feature | Syntax | Benefit | Use Case |
|---|---|---|---|
| Container Type | container-type: inline-size |
Component-aware | Reusable components |
| Container Query | @container (min-width: 400px) |
Context-based styling | Adaptive cards |
| Named Containers | container-name: sidebar |
Specific targeting | Multiple containers |
| Container Units | cqw, cqh, cqi, cqb |
Relative to container | Fluid sizing |
| Intrinsic Sizing | width: fit-content |
Content-based size | Dynamic layouts |
Example: Container query patterns
// Basic container setup
@mixin container($name: null, $type: inline-size) {
container-type: $type;
@if $name {
container-name: $name;
}
}
// Responsive card with container queries
@mixin responsive-card {
@include container(card);
.card-content {
display: flex;
flex-direction: column;
gap: 1rem;
}
// When container is wide enough, use row layout
@container (min-width: 400px) {
.card-content {
flex-direction: row;
align-items: center;
}
.card-image {
width: 40%;
}
.card-text {
width: 60%;
}
}
// Even wider, use different layout
@container (min-width: 600px) {
.card-content {
display: grid;
grid-template-columns: 200px 1fr;
gap: 2rem;
}
}
}
// Named container queries
.sidebar {
@include container(sidebar, inline-size);
.widget {
// Query specific container
@container sidebar (min-width: 300px) {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
}
// Container query units
.adaptive-text {
@include container;
h2 {
// Font size relative to container width
font-size: clamp(1.5rem, 5cqw, 3rem);
}
.description {
// Padding relative to container
padding: 2cqi; // 2% of inline size
}
}
Example: Container query component library
// Mixin for container-aware components
@mixin container-component($name, $breakpoints) {
container-name: $name;
container-type: inline-size;
@each $size, $width in $breakpoints {
@container #{$name} (min-width: #{$width}) {
@content($size);
}
}
}
// Usage
.product-card {
@include container-component(
product,
(small: 300px, medium: 500px, large: 700px)
) using ($size) {
@if $size == small {
.product-image {
aspect-ratio: 1;
}
} @else if $size == medium {
display: grid;
grid-template-columns: 200px 1fr;
.product-image {
aspect-ratio: 3/4;
}
} @else if $size == large {
grid-template-columns: 300px 1fr 200px;
.product-actions {
display: block;
}
}
}
}
// Container query with fallback
@mixin container-with-fallback($width) {
// Fallback using media query
@media (min-width: $width) {
@content;
}
// Progressive enhancement with container query
@supports (container-type: inline-size) {
@media (min-width: 0) {
@content; // Reset media query
}
@container (min-width: $width) {
@content;
}
}
}
// Container-aware grid
@mixin container-grid {
container-type: inline-size;
display: grid;
gap: 1rem;
// Compact layout (default)
grid-template-columns: 1fr;
// Medium container
@container (min-width: 400px) {
grid-template-columns: repeat(2, 1fr);
}
// Large container
@container (min-width: 700px) {
grid-template-columns: repeat(3, 1fr);
}
// Extra large container
@container (min-width: 1000px) {
grid-template-columns: repeat(4, 1fr);
}
}
Example: Intrinsic sizing patterns
// Intrinsic centering
@mixin intrinsic-center($max-width: none) {
width: fit-content;
margin-inline: auto;
@if $max-width != none {
max-width: $max-width;
}
}
// Intrinsic sidebar
@mixin intrinsic-sidebar(
$sidebar-min: 200px,
$content-min: 60%
) {
display: flex;
flex-wrap: wrap;
gap: 1rem;
.sidebar {
flex-basis: $sidebar-min;
flex-grow: 1;
}
.content {
flex-basis: 0;
flex-grow: 999;
min-width: $content-min;
}
}
// Quantity queries (style based on item count)
@mixin quantity-query($min, $max: null) {
@if $max {
// Between min and max items
&:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}),
&:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}) ~ & {
@content;
}
} @else {
// At least min items
&:nth-last-child(n + #{$min}),
&:nth-last-child(n + #{$min}) ~ & {
@content;
}
}
}
// Auto-sizing grid
@mixin auto-size-grid($min: 250px) {
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(min($min, 100%), 1fr)
);
gap: 1rem;
// Items adjust based on available space
> * {
width: 100%;
height: 100%;
}
}
// Usage
.centered-form {
@include intrinsic-center(600px);
}
.layout {
@include intrinsic-sidebar(280px, 65%);
}
// Style differently based on number of items
.nav-item {
@include quantity-query(5) {
// When 5+ items, reduce font size
font-size: 0.875rem;
}
}
.photo-grid {
@include auto-size-grid(300px);
}
Grid and Flexbox Integration Summary
- Grid for 2D layouts: Use CSS Grid for complex, two-dimensional layouts
- Flex for 1D layouts: Use Flexbox for one-dimensional, flexible content flow
- Auto-fit/fill: Create responsive grids without media queries
- Subgrid: Align nested grid items to parent grid (modern browsers)
- Container queries: Style components based on their container size, not viewport
- Layout mixins: Stack, Cluster, Sidebar patterns for common layouts
- Intrinsic sizing: Use fit-content, min-content for content-aware layouts
- Combine techniques: Grid + Flex together for optimal layouts
Note: Container queries with
@container enable component-level responsiveness, making components truly reusable regardless of where
they're placed. Always set container-type on the parent element.