惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
雷峰网
雷峰网
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Spread Privacy
Spread Privacy
H
Hacker News: Front Page
PCI Perspectives
PCI Perspectives
Webroot Blog
Webroot Blog
罗磊的独立博客
H
Heimdal Security Blog
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Last Week in AI
Last Week in AI
美团技术团队
Help Net Security
Help Net Security
The Hacker News
The Hacker News
C
Cisco Blogs
T
The Blog of Author Tim Ferriss
J
Java Code Geeks
The Register - Security
The Register - Security
IT之家
IT之家
WordPress大学
WordPress大学
Jina AI
Jina AI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
H
Help Net Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
NISL@THU
NISL@THU
爱范儿
爱范儿
The GitHub Blog
The GitHub Blog
Scott Helme
Scott Helme
V
Vulnerabilities – Threatpost
B
Blog
T
Tenable Blog
博客园 - 三生石上(FineUI控件)
T
The Exploit Database - CXSecurity.com
S
Security Affairs
小众软件
小众软件
Hacker News: Ask HN
Hacker News: Ask HN
Security Latest
Security Latest
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
A
Arctic Wolf
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence

Butler's Log

Agentic Version Control Benchmarks Grit: rewriting Git in Rust with agents Git Merge 2026 Agent-safe Git with GitButler We’ve raised $17M to build what comes after Git Announcing the GitButler CLI for Linux The Great CSS Expansion A couple of git nits Simplifying Git by Using GitButler Introducing the GitButler CLI GitButler 0.19 - "Commander Keen" But Head: Crafting a Custom Font MCP vs RAG: Two Very Different Ways to Gain Context Getting Started With GitButler Agents Using the GitButler MCP Server to Build Better AI-Driven Git Workflows Using GitButler With Multiple GitHub Accounts Advent of Code! Upcoming GitButler Events Use GitButler for your Gerrit workflow Integrating GitButler and GitHub Enterprise Butler Flow: shipping code faster (but less like Alfred, more like CI on steroids) - Part 3 Butler Flow: shipping code faster (but less like Alfred, more like CI on steroids) - Part 2 Butler Flow: shipping code faster (but less like Alfred, more like CI on steroids) - Part 1 Using Cursor Hooks for automatic version control Deep Dive into the new Cursor Hooks A Responsive Item Counter with CSS only GitButler 0.16 - "Sweet Sixteen" GitButler's Claude Code tab GitButler's Annual Open Source Pledge Report Git Mini Summit 2025 Videos Automate Your AI Workflows with Claude Code Hooks Managing Multiple Claude Code Sessions Without Worktrees GitButler 0.15 - "Quirky Quinceañera" 20 years of Git. Still weird, still wonderful. GitButler's new patch based Code Review (Beta) Going down the rabbit hole of Git's new bundle-uri How to do patch-based review with git range-diff How Core Git Developers Configure Git Why is Git Autocorrect too fast for Formula One drivers? Stacked Branches with GitButler Git Merge 2024 Talks are Up GitButler 0.13 - "Lucky Baseball" Fearless Rebasing Git Merge 2024 Why GitHub Actually Won GitButler is joining the Open Source Pledge The New Era of Town Hall Chat The Future of Open Source GitButler is now Fair Source Git Merge 2024 GitButler 0.12 - "Stingy Baker" The Birth of THE MERGE GitButler for Windows Fixing up Git with Autosquash The Git Zeitgeist Git Worktrees and GitButler DevWorld Git Slides Git Tips and Tricks Git Tips 1: Oldies but Goodies Git Tips 2: New Stuff in Git Git Tips 3: Really Large Repositories FOSDEM Git Talk Opening Up GitButler Debugging Tauri in VS Code Advent of GitButler Code Signing Commits in Git, Explained Virtual Branches Alpha Our We Are Developers Adventure Building Virtual Branches DevDays in Vilnius The Future of Software and Open Source Introducing GitButler
Grid Happens: Because Flexbox Wasn’t Enough
Pavel Laptev · 2025-10-14 · via Butler's Log

Hey! Today I want to talk about Grids on the web. This article was inspired by our recent redesign of the marketing and authentication pages.

After imageBefore image

Layout grid x-ray

