Grid without the rewrite

CSS Grid entered J05N as a progressive capability layer, improving an old reporting route without making browser support or redesign one synchronized event.

CSS Grid made T04P's oldest reporting route look easy to replace.

The route used nested floats, clearfix utilities, negative margins, and widths that made sense only if you remembered three previous layouts. A summary panel sat beside filters. A report table occupied the remaining width. Supporting notes tried to clear both columns. At intermediate sizes, the pieces wrapped according to float mechanics rather than content priority.

In a browser with the newer Grid implementation, the relationship fit into a small block of CSS: named areas, a constrained filter column, one flexible report track, and a gap. The code looked so much better that it invited a larger conclusion. I could use Grid as the reason to redesign the route, replace its markup, and delete the fallback in one change.

J05N had made me suspicious of destinations without migration paths.

New layout capability and new product structure were separate changes. Combining them would make a failure impossible to classify: was the source order wrong, the new design misunderstood, the Grid code incomplete, or an older browser simply outside the assumed support?

I decided to introduce Grid as an enhancement to the existing reporting task. The baseline document would become coherent first. The enhanced layout would apply only where the browser proved the necessary capability. A later redesign, if the report earned one, would have to justify itself independently.

2017 changed the practical question

Grid had existed in specifications and experimental implementations for years. In early 2017, the situation shifted quickly. The CSS Grid Layout Level 1 specification was in Candidate Recommendation, and Firefox 52, Chrome 57, and Safari 10.1 shipped modern unprefixed implementations during March. The updated Edge implementation was arriving with EdgeHTML 16 in the Windows 10 Fall Creators Update.

The question was no longer whether Grid would ever be useful. It was which users and browsers could rely on the interoperable model now, and what everyone else would receive.

My support matrix still included Internet Explorer 11 and older application browsers. IE exposed an earlier prefixed grid model with different placement and sizing behavior. Treating -ms-grid as a simple prefix for the current specification would be inaccurate and expensive. A complete translation would maintain two layout programs.

The route already had a valid one-column possibility. That gave me a better fallback than counterfeit parity.

The migration policy became:

all supported browsers: meaningful source order and complete vertical flow
modern Grid support: two-dimensional enhancement
older prefixed Grid: receive baseline, not a parallel implementation

This was not minimum effort disguised as progressive enhancement. It was an explicit statement of which product qualities had to remain equivalent and which visual arrangement could vary by capability.

The old markup had been arranged for floats. A filter sidebar appeared first because floating it left made the rest of the layout convenient. In the visible desktop arrangement, the report title appeared at the top of the main column. In source order, keyboard and screen-reader users encountered the filters before learning which report they controlled.

Grid can place elements independently of document order, which can tempt an author to preserve bad markup and repair only the picture. I used the opposite sequence.

The source order became:

  1. Report title and current scope.
  2. Summary of the current result.
  3. Filters that can change the result.
  4. The report table.
  5. Notes explaining calculation and freshness.

With styles removed, that sequence described the task. A user learned the subject, received the current state, encountered controls, read results, then reached supporting details.

The Grid layout could place summary and filters in a narrow side track while keeping their source positions meaningful. I did not use CSS order or explicit placement to create a visual sequence that contradicted keyboard focus. Grid's placement power was reserved for spatial relationship, not information repair.

This change improved every browser before one Grid declaration shipped.

The baseline was an actual layout

“Fallback” can imply an emergency rendering left over after the real design. J05N called it the baseline because it was complete and intentional.

The reporting route flowed vertically. Sections used ordinary block layout. The filters appeared in a fieldset with clear grouping. The table occupied its own horizontal overflow region on narrow screens rather than widening the page. Spacing came from parent stack rules instead of margins embedded in each component.

.reportLayout > * + * {
  margin-top: 1.5rem;
}
 
.reportTableViewport {
  max-width: 100%;
  overflow-x: auto;
}

The baseline did not attempt a two-column desktop arrangement through floats or an elaborate Flexbox substitute. It preserved:

  • Access to every content section and action.
  • Logical reading and focus order.
  • Legible labels, controls, table headers, and notes.
  • Visible focus and error state.
  • A stable route at narrow and zoomed widths.

Compact side-by-side placement was not in that list. Older browsers displayed a longer page, not a broken one.

This distinction was the foundation of the migration. If the baseline had been treated as temporary ugliness, every review would pressure me to reproduce Grid with old techniques and restore the maintenance burden.

The capability layer named its requirement

The enhanced rules lived inside a feature query:

