Why Does auto-fill Create Phantom Grid Columns?

Auto-fill phantom grid columns happen when CSS Grid reserves empty tracks, gaps, and column space even when there are not enough real items to fill the row.

CSS Grid Auto-Fill Fix

Why does auto-fill create phantom grid columns?

auto-fill creates phantom grid columns when the browser keeps empty tracks in the grid even though there are no real items inside them. That can leave visible gaps, make cards look squeezed, and create a strange sense that the layout is reserving space for invisible content.

This is not a browser bug. It is the main difference between auto-fill and auto-fit. auto-fill fills the row with as many tracks as can fit, including empty ones. auto-fit collapses empty tracks and lets the remaining items stretch. If you choose the wrong one, your grid can look like it has ghost columns.

  • CSS Grid
  • auto-fill
  • phantom columns
  • empty tracks

Compare auto-fill and auto-fit with only two cards

The fastest test is simple: keep the same grid, leave only two items, then switch auto-fill to auto-fit. If the phantom space disappears, the empty tracks were being preserved by auto-fill.

Related: Try this in the FrontFixer Live Inspector.

Open Live Inspector

What the bug looks like

A responsive card grid appears to reserve columns for missing items or leaves strange empty areas.

Why it happens

auto-fill keeps empty grid tracks instead of collapsing them like auto-fit.

What usually fixes it

Switch to auto-fit, cap track width, or use auto-fill only for intentional slot systems.

Why auto-fill can make invisible columns feel real

auto-fill tells CSS Grid to create as many tracks as can fit in the container. If the container can fit four tracks but you only have two real cards, the grid can still reserve the shape of those extra tracks. That is why the layout can look like it is saving room for cards that do not exist.

This behavior is useful in some designs. For example, a calendar, dashboard slot system, skeleton loading state, or reserved product shelf may need empty columns to remain part of the layout. In those cases, the “phantom” columns are not a bug. They are a feature.

But for normal article cards, product cards, feature cards, and related-post grids, phantom columns often look accidental. The reader sees a strange gap, not a clever grid algorithm. When the design should be content-driven, auto-fit is often the better default.

auto-fill preserves tracksEmpty columns can still affect the layout rhythm.
auto-fit collapses tracksExisting cards can expand after empty tracks disappear.
Phantom space is not always badIt is only bad when it looks accidental.
Better mindsetChoose grid behavior based on item count, not only screen width.
Error 1

Empty tracks stay reserved with only a few cards

The most common mistake is using auto-fill for a normal card grid where the existing cards should use the available space. With only a few cards, empty tracks stay reserved and the row looks like it contains invisible items.

Broken code

Empty tracks remain
.cards {
  display: grid;
  grid-template-columns:
    repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}

Broken visual result

Phantom slots reserved
phantom
Feature cards

The row keeps room for columns with no real cards.

Card A Card B Empty track
The empty track still shapes the row, so the section looks unfinished.

Correct code

Empty tracks collapse
.cards {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: 16px;
}

Fixed visual result

Existing cards fill space
collapsed
Feature cards

The empty tracks collapse and the two cards own the row.

Card A Card B
Use auto-fit when existing cards should expand into unused space.
Error 2

Phantom gaps make the row look misaligned

Phantom columns do not only reserve width. They can also preserve the visual rhythm of gaps. That is why a grid can look slightly shifted, squeezed, or oddly spaced even when the cards themselves are not overflowing.

Broken code

Gap belongs to phantom tracks
.product-grid {
  display: grid;
  grid-template-columns:
    repeat(auto-fill, minmax(180px, 1fr));
  gap: 24px;
}

Broken visual result

Gaps feel random
gap
Product row

Large gaps make the empty column feel visible.

A B Ghost
The spacing rhythm makes the phantom track feel like a missing card.

Correct code

Gap and behavior aligned
.product-grid {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(min(100%, 180px), 1fr));
  gap: clamp(12px, 3vw, 24px);
}

Fixed visual result

Spacing feels intentional
balanced
Product row

The grid uses available space without exposing ghost gaps.

A B C
If empty tracks are not part of the design, collapse them and scale the gap.
Error 3