The new design is based on a 12-column grid, with three main sections:

  • Full-width section (blue)
  • Narrow section (pink)
  • Off-center section (tilt)

So, how do you implement this in CSS? There are several ways, and we'll go through them taking a look at the pros and cons.

Before CSS Grid became the de facto layout system, developers had to come up with all sorts of creative (and sometimes painful) ways to make grids work.

The earliest method was to literally use HTML tables for page structure. A <table> would define your rows and columns, and each <td> cell would hold a piece of content.

HTML

<table width="100%">
  <tr>
    <td width="25%">Sidebar</td>
    <td>Main content</td>
  </tr>
</table>

It worked for rigid layouts, but it mixed presentation with content and was notoriously hard to maintain. There was no real responsiveness, just "stretchable" layouts, and iframes were a thing.

Speaking of maintainability and mixing presentation with content, here's a realistic example from the modern web. (Yes, we still use tables: in emails)

Screenshot 2025-10-12 at 00.36.59.png

Then came the era of floats. By floating elements left or right and manually calculating widths in percentages, you could simulate a grid. It was a huge improvement over tables, but still fragile. You needed clearfix hacks, and even the smallest DOM change could break your layout.

Soon after, we started to see the first CSS frameworks. One of the most popular was the 960 Grid System. It was based on a 960px-wide container divided into 12, 16, or 24 columns. You would add classes to your elements to specify how many columns they should span.

A slide from the official 960 Grid System site (speakerdeck.com/nathansmith/960-grid-system)

A slide from the official 960 Grid System site (speakerdeck.com/nathansmith/960-grid-system)

Interestingly, later versions of the 960 Grid System introduced subgrids and adaptive modes using Adapt.js. Before media queries were widely supported, this JavaScript library allowed you to load different CSS files based on the viewport width.

JS

var ADAPT_CONFIG = {
  // Where is your CSS?
  path: 'assets/css/',

  // false = Only run once, when page first loads.
  // true = Change on window resize and page tilt.
  dynamic: true,

  // Optional callback... myCallback(i, width)
  callback: myCallback,

  // First range entry is the minimum.
  // Last range entry is the maximum.
  // Separate ranges by "to" keyword.
  range: [
    '0px    to 760px  = mobile.css',
    '760px  to 980px  = 720.css',
    '980px  to 1280px = 960.css',
    '1280px to 1600px = 1200.css',
    '1600px to 1920px = 1560.css',
    '1940px to 2540px = 1920.css',
    '2540px           = 2520.css'
  ]
};

When Flexbox appeared around 2012-2013, it completely changed the way we thought about layout. For the first time, we could distribute space and align elements dynamically, both vertically and horizontally, without resorting to floats or clearfix hacks.

CSS

.container {
  display: flex;
  gap: 1.5rem;
}

.col {
  flex: 1;
}

Suddenly, layouts became fluid. Elements could grow or shrink automatically based on available space, and centering something both horizontally and vertically finally became a one-liner.

Flexbox was a huge step forward. It's simple to use and understand, and it works great for one-dimensional layouts, like navbars or cards, where you want to distribute space between items and align things in a row or column.

So what's the issue with Flexbox if it's so great? The problem is it's one-dimensional. Let's imagine you have a section, an aside, and a footer. You want the aside on the left, the section to take the rest of the space, and the footer at the bottom.

Flexbox has the concept of a gutter (the gap property) and the flex property to specify how much space an element should take. In theory, you can say flex: 8 for the aside and flex: 4 for the section, and it will take three times more space than the aside. But how do you specify the next row? You can't—if you add a footer with flex: 12, it will be on the same row as the aside and section.

Again, if we want to make a grid, we have to bake in classes like col-12 (100% width), col-3 (25% width), and so on.

The difference between previous CSS frameworks and Flexbox is CSS became much more powerful. Now, we don't need hacks like clearfix; we can create flows and align things easily. Another important invention was media queries, so we can change the layout based on screen size. And preprocessors like SASS let us create mixins and functions to generate these classes.

Here is one of my old pet projects Tiny percentage SCSS flexbox grid system. The layout looks like this:

HTML