@supports (display: grid) {
  .reportLayout {
    display: grid;
    grid-template-columns: minmax(14rem, 18rem) minmax(0, 1fr);
    grid-template-areas:
      "summary report"
      "filters report"
      ".       notes";
    grid-column-gap: 1.5rem;
    grid-row-gap: 1.5rem;
  }
 
  .reportSummary { grid-area: summary; }
  .reportFilters { grid-area: filters; }
  .reportBody { grid-area: report; }
  .reportNotes { grid-area: notes; }
}

In October 2017, the grid-*-gap property names matched the interoperable Grid model I was targeting. I did not write the later generic gap shorthand backward into the example.

Capability detection described the feature required by the CSS. It avoided a browser-name table embedded in application logic. Browsers that did not understand @supports ignored the entire block and retained the baseline.

The query was not proof that every Grid detail was bug-free. It established the broad boundary. Browser fixtures and real content still tested track sizing, overflow, and placement.

I resisted querying every individual declaration. A forest of nested feature tests would be harder to understand than one carefully chosen enhancement using the stable core shared by the target implementations.

The code stated both the dependency and the fallback in one place.

minmax(0, 1fr) solved a real overflow

The first enhanced version used:

grid-template-columns: 18rem 1fr;

A table with a long unbroken identifier widened the flexible track beyond the container. The page gained horizontal scrolling even though the table wrapper was supposed to own overflow.

The surprise came from Grid's automatic minimum sizing. A flexible track does not necessarily shrink below the minimum contribution of its content. 1fr means a share of free space; it does not unconditionally mean “fit inside whatever remains.”

Changing the report track to minmax(0, 1fr) allowed it to shrink to the available width. The table viewport then handled its own overflow as intended.

grid-template-columns: minmax(14rem, 18rem) minmax(0, 1fr);

This one detail fixed the symptom and clarified ownership:

page grid owns column allocation
report region may shrink within its track
table viewport owns overflow of wide tabular content
table preserves its readable minimum structure

Setting min-width: 0 on the grid item provided a useful defensive equivalent where nested component styles still imposed automatic minimum behavior.

The incident showed why a clean Grid demo was insufficient. Real content, especially intrinsic sizes, participates in track calculation. The layout system was expressive, not magical.

Grid exposed old component assumptions

Several J05N components carried layout decisions from their original pages.

The summary panel included a right margin because it had always been a floated sidebar. The filter form set a fixed width. A chart calculated its canvas from an assumed 280-pixel column. The report table wrapper applied a minimum width to its parent rather than to its own scroll region.

Inside Grid, those assumptions combined with track sizing and produced doubled gaps, overflow, and clipped charts.

I applied an ownership rule:

layout container places siblings
component manages internal composition
content component observes its available container

External margins left the components. The Grid container's row and column gaps owned separation. The filter form filled its track without declaring the track size. The chart measured its actual container after layout and redrew when that container changed. The table kept its wide content inside a local scroll viewport.

These changes improved baseline composition too. The components became less coupled to the float page and easier to use in other stacks.

Grid was an architectural test because it changed which layer visibly won layout conflicts. The feature did not create the old ownership mistakes; it made them impossible to ignore.

Named areas documented relationships

Explicit line numbers could have expressed the layout:

.reportSummary { grid-column: 1; grid-row: 1; }

Named areas made the intended composition easier to review. The template showed the side rail and report relationship as a small map. Component rules named their role rather than repeating coordinates.

The names remained page-specific. J05N did not export universal sidebar, main, and footer areas. A reporting route understood summary, filters, report, and notes; another application could have entirely different content relationships.

The design-system layer provided principles and a narrow layout helper only after multiple routes shared the same contract. The first Grid experiment stayed local so it could change without becoming a package promise.

Named areas also made responsive changes legible. At a narrower enhanced width, the template could become:

grid-template-areas:
  "summary"
  "filters"
  "report"
  "notes";
grid-template-columns: minmax(0, 1fr);

That arrangement matched source order, which prevented a visual breakpoint from creating a new keyboard sequence.

The CSS became a readable statement of content relationships, not a generic grid abstraction designed before a second consumer existed.

Breakpoints came from content stress

The first visual tests used a wide desktop viewport and a narrow phone viewport. Both passed. At an intermediate width, long filter labels wrapped into four lines while the report column became too narrow to scan.

The failure belonged to neither named device. It came from the combined minimum useful widths of the side content, gap, and report.