Cards refuse to stretch because phantom tracks take space

A layout may look like the cards are too small even though the container has plenty of room. The missing detail is that the empty tracks still participate in the grid. The real cards are sharing space with phantom columns.

Broken code

Real cards share with ghosts
.cards {
  display: grid;
  grid-template-columns:
    repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}

Broken visual result

Cards stay too small
reserved
Card section

The real cards do not get all the available row width.

Real A B Ghost
The grid seems spacious, but empty tracks are still taking a share.

Correct code

Only real cards share
.cards {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 16px;
}

.cards > * {
  min-width: 0;
}

Fixed visual result

Real cards own the row
clean
Card section

The existing cards now share the available space.

Card A Card B
When the grid is content-driven, let empty tracks collapse.
Error 4

Using auto-fit when the design actually needs reserved slots

The opposite mistake can happen too. Some interfaces really do need empty slots to remain visible. If the design is a scheduler, seat map, dashboard placeholder, or loading skeleton, auto-fill may be the correct behavior.

Broken code

Slots collapse accidentally
.slot-grid {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(160px, 1fr));
  gap: 16px;
}

Broken visual result

Reserved rhythm disappears
collapsed
Schedule slots

The design expected empty slots to stay visible.

Booked Booked
For slot-based interfaces, collapsing empty tracks can remove important rhythm.

Correct code

Reserved slots intentional
.slot-grid {
  display: grid;
  grid-template-columns:
    repeat(auto-fill, minmax(160px, 1fr));
  gap: 16px;
}

.slot.is-empty {
  opacity: .45;
}

Fixed visual result

Slots stay visible
intentional
Schedule slots

Empty slots are visible because the design needs them.

Booked Booked Empty
Use auto-fill when the empty tracks communicate real future slots.
Premium pattern

A production-minded auto-fill pattern

A premium grid does not treat auto-fill as a random replacement for auto-fit. It uses auto-fill only when empty tracks are part of the interface. For content-driven card grids, it usually uses auto-fit instead.

Premium code

Choose by intent
/* Content-driven cards */
.card-grid {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: clamp(14px, 2vw, 24px);
}

/* Slot-based UI */
.slot-grid {
  display: grid;
  grid-template-columns:
    repeat(auto-fill, minmax(160px, 1fr));
  gap: 16px;
}

Premium visual result

Grid behavior matches intent
premium
Two grid modes

The card grid collapses empties. The slot grid preserves them.

Cards
Auto-fit fills real content only
Slots
Auto-fill keeps reserved rhythm
Premium CSS Grid chooses auto-fit or auto-fill based on whether empty tracks should collapse or stay meaningful.

Fast practical rule

If auto-fill creates phantom grid columns, ask whether the empty tracks are useful. If the grid is a normal card list, switch to auto-fit. If the grid is a slot-based interface, keep auto-fill and make the empty slots visually intentional.

Debug checklist

  • Check whether the grid uses repeat(auto-fill, minmax(...)).
  • Test the grid with only one or two items.
  • Look for empty tracks that still preserve width or gaps.
  • Switch temporarily from auto-fill to auto-fit and compare the result.
  • Decide whether empty columns should communicate real reserved slots.
  • Use auto-fit for normal content-driven card grids.
  • Use auto-fill for calendars, placeholders, skeletons, or slot systems.
  • Make reserved empty states visually intentional when they are part of the UI.
Best first moveReplace auto-fill with auto-fit and test the same item count.
Most common causeEmpty tracks are being preserved in a card grid that should collapse them.
Most sneaky causeThe gap between phantom tracks makes the missing columns feel visible.
Better mindsetAuto-fill is for reserved rhythm. Auto-fit is usually better for live content.

When phantom columns are actually useful

Phantom columns are not always a mistake. A booking calendar, empty dashboard panel, skeleton loading layout, or seat map may need those empty tracks to remain visible. In that context, the empty space is not “dead.” It communicates that the interface has reserved positions.

The problem is using that same behavior for regular content cards. A related-post grid, feature section, or product list usually should not look like it is missing invisible cards. Those layouts usually want the existing cards to control the space.