<div class="grid">
  <div class="col-desk-12 col-tab-4 col-mob-2"></div>
  <div class="col-desk-4 col-tab-5 col-mob-2"></div>
  <div class="col-desk-3 col-tab-3 col-mob-4"></div>
  <div class="col-desk-2 col-mob-2"></div>
  <div class="col-desk-3 col-mob-2"></div>
  <div class="col-desk-1 col-mob-2"></div>
  <div class="col-desk-4 col-desk-shift-1 col-tab-shift-0 col-tab-6 col-mob-2"></div>
  <div class="col-desk-4 col-mob-3"></div>
  <div class="col-desk-2 col-mob-1"></div>
  <div class="col-desk-1 col-mob-1"></div>
  <div class="col-desk-1 col-mob-3"></div>
  <div class="col-desk-1 col-mob-1"></div>
  <div class="col-desk-2 col-mob-1"></div>
  <div class="col-desk-2 col-desk-shift-1 col-tab-shift-0 col-tab-1 col-mob-1"></div>
  <div class="col-desk-1 col-tab-7 col-mob-1"></div>
  <div class="col-desk-3 col-tab-5 col-mob-4"></div>
</div>

The power of SASS here is that, using variables, you can change the number of columns, the gutter size, and the breakpoints.

SCSS

// for each 3 breakpoints you can 
$grid-columns: 12;
$grid-sideMargin: 40px;
$grid-gutter: 20px;
$grid-breakpoint: 768px;

Looks like a full grid system, right? But again, it's not a real grid, just a set of classes you use to create a grid. If you want to change the layout, you have to change the classes for each element.

And finally, we have CSS Grid. Introduced around 2017, CSS Grid is a two-dimensional layout system that allows you to define both rows and columns in a single container.

CSS

.container {
  display: grid;
  grid-template-columns: repeat(12, 1fr); /* 12 equal columns */
  gap: 1.5rem;
}
.col {
  grid-column: span 4; /* Span 4 out of 12 columns */
}

CSS Grid introduces several new concepts: grid areas, grid lines, the fr unit, and the ability to overlap elements. It also provides powerful alignment capabilities and handles complex layouts with ease. Essentially, it's a full layout builder. Unlike Flexbox, you can create the same layout using a combination of different Grid techniques. Let's take this as an example:

/* ------------------------------------- */
/*               HEADER                  */
/* ------------------------------------- */
/*         |                             */
/* SIDEBAR |          CONTENT            */
/*         |                             */
/* ------------------------------------- */
/*               FOOTER                  */
/* ------------------------------------- */

CSS

.grid-container {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar content"
    "footer footer";
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
  min-height: 100vh;
}

.header {
  grid-area: header;
  background: #f3f4f6;
  padding: 1rem;
}

/* Other styles for sidebar, content, and footer */

As you can see, it's almost like a drawing. You can see the layout structure right in the CSS. You define areas like header, sidebar, content, and footer, and then assign those areas directly in the CSS.

Another powerful feature of CSS Grid is subgrid, but let's talk about this using our redesign as an example.

Columns, Alignment, and Grid Magic

When we began redesigning our marketing pages, I knew CSS Grid would be a perfect fit. I wanted precise alignment of elements across different top-level sections, as well as their content and nested sections.

grid-alignment.webp

Here is a simple example of 12 columns grid:

CSS

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 20px;
}

The difference between the layout I showed above (with a header, sidebar, content, and footer) and our layout is that we still want a flow-like structure. We want a full-width section, a narrow section, and an off-center section, but we don’t want to define extra rows—just columns. The great thing about grids is that they can automatically wrap to the next row as needed. It’s like Flexbox, but with extra power.

fixed-grid-vs-flow.webp

HTML

<div class="grid">
  <div class="item span-2">2 columns</div>
  <div class="item span-10">10 columns</div>
  <div class="item span-12">12 columns (full width)</div>
</div>

CSS

.span-2 {
  grid-column: span 2;
}
.span-10 {
  grid-column: span 10;
}
.span-12 {
  grid-column: span 12;
}

There are many ways in Grid to define your columns/rows. For example, instead of spanning columns, you can define the start and end lines. If you want a full-width section, you can use grid-column: 1 / -1; (start from the first line and end at the last). For a narrow section, you can use grid-column: 3 / span 8; (start from the third line and span 8 columns).

