Mastery Games

How to Build a Grid Inspector

We've seen that when building a Grid layout, you're working with an invisible grid. So you power up the devtools Grid Inspector and in your best Harry Potter voice chant Aparecium Grid! Then just like magic, your invisible grid appears! This is both neat and frustrating. You can't see or style your grid, but the devtools somehow can? It's cheating right?! In this post I'll show you how to create your own Grid Inspector - a super fun little project that will leave you with a better understanding of how this important tool works.

In my Grid Critters Mastery Game I wanted to teach how CSS Grid lines & gaps work in a fun and engaging way. So I created a custom Grid Inspector where each grid line is a pair of laser-connnected interceptor spaceships. It looks like this:

Space ship grid inspector

To show you how to build one like it let's start with the basics.

Positioning the Inspector

We'll build a grid inspector using this basic grid layout as an example:

#container{
  display: grid;
  width: 100%;
  height: 350px;
  grid-template-columns: [full-start] 1fr 1fr [full-end];
  grid-template-rows: 100px 1fr 100px;
  grid-gap: 20px;
}

.purple {
  grid-row: span 2;
}

.blue {
  grid-column: span 2;
}

The first thing we'll need is to create a div and place it exactly over the top of the display:grid element.

const container = document.getElementById("container");
const inspector = document.createElement('div');
inspector.setAttribute('style', `
  position: absolute;
  height: ${container.offsetHeight}px;
  width: ${container.offsetWidth}px;
  top: ${container.offsetTop}px;
  left: ${container.offsetLeft}px;
  background: rgba(58, 250, 8, .5);
`);
document.body.appendChild(inspector);

Getting the Grid Data

Now that we have our inspector div placed right over top of the element we're going to be inspecting, we want to ask the browser about the rows, columns, and gaps in our grid:

const styles = window.getComputedStyle(container)

const rows = styles.getPropertyValue('grid-template-rows')
const columns = styles.getPropertyValue('grid-template-columns')

const rowGap = styles.getPropertyValue('grid-row-gap')
const columnGap = styles.getPropertyValue('grid-column-gap')

The browser really throws us a bone here by returning the current pixel size of things, rather than in the units specified. Our example's two columns are given 1fr width, but querying their property value returns a string of "[full-start] 300px 300px [full-end]". This tells us the names of the grid lines and the sizes of the tracks (rows and columns). See Naming your CSS Grid Lines to understand exactly how that syntax works.

Transforming the Grid Data

But for our Grid Inspector we're actually more interested in displaying the lines that sit on the edges of the grid and between each of the tracks. So we'll convert this info into an array of objects that describe the position and name of each grid line.

// convert the rows and columns into a format we can work with
const columnData = parseGridTemplate(columns, columnGap)
const rowData = parseGridTemplate(rows, rowGap)

See this codepen if you want to dive into our parseGridTemplate function.

So the browser gave us this:

// columns
'[full-start] 300px 300px [full-end]'

// columnGap
20

and we transformed it into this:

;[
  {
    start: -1,
    end: 1,
    name: 'full-start',
  },
  {
    start: 299,
    end: 301,
    name: null,
    gap: 20,
  },
  {
    start: 619,
    end: 621,
    name: 'full-end',
  },
]

The start and end values are where we want our grid lines to show up, and the middle line has a 20px gap (outer lines don't get gaps applied to them which is fantastic).

We now have a format that describes all the grid lines we want to render. This is where a template framework like React/Angular/Vue would come in handy. But let's make this one in vanilla JS for this exercise.

Rendering the Grid Lines

Taking our grid data, we can now create a simple styled div for each grid line and put it where it goes, accounting for any grid gap sizes the lines might have. We'll also extend the lines out a bit farther than the element to make them easier to see.

// extend the lines a bit so we can see them better
const extendLines = 20

// render a line for each vertical grid line
columnData.forEach(item => {
  const line = document.createElement('div')
  line.setAttribute(
    'style',
    `
    background: rgba(0, 0, 0, 1);
    position: absolute;
    height: ${container.offsetHeight}px;
    width: ${item.end - item.start + (item.gap || 0)}px;
    left: ${item.start}px;
  `
  )
  inspector.appendChild(line)
})

// render a line for each horizontal grid line
rowData.forEach(item => {
  const line = document.createElement('div')
  line.setAttribute(
    'style',
    `
    background: rgba(0, 0, 0, 1);
    position: absolute;
    width: ${container.offsetWidth}px;
    height: ${item.end - item.start + (item.gap || 0)}px;
    top: ${item.start}px;
  `
  )
  inspector.appendChild(line)
})
render grid lines

Here's the codepen example of this.

See, it's not black magic! We just leverage the info the browser gives us, throw in a wee bit o' JS, add some styling spices and voilà. Our very own custom Grid Inspector! I went a little crazy on mine for Grid Critters, using the positioning to render sprites to a canvas, animated the ships flying into their positions, and even made fun little thruster animations for when when grid gaps change size:

animated css grid gaps

Now you know how Grid Inspectors like the one in Firefox work (only with a lot more features and polish).

From here you can take yours in any awesome direction you can imagine. I'd love to see where you take it! Send me a video on twitter (@geddski) and show me what you make!

Grid Critters Game

Master CSS Grid right from the start by playing this new mastery game. You'll learn the ins and outs of Grids one fun level at a time, while saving an adorable alien life form from certain destruction.Master CSS Grid