CSCI 4513
Week 2, Lecture 3
Poor planning nearly cost the gods everything, just as CSS Grid requires careful specification before implementation.
The Tale:
After a devastating war, Asgard's walls lay in ruins. A mysterious builder offered to construct an impenetrable wall in three seasons for the sun, moon, and goddess Freyja. The gods agreed, confident the task was impossible, setting one constraint: the builder must work alone. They allowed him his horse Svadilfari—not realizing this concession's power.
The builder worked with astonishing efficiency. As winter ended, the gods realized in horror that the wall was nearly complete. They had failed to properly scope the project and were about to lose everything. Loki desperately lured Svadilfari away, disrupting work just enough that the builder missed his deadline. The lesson remained: inadequate planning nearly cost the gods everything.
/* Proper planning prevents problems */
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
Click each card to reveal thoughts!
The gods allowed the builder his horse without understanding its power. What CSS Grid features have you used without fully understanding them?
Consider: Have you copy-pasted Grid code that "just works"? Do you understand auto-fit vs auto-fill? What about implicit vs explicit grid? Like the builder's horse, powerful features can surprise you if you don't understand their full capabilities.
What requirements should you define before starting a grid layout?
Consider: How many columns/rows do you need? Which screen sizes must you support? Should items reflow or resize? What's your minimum/maximum width? Planning prevents the "nearly done but broken" situation the gods faced.
The wall was nearly complete but broke at the deadline—like layouts that work on desktop but break on mobile. How can you prevent this?
Consider: Test on mobile from day one, not day 99. Use responsive units (fr, %, minmax) instead of fixed pixels. Use auto-fit/auto-fill for automatic wrapping. DevTools device emulation catches problems early.
Before we dive into theory, let's visualize Grid in action!
This will feel foreign—that's okay! Hands-on exploration is the fastest way to build intuition about how Grid works.
CSS Grid is a two-dimensional layout system designed for precise placement of items in both rows AND columns simultaneously.
<div class="container">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
</div>
.container {
display: grid;
/* or display: inline-grid; */
}
/* Define 3 columns and 2 rows */
.container {
display: grid;
grid-template-columns: 50px 50px 50px;
grid-template-rows: 50px 50px;
}
/* Shorthand: rows / columns */
.container {
display: grid;
grid-template: 50px 50px / 50px 50px 50px;
}
/* Different sizes for each column */
.container {
grid-template-columns: 250px 50px 50px;
}
The dividing lines between rows and columns. Numbered from 1.
The space between two grid lines (a single row or column).
The space where a row and column intersect (like a spreadsheet cell).
Any rectangular section of the grid (one or more cells).
.container {
display: grid;
grid-template-columns: 50px 50px;
grid-template-rows: 50px 50px;
/* Only defines 2x2 grid (4 items) */
}
What if we have 5 items?
grid-auto-rows and grid-auto-columns.container {
grid-auto-rows: 50px; /* New rows match explicit rows */
}
Let's practice positioning and spanning!
/* Separate row and column gaps */
.container {
display: grid;
grid-template: 50px 50px / 50px 50px;
row-gap: 20px;
column-gap: 10px;
}
/* Shorthand: row-gap column-gap */
.container {
gap: 20px 10px;
}
/* Same gap for rows and columns */
.container {
gap: 1rem;
}
/* Make item span multiple columns */
.item {
grid-column-start: 1;
grid-column-end: 3; /* Spans columns 1-2 */
}
/* Make item span multiple rows */
.item {
grid-row-start: 1;
grid-row-end: 3; /* Spans rows 1-2 */
}
/* Shorthand: start / end */
.item {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
/* row-start / col-start / row-end / col-end */
.item {
grid-area: 1 / 1 / 3 / 3;
}
/* Give item a name */
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
/* Use names in template */
.container {
grid-template-areas:
"header header"
"sidebar content"
"sidebar content";
}
.container {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: 100px 1fr 100px;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
Use . to indicate empty cells:
grid-template-areas:
"header header header"
". content ."
"footer footer footer";
/* Instead of this tedious approach... */
.container {
grid-template-columns: 150px 150px 150px 150px 150px;
}
/* Use repeat() */
.container {
grid-template-columns: repeat(5, 150px);
}
/* Can mix different sizes */
.container {
grid-template-columns: repeat(2, 2fr) repeat(3, 1fr);
/* First 2 columns = 2fr, last 3 columns = 1fr */
}
fr distributes remaining space proportionally.
/* Equal columns */
.container {
grid-template-columns: 1fr 1fr 1fr 1fr;
/* Each column gets 1/4 of available space */
}
/* Unequal distribution */
.container {
grid-template-columns: 2fr 1fr 1fr;
/* First column gets 2/4, others get 1/4 each */
}
/* Mix static and dynamic */
.container {
grid-template-columns: 200px 1fr 1fr;
/* First column = 200px, rest split remaining */
}
Time to master grid areas and ordering!
/* min() returns smallest value */
.container {
grid-template-rows: min(100px, 50%);
/* Whichever is smaller: 100px or 50% of container */
}
/* max() returns largest value */
.container {
grid-template-columns: max(120px, 15%);
/* Whichever is larger: 120px or 15% of container */
}
minmax(min, max) - Grid-specific function for setting track size boundaries.
/* Columns between 150px and 200px */
.container {
grid-template-columns: repeat(5, minmax(150px, 200px));
}
/* Minimum width with flexible growth */
.container {
grid-template-columns: minmax(200px, 1fr) minmax(300px, 2fr);
}
Tracks grow/shrink between min and max values as container resizes.
/* clamp(minimum, ideal, maximum) */
.container {
grid-template-columns: repeat(5, clamp(150px, 20%, 200px));
/* Each column tries to be 20% width */
/* But never smaller than 150px */
/* And never larger than 200px */
}
/* Responsive columns without media queries! */
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
repeat(auto-fit,
minmax(200px, 1fr)
)
Collapses empty tracks. Items expand to fill container.
repeat(auto-fill,
minmax(200px, 1fr)
)
Keeps empty tracks. Items stay at minimum size.
In most cases, auto-fit is what you want for responsive layouts.
Advanced challenges ahead!
/* Grid for overall page layout */
.page {
display: grid;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
}
/* Flex for items within grid cells */
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
.sidebar nav {
display: flex;
flex-direction: column;
gap: 1rem;
}
Grid items can be flex containers! Use the best tool for each job.
Build a full admin dashboard layout using CSS Grid. This project will test everything you've learned about Grid!
Finish strong—complete the final levels!
📅 Next Class: JS Objects and Constructors
📝 Homework: Admin Dashboard