CSS

.full-width {
  grid-column: span 12;
}
.narrow {
 grid-column: 3 / span 8; /* Start at column 3 and span 8 columns */
}
.off-center {
  grid-column: 3 / span 9; /* Start at column 2 and span 7 columns */
}

It looks simple, but the syntax can be confusing. For example, if you want your column to start from column 2, you actually need to write grid-column: 3 / span 8; because the first line is 1.

grid-column-span-explane.webp

Is there a way to simplify this? You can use CSS custom properties to define the start and end lines. So you can define --start and --end properties and use them in your CSS.

CSS

:root {
  --start: 3;
  --end: 10;
}

.narrow {
  grid-column: var(--start) / var(--end);
}

But that feels a bit like a hack. There's a more elegant, native way: define names for the grid lines:

CSS

.grid {
  display: grid;
  grid-template-columns: [full-start] repeat(2, 1fr) [narrow-start] repeat(8, 1fr) [narrow-end] 1fr [off-center] 1fr [full-end];
  gap: 20px;
}
.full-width {
  grid-column: full-start / full-end;
}
.narrow {
  grid-column: narrow-start / narrow-end;
}
.off-center {
  grid-column: narrow-start / off-center;
}

Even better, with this approach, you can change everything about the layout in one place for different screen sizes using media queries.

CSS

@media ( max-width: 768px ) {
  grid-template-columns:
    [full-start]
    1fr
    [narrow-start]
    repeat(10, 1fr)
    [narrow-end off-center]
    1fr
    [full-end];
}

@media ( max-width: 480px ) {
  grid-template-columns:
    [full-start narrow-start]
    repeat(4, 1fr)
    [narrow-end full-end off-center];
}

The cool thing here is you can combine different areas into one. For example, you can combine [narrow-end] and [off-center] on the tablet breakpoint into one area like [narrow-end off-center], and on the mobile, you can combine all three into [full-end narrow-end off-center].

Subgrids is a relatively new feature. I remember that just a few years ago, it wasn’t supported widely, and I really struggled without it. To me, using grid layout without subgrids was almost pointless because it required hacks. Most website structures are far more complex than a single grid.

website-grid-structure.webp

As you can see in the image above, you have a grid on the main wrapper component, then a section inside, and then cards and blocks inside the section. You want them all to align with the main grid. Without subgrid, you can't do this cleanly.

All you need to do is set display: subgrid on the child grid, and it will inherit the grid structure from the parent grid.

CSS

.section {
  display: grid;
  grid-template-columns: subgrid;
  gap: 20px;
}
.card {
  grid-column: span 4;
}

Let's combine all these techniques into one example. Here, we have nested components that consume the main grid and also rearrange the layout for different screen sizes.

It's surprising how well CSS Grid solves so many issues we used to tackle with hacks. Here are my takeaways:

  • CSS Grid sound complex, but to achieve most layouts, you only need a small part of the system. Many things you used to do in Flexbox also work in Grid, like justify-content, align-items, gap, and so on.
  • CSS Grid is not a silver bullet. There are still cases where Flexbox is a better fit, for example, for simple one-dimensional layouts like navbars or lists. But for complex layouts with multiple rows and columns, Grid is the way to go.
  • You can name column ranges, which makes column assignment much more readable and easier to maintain.
  • With media queries, you can change the whole grid structure in one place and rearrange the layout for different screen sizes. You can also combine different areas into one, making it even more flexible.
  • With subgrids, you can make complex nested layouts and still keep everything aligned to the main grid.

Note: If you want to learn more about CSS Grid, I recommend resources like CSS Tricks Complete Guide to Grid and MDN Web Docs on CSS Grid.

Pavel Laptev

Written by Pavel Laptev

Quack! A digital designer who loves open source. Flaps around making interfaces nice and helps the design and frontend pond whenever he can.

Table of Contents

  • Life Before Grid: The Struggle
  • When Tables Ruled the Web
  • Float Like a Butterfly, Layout Like a Brick
  • Flexbox: The Cool Kid
  • CSS Grid to the Rescue
  • Columns, Alignment, and Grid Magic
  • Subgrids: Grids All the Way Down
  • Key Takeaways