Beyond Basic Grids
You have mastered the fundamentals. Now let's tackle advanced patterns that solve real-world layout challenges. We will 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. Do not be afraid of 24-32px gaps,
they help users understand the structure.