I resized until the layout began to compromise reading, then placed the transition slightly before that point. The breakpoint was expressed in relative units so increased text size influenced the decision more naturally than a device pixel assumption.

@supports (display: grid) {
  @media (min-width: 64em) {
    /* two-track template */
  }
}

Below the threshold, even Grid-capable browsers received the vertical template. Grid was still useful for explicit areas and gap, but not obligated to produce columns.

I tested with long labels, enlarged text, a wide table, empty summary data, and browser zoom. At 200 percent zoom, the effective layout width fell below the two-column condition and the route returned to one column without losing meaning.

A breakpoint is a content contract, not a census of popular hardware. The old float layout had accumulated device-oriented values. The Grid migration gave me a chance to replace them with observed stress points.

Grid's auto-placement could fill available cells densely and produce attractive arrangements from variable content. I avoided dense placement for the reporting route.

Reordering items visually to fill holes can make the painted sequence diverge from DOM and keyboard order. A keyboard user might move focus in source order while focus indicators jump unpredictably across columns. A screen-reader user would hear a sequence that no longer matched the visual reference someone else described.

The report used explicit named areas for major regions and natural source order within each region. Repeated summary facts used simple row flow. No focusable control depended on dense visual reordering.

This did not mean CSS visual placement was inherently inaccessible. It meant placement had to preserve a coherent relationship among document order, reading order, and interaction order. The route did not have a reason strong enough to make those differ.

Grid gave me more placement power than the product needed. Restraint kept the document model understandable.

The best use of a layout feature is not a demonstration of every available axis.

Internet Explorer received deliberate non-parity

Internet Explorer 11 had a prefixed grid implementation based on an older model. It supported explicit rows and columns but lacked the modern feature set and syntax I used. Supporting it through -ms-grid would require duplicate placement declarations and manual handling for repeated content.

The route's baseline already fulfilled the task. I documented the browser result:

IE11: vertical report flow, complete interaction
modern Grid browsers: enhanced side rail and report tracks

This required visual review on IE11, not merely trusting that ignored rules were safe. The browser needed the baseline stylesheet, table overflow, focus styles, form behavior, and application JavaScript to work. Progressive enhancement is not permission to stop testing the baseline consumer.

I found one problem: a selector inside the enhancement block had been the only rule removing an old float. IE ignored the block and retained the float from legacy CSS. The fix moved float removal into the baseline cleanup before Grid activated.

That incident reinforced the order. The baseline must stand on its own. Enhancement should add capability, not secretly repair damage left by the previous architecture.

Older browsers did not need a laborious imitation of Grid. They needed a maintained version of the reporting task.

@supports (display: grid) answered whether the browser recognized a modern declaration. It did not answer whether the application had tested that browser, whether a particular bug affected my content, or how long the fallback remained supported.

J05N kept a browser policy outside the stylesheet. It named baseline browsers, enhanced browsers, tested versions, and known limitations. The feature query implemented one capability decision inside that policy.

This avoided two opposite mistakes.

The first was user-agent detection, which would freeze assumptions about browser versions into code and miss capable or unusual engines. The second was assuming feature detection eliminated the need for compatibility research and testing.

A browser could parse Grid and still contain a track sizing bug triggered by my table. Another could support Grid while lacking a related JavaScript feature the route needed. Each layer used the narrowest capability check available and the application still tested complete tasks.

The policy also defined retirement. The baseline vertical layout remained useful even after older browsers left support because it served narrow widths, print, zoom, and failure modes. I would not delete it merely because the @supports branch became common.

Progressive layers can outlive the compatibility moment that first justified them.

The Grid change produced large screenshot differences by design. A tool that treated any pixel difference as failure would make progressive enhancement look like breakage.

I captured named scenarios for baseline and enhanced layouts. The baseline ran in an older browser fixture and at narrow width. The enhancement ran in modern browsers at the one- and two-column thresholds. Each snapshot stated which geometry it represented.

Review focused on invariants and intended differences:

  • Content and controls remained present in both.
  • Source and focus order stayed the same.
  • Table overflow belonged to its local viewport.
  • Enhanced columns aligned without overlap.
  • Long labels and notes wrapped without clipping.
  • Focus indicators remained visible against each surface.

Image diffs detected unexpected movement, but they did not decide whether two columns were better or whether the source order made sense. Keyboard and DOM assertions covered those contracts.

The baseline was not compared pixel-for-pixel with the enhanced view. Each was compared with its own approved behavior across later changes.

Visual testing became useful when it knew which rendering it was observing and stopped pretending all valid browsers should draw the same coordinates.