The authority move is to name the intent before choosing the keyword: content-driven grids usually want auto-fit; slot-driven grids can justify auto-fill.

Why this bug survives desktop review

This bug often hides during development because the demo content has the perfect number of cards. Six cards in a three-column layout look clean. Eight cards in a wide grid might also look fine. The phantom-column problem usually appears when filters, search results, or dynamic content leave only one or two items.

A strong review checks content states, not just breakpoints. Test one item, two items, many items, and empty loading states. That is the only way to know whether auto-fill is helping the interface or quietly creating ghosts.

The simplest mental model

Think of auto-fill as a grid that draws possible seats first, then places cards into some of those seats. Think of auto-fit as a grid that removes the empty seats and lets the occupied seats use the remaining space. Once you see that difference, the phantom column bug becomes much easier to diagnose.

Final takeaway

auto-fill creates phantom grid columns because it preserves empty tracks. That is useful when your interface needs reserved slots, but it can look broken when a normal card grid appears to be saving space for invisible items.

Use auto-fit when existing content should expand into available space. Use auto-fill when empty tracks are meaningful. The fix is not memorizing one keyword. The fix is matching the keyword to the layout’s real intent.

Want more fixes like this?

Browse more CSS Grid, responsive layout, overflow, and card grid debugging guides in the FrontFixer library.

Why Is My CSS Grid Not Equal Height?

CSS grid not equal height problems usually happen when grid items are not stretching, inner cards do not use height 100%, rows are being compared incorrectly, or card content is not arranged with a consistent internal layout.

CSS Grid Equal Height Fix

Why is my CSS grid not equal height?

CSS Grid can make columns line up beautifully, but equal-height cards still break when one card has more text, another has a taller image, or the grid item stretches while the card inside it does not. The fix depends on what “equal height” means: equal inside the same row, equal across all rows, or equal internal content alignment.

  • CSS Grid
  • equal height cards
  • align-items
  • grid-auto-rows

What the bug looks like

Cards in a grid look uneven, buttons sit at different levels, or shorter cards do not stretch to match taller cards.

Why it happens

The grid, grid item, card wrapper, and inner content layout are not all following the same height strategy.

What usually fixes it

Use stretch alignment, make the card fill the grid area, and use a flex column inside the card for consistent content alignment.

Error 1

align-items:start prevents equal height stretching

CSS Grid items stretch by default. But if the grid container uses align-items:start, each item keeps its own content height. That makes cards in the same row look uneven.

Broken code

Stretch disabled
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  align-items: start;
}

Broken visual result

Cards have different heights
uneven
Feature grid

The row does not stretch items to the same height.

Short card Longer card with more content and more height Medium card
align-items:start tells the grid items not to stretch vertically.

Correct code

Stretch items
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  align-items: stretch;
}

Fixed visual result

Cards stretch in the row
equal row
Feature grid

The grid items stretch to match the tallest item in the row.

Short card Longer card with more content and more height Medium card
For same-row equal height, let grid items stretch instead of aligning them at the start.
Error 2

The grid item is equal height, but the card inside is not

Sometimes the grid item is stretching correctly, but the visible card inside it still uses content height. In that case, make the card fill the grid item with height:100%.

Broken code

Inner card stays short
.grid {
  display: grid;
  align-items: stretch;
}

.card {
  /* visible card still uses content height */
}

Broken visual result

The wrapper stretches, not the card
inner issue
Card wrappers

The grid area may be equal, but the visible card does not fill it.

Short inner card Tall inner card with extra text Medium inner card
The equal-height grid area is invisible if the inner card does not fill it.

Correct code

Card fills grid item
.grid {
  display: grid;
  align-items: stretch;
}

.card {
  height: 100%;
}

Fixed visual result

Visible cards match
height 100%
Card wrappers

The visible card fills the grid area, so the row looks equal.

Short inner card Tall inner card with extra text Medium inner card
When a card is nested inside a grid item, make the visible card fill the available height.
Error 3

You expect all rows to have the same height

CSS Grid naturally equalizes items inside the same row. It does not always make every row in the whole grid the same height. If you want rows across the grid to match, use grid-auto-rows:1fr carefully.

