Beyond Basic Grids
You've mastered the fundamentals. Now let's tackle advanced patterns that solve real-world layout challenges. We'll use SCSS to make these complex layouts maintainable and reusable.
💡 Level Up:
These patterns appear in production apps daily. Learning to build them with SCSS will make you a valuable team member on any web project.
Pattern 1: Masonry Grid
The Pinterest-style masonry layout where items have different heights:
// Masonry configuration
$masonry-columns: 4;
$masonry-gap: 16px;
@mixin masonry-grid($cols: $masonry-columns, $gap: $masonry-gap) {
display: grid;
grid-template-columns: repeat($cols, 1fr);
grid-auto-rows: 10px; // Small row height for granular control
gap: $gap;
// Make items span the rows they need
> * {
// Calculate how many rows based on content height
// This would be set per item or via JavaScript
}
}
// Responsive masonry
.masonry {
@include masonry-grid(2, 12px);
@media (min-width: 768px) {
@include masonry-grid(3, 16px);
}
@media (min-width: 1024px) {
@include masonry-grid(4, 20px);
}
}
// Item spanning mixin
@mixin masonry-item($row-span) {
grid-row: span $row-span;
}
Pattern 2: Dashboard Layout
Complex dashboard with repositionable widgets:
// Dashboard grid system
$dashboard-cols: 12;
$dashboard-rows: 12;
$dashboard-gap: 16px;
@mixin dashboard-container {
display: grid;
grid-template-columns: repeat($dashboard-cols, 1fr);
grid-template-rows: repeat($dashboard-rows, minmax(80px, auto));
gap: $dashboard-gap;
padding: $dashboard-gap;
min-height: 100vh;
}
// Widget positioning mixin
@mixin widget($col-start, $col-span, $row-start, $row-span) {
grid-column: $col-start / span $col-span;
grid-row: $row-start / span $row-span;
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
// Usage
.dashboard {
@include dashboard-container;
.widget-stats {
@include widget(1, 3, 1, 2);
}
.widget-chart {
@include widget(4, 6, 1, 4);
}
.widget-activity {
@include widget(10, 3, 1, 6);
}
.widget-table {
@include widget(1, 9, 3, 8);
}
}
Pattern 3: Magazine Layout
// Magazine-style asymmetric grid
@mixin magazine-layout {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: repeat(4, minmax(200px, auto));
gap: 20px;
.feature {
grid-column: 1 / 5; // Spans 4 columns
grid-row: 1 / 3; // Spans 2 rows
}
.sidebar-1 {
grid-column: 5 / 7; // Last 2 columns
grid-row: 1 / 2;
}
.sidebar-2 {
grid-column: 5 / 7;
grid-row: 2 / 3;
}
.article {
grid-column: span 2; // Each article spans 2 columns
grid-row: span 1;
}
}
.magazine {
@include magazine-layout;
@media (max-width: 768px) {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
.feature,
.sidebar-1,
.sidebar-2,
.article {
grid-column: 1;
grid-row: auto;
}
}
}
Pattern 4: Card Gallery with Auto-Fit
// Responsive card gallery that auto-fits
$card-min-width: 280px;
$card-max-width: 1fr;
@mixin auto-grid($min: $card-min-width, $max: $card-max-width, $gap: 24px) {
display: grid;
grid-template-columns: repeat(auto-fit, minmax($min, $max));
gap: $gap;
}
// Different gallery types
.gallery-compact {
@include auto-grid(200px, 1fr, 16px);
}
.gallery-normal {
@include auto-grid(280px, 1fr, 24px);
}
.gallery-spacious {
@include auto-grid(350px, 1fr, 32px);
}
// Cards that span multiple columns when space allows
.featured-card {
@media (min-width: 768px) {
grid-column: span 2;
}
}
✅ Pro Pattern:
Use auto-fit for galleries where empty space should collapse,
and auto-fill when you want to maintain empty columns.
Pattern 5: Split Screen Layout
// Full-height split layouts
@mixin split-screen($left-width: 1fr, $right-width: 1fr, $gap: 0) {
display: grid;
grid-template-columns: $left-width $right-width;
gap: $gap;
min-height: 100vh;
}
// Common split patterns
.split-50-50 {
@include split-screen(1fr, 1fr);
}
.split-60-40 {
@include split-screen(3fr, 2fr);
}
.split-sidebar {
@include split-screen(300px, 1fr, 24px);
@media (max-width: 768px) {
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
}
}
Pattern 6: Grid Template Areas
// Named area layouts
@mixin app-layout {
display: grid;
grid-template-areas:
"sidebar header header"
"sidebar content aside"
"sidebar footer footer";
grid-template-columns: 250px 1fr 300px;
grid-template-rows: 60px 1fr 80px;
gap: 16px;
min-height: 100vh;
@media (max-width: 1024px) {
grid-template-areas:
"header"
"content"
"aside"
"footer";
grid-template-columns: 1fr;
grid-template-rows: 60px 1fr auto 80px;
.sidebar {
display: none;
}
}
}
.app {
@include app-layout;
.sidebar { grid-area: sidebar; }
.header { grid-area: header; }
.content { grid-area: content; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
}
Pattern 7: Overlapping Grid Items
// Create overlapping effects
@mixin overlap-grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: repeat(6, 100px);
.layer-back {
grid-column: 1 / 8;
grid-row: 1 / 4;
z-index: 1;
}
.layer-front {
grid-column: 6 / 13;
grid-row: 2 / 6;
z-index: 2;
}
}
// Hero section with overlapping image and text
.hero-overlap {
@include overlap-grid;
.hero-image {
grid-column: 1 / 9;
grid-row: 1 / 7;
z-index: 1;
}
.hero-text {
grid-column: 7 / 13;
grid-row: 3 / 6;
z-index: 2;
background: rgba(255, 255, 255, 0.95);
padding: 40px;
}
}
Pattern 8: Asymmetric Blog Layout
// Blog with varying post sizes
@mixin blog-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-auto-rows: 250px;
gap: 20px;
.post-large {
grid-row: span 2;
grid-column: span 2;
@media (max-width: 768px) {
grid-column: span 1;
grid-row: span 1;
}
}
.post-tall {
grid-row: span 2;
}
.post-wide {
grid-column: span 2;
@media (max-width: 768px) {
grid-column: span 1;
}
}
}
.blog {
@include blog-grid;
}
Combining Patterns
// Real-world example combining multiple patterns
.portfolio {
// Outer container
@include split-screen(300px, 1fr, 32px);
.portfolio-nav {
// Left sidebar stays fixed
position: sticky;
top: 0;
height: 100vh;
}
.portfolio-main {
// Right side uses masonry
@include masonry-grid(3, 20px);
@media (max-width: 1024px) {
@include masonry-grid(2, 16px);
}
}
}
🎨 Design Tip:
Complex grids work best with generous whitespace. Don't be afraid of 24-32px gaps - they help users understand the structure.