The reporting route was sometimes printed or saved as a PDF. The float layout produced clipped columns and separated notes from their report.

Rather than printing the screen Grid, the print stylesheet used the document's vertical flow. It removed interactive controls that had no printed purpose while preserving selected filter values as text. The report table could break according to print constraints, and notes followed it in source order.

Because the markup had already been reordered for meaning, the print version required little structural repair. Grid placement disappeared, and the baseline document remained.

This outcome changed how I thought about fallback. The unenhanced flow was not only for older browsers. It was the semantic foundation from which narrow screens, zoom, print, and partial capability could derive appropriate presentations.

A progressive architecture can produce several intentional outputs without naming one of them the real page and the others degraded copies.

The document carried the stable task. Media and capability layers expressed context.

The migration shipped in stages.

Stage one: semantic source order

Markup moved into a meaningful sequence. Old floats were adjusted so the existing visual layout remained acceptable. Keyboard and screen-reader review verified the improvement.

Stage two: baseline cleanup

Components lost external margins and fixed widths. The vertical flow became the explicit default. Table and chart ownership moved to their local containers.

Stage three: Grid enhancement

The feature query, named areas, tracks, and gap activated for capable browsers. Browser fixtures covered March-era modern implementations and the new Edge path.

Stage four: content-driven refinement

Intermediate width, zoom, long labels, and intrinsic-size failures adjusted breakpoints and track constraints.

Stage five: broader reuse review

Only after another route used similar patterns would J05N consider a shared grid composition. The first implementation remained page-specific evidence.

Each stage left a valid route and could be reverted independently. The source-order improvement did not depend on Grid shipping. The Grid layer did not depend on a new product design. Component cleanup benefited baseline and enhanced views.

This sequence made progress observable and reduced the pressure to solve every future layout before the first one shipped.

Once the Grid enhancement settled, the reporting route looked cleaner without changing its task. It also revealed that the summary repeated information already visible in the table and that several filters belonged closer to specific columns.

Those were product observations, not CSS requirements.

I documented them for a later reporting redesign. That project could reconsider information hierarchy, query state, and responsive table behavior with the current route as a stable baseline. It would not have to carry a browser-platform migration inside the same change.

Separating the work preserved causal evidence. I knew which improvements came from meaningful source order, which came from component ownership cleanup, which came from Grid placement, and which still required a product decision.

The new CSS feature had earned adoption without becoming an excuse to declare everything around it obsolete.

Progressive enhancement was a deployment strategy

I had previously used progressive enhancement mostly to discuss pages that remained usable without JavaScript. The Grid migration showed a broader value: it was a strategy for deploying platform change across browsers and interfaces that could not update in one synchronized moment.

The sequence was:

ship a valid semantic baseline
-> detect a specific additional capability
-> add a bounded improvement
-> observe real content and browsers
-> retain the baseline for contexts that still need it

This reduced technical risk because failure fell back to a maintained path. It reduced design risk because enhancement could be judged against an existing task rather than paired with a new one. It reduced maintenance risk because older engines did not receive a second complex layout implementation.

Capability layers did not mean every experience was visually identical. They meant the differences were intentional, documented, and proportional to what the environment could support.

Grid remained a tool, not an era boundary

The final route contained far less layout code than the float version. More importantly, its structure was easier to explain.

The document order carried meaning. The baseline provided a complete vertical task. Grid named the two-dimensional relationship for capable browsers. Tracks could shrink because intrinsic sizing was understood. Components owned their interiors while the page owned placement. Tests covered behavior at stress points rather than two named devices.

CSS Grid was a genuine breakthrough for web layout in 2017. It did not require treating everything built before it as a mistake or every browser without it as broken.

The web platform advances continuously. If each capability becomes a rewrite mandate, software remains in permanent migration and product changes become inseparable from technology fashion. If a capability enters through a deliberate layer, it can improve the places that benefit while stable foundations remain useful.

T04P still needs a deeper reporting redesign. That work should follow evidence about the reporting task. Grid has simply given its relationships a better language.

The next limitation is already visible: the reporting module can occupy a sidebar, a full page, or an embedded panel, while media queries know only the viewport. I expect layout rules to move closer to the component's actual containing space. Until CSS can express that reliably, J05N keeps those arrangements explicit and refuses to disguise window measurements as reusable component knowledge.

That was the result I wanted from J05N: not a modern-looking codebase, but an application able to absorb a better platform feature without losing the history, users, and constraints that existed the day before it shipped.