Broken code

Rows use content height
.card-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: auto;
  gap: 16px;
}

Broken visual result

Rows are different heights
auto rows
Multi-row grid

Each row follows its own tallest content.

Short Short Much taller card with more content Medium
Different rows can have different heights because each row is sized by its own content.

Correct code

Equal implicit rows
.card-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  gap: 16px;
}

.card {
  height: 100%;
}

Fixed visual result

Rows share equal height
1fr rows
Multi-row grid

Implicit rows can share the available row height pattern.

Short Short Much taller card with more content Medium
Use grid-auto-rows:1fr only when equal row height is really the visual goal.
Error 4

The cards are equal height, but the content inside is not aligned

Sometimes the card heights are equal, but the CTAs, badges, or prices appear at different vertical positions. That is an internal card layout problem. Use a flex column inside the card and push the CTA to the bottom.

Broken code

Content stacks naturally
.card {
  height: 100%;
}

.card-button {
  /* button follows content */
}

Broken visual result

Buttons sit unevenly
inside uneven
Pricing grid

The card boxes match, but the internal buttons do not line up.

BasicChoose Pro plan with more details and longer descriptionChoose TeamChoose
Equal outer height does not automatically align internal content.

Correct code

Flex column card
.card {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.card-button {
  margin-top: auto;
}

Fixed visual result

Buttons align at bottom
aligned CTAs
Pricing grid

The card content uses a column layout, so CTAs line up.

BasicChoose Pro plan with more details and longer descriptionChoose TeamChoose
Use flex inside the grid card when you need internal elements to align consistently.
Premium pattern

A production-minded equal-height CSS Grid pattern

A strong equal-height card grid uses responsive tracks, stretch alignment, safe column sizing, cards that fill their grid area, and flex column content inside each card.

Premium code

Equal-height card system
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  grid-auto-rows: 1fr;
  align-items: stretch;
  gap: clamp(16px, 2vw, 24px);
}

.card-grid > * {
  min-width: 0;
}

.card {
  height: 100%;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.card-media {
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.card-content {
  display: flex;
  flex: 1;
  flex-direction: column;
}

.card-action {
  margin-top: auto;
}

Premium visual result

Equal height and aligned content
premium
Production card grid

The grid, cards, and inner content all follow the same height strategy.

StarterView Professional plan with longer detailsView TeamView
Premium equal-height grids do not rely on fake fixed heights. They use grid for rows and flex for internal card alignment.

Fast practical rule

If CSS grid is not equal height, check align-items first. Then make the visible card use height:100%. If the card content still looks uneven, use display:flex, flex-direction:column, and margin-top:auto for bottom-aligned CTAs.

Debug checklist

  • Check whether the grid has align-items:start, center, or another value that prevents stretching.
  • Use align-items:stretch when same-row equal height is desired.
  • If the visible card is nested inside the grid item, add height:100% to the card.
  • Use display:flex and flex-direction:column inside cards when buttons need to align at the bottom.
  • Use margin-top:auto for card CTAs that should sit at the same vertical level.
  • Use grid-auto-rows:1fr only when equal row height across multiple rows is actually needed.
  • Normalize image areas with aspect-ratio or consistent media height.
  • Keep responsive behavior in mind: equal-height desktop cards may stack naturally on mobile.
Best first moveRemove align-items:start and test whether the grid items stretch.
Most common causeThe grid item stretches, but the visible card inside does not use height:100%.
Most sneaky causeThe cards are equal height, but internal buttons or badges are not aligned.
Better mindsetGrid controls the outside. Flex often controls the inside of each card.

Final takeaway

A CSS grid not equal height problem is usually not solved by forcing a random fixed height. The real fix is to know which level needs equal height: the grid item, the visible card, the grid row, or the content inside the card.

Let grid stretch the outside, make the card fill the grid area, and use flex inside the card for aligned internal content. That gives you equal-height cards without fragile fixed-height hacks.

Want more fixes like this?

Browse more CSS Grid, card layout, and responsive debugging guides in the FrontFixer library.