HTML and CSS course Β· Module 8: CSS Grid

Advanced Positioning in CSS Grid

7 min read
In this lesson6

Imagine you are a pyramid architect and need to precisely determine where each chamber, corridor and treasury will be. The plan from the previous lesson has a weak spot, though: when the pharaoh adds one more column, every 1 / 4 has to be corrected by hand. In CSS Grid, you have advanced positioning techniques at your disposal that let you control every grid element with surgical precision and write plans that survive a rebuild.

grid-column and grid-row with Line Numbers

Every grid has numbered lines, both vertical (column lines) and horizontal (row lines). Numbering starts from 1. If you have 3 columns, you have 4 column lines (1, 2, 3, 4). You can specify the exact position of an element by providing the start and end lines:

1.pharaoh-chamber {
2  grid-column: 1 / 3;  /* From line 1 to line 3 = spans 2 columns */
3  grid-row: 1 / 2;     /* From line 1 to line 2 = spans 1 row */
4}

The pharaoh's chamber takes two columns and one row, because it ends at line 3 and at line 2. You can also use negative line numbers, counted from the end of the grid. Line -1 is always the last line of the explicit grid, the one defined in grid-template-columns:

1.footer {
2  grid-column: 1 / -1;  /* From the first to the last line = full width */
3}

The footer reaches from the first to the last line, and when you add a column, it will still span the full width without any correction. Negative numbers do not, however, count tracks that the browser added by itself outside the explicit grid. It's like drawing precise coordinates on a pyramid blueprint, where each stone block has an exactly designated position.

Stretching Elements - The span Keyword

Instead of providing end line numbers, you can use the span keyword to specify how many cells an element should occupy:

1.grand-hall {
2  grid-column: span 2;  /* Stretch across 2 columns from the current position */
3  grid-row: span 3;     /* Stretch across 3 rows */
4}
5
6.treasure-room {
7  grid-column: 2 / span 2;  /* Start from line 2, occupy 2 columns */
8  grid-row: 1 / span 1;
9}

The difference between span and line numbers is that span is relative and says "occupy N cells", while line numbers are absolute and say "from line X to line Y". The grand hall, having no start line, lands wherever automatic placement puts it, while the treasure room starts exactly at line 2.

Named Grid Lines

Numbers are hard to remember, so you can give names to lines, which makes the code more readable. Names are placed in square brackets between the column sizes, and a single line can have several names at once:

1.temple {
2  display: grid;
3  grid-template-columns:
4    [sidebar-start] 200px
5    [sidebar-end main-start] 1fr
6    [main-end aside-start] 250px
7    [aside-end];
8  grid-template-rows:
9    [header-start] 80px
10    [header-end content-start] 1fr
11    [content-end footer-start] 60px
12    [footer-end];
13}

The line between the sidebar and the content carries two names: sidebar-end and main-start. The column and row sizes are the same as without names, because names only describe the lines. Without names you would write the same rows briefly as grid-template-rows: 80px 1fr 60px: a fixed header, flexible content and a fixed footer. Now you can position elements using names instead of numbers:

1.sidebar {
2  grid-column: sidebar-start / sidebar-end;
3  grid-row: content-start / content-end;
4}
5
6.main-content {
7  grid-column: main-start / main-end;
8  grid-row: content-start / content-end;
9}
10
11.header {
12  grid-column: sidebar-start / aside-end;  /* Full width */
13  grid-row: header-start / header-end;
14}

The header reaches from sidebar-start to aside-end, which is the full width. Named lines are like labels on an architectural blueprint: instead of "line 3", you have "start of the main hall". It's much easier to navigate!

grid-area as a Positioning Shorthand

The grid-area property lets you define an element's position in a single line. Format: grid-area: row-start / column-start / row-end / column-end. The values can be numbers, negative numbers or line names:

1.pharaoh-throne {
2  grid-area: 1 / 1 / 3 / 3;
3  /* Row from 1 to 3, column from 1 to 3 = a 2x2 square */
4}
5
6.guard-post {
7  grid-area: 3 / 1 / 4 / -1;
8  /* Last row, full width */
9}

The throne takes a 2x2 square in the top left corner, and thanks to -1 the guard post stretches across the whole third row, regardless of the number of columns.

Practical Example: Egyptian Temple Floor Plan

Let's combine all the techniques to create a complex temple floor plan. The columns carry the names of the entrance, the hall and the chapel, and the rows are named top, middle, bottom and end:

1.temple-complex {
2  display: grid;
3  grid-template-columns:
4    [entrance-start] 150px
5    [entrance-end hall-start] 1fr
6    [hall-end chapel-start] 200px
7    [chapel-end];
8  grid-template-rows:
9    [top] 100px
10    [middle] 1fr
11    [bottom] 80px
12    [end];
13  gap: 10px;
14  min-height: 400px;
15}
16
17.entrance {
18  grid-column: entrance-start / chapel-end;  /* Full width */
19  grid-row: top / middle;
20}
21
22.main-hall {
23  grid-area: middle / hall-start / bottom / hall-end;
24}
25
26.side-chapel {
27  grid-column: chapel-start / chapel-end;
28  grid-row: middle / end;  /* Two rows */
29}
30
31.storage {
32  grid-column: entrance-start / entrance-end;
33  grid-row: middle / bottom;
34}
35
36.foundation {
37  grid-column: 1 / -1;  /* Full width using numbers */
38  grid-row: bottom / end;
39}

The entrance takes the whole top row, the main hall uses grid-area written with names only, and the foundation mixes names with numbers. Notice that the side chapel and the foundation share the last row in the chapel column. Explicitly positioned items may overlap, and that is not a syntax error. The one drawn on top is the one that comes later in the HTML, unless you change its z-index. In a real project, shorten the chapel to one row or use the overlap deliberately.

Advanced positioning combines very well with an automatic grid. The gallery counts its columns by itself thanks to repeat(auto-fill, minmax(250px, 1fr)), and a featured statue takes a two-by-two square:

1.gallery {
2  display: grid;
3  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
4  gap: 16px;
5}
6
7.gallery .featured {
8  grid-column: span 2;
9  grid-row: span 2;
10}

Each column is between 250px and 1fr wide, and the remaining exhibits arrange themselves around the statue. When the screen fits only one column, span 2 forces the browser to add an extra, implicit column outside the planned grid, which is why it is safer to undo the span in a media query on narrow screens. Large items also sometimes leave empty cells, and grid-auto-flow: dense lets the browser fill them with smaller items, at the cost of changing the visual order.

With these advanced positioning techniques, you can precisely arrange elements within the grid. Line numbers give you full control, span simplifies stretching, named lines make the code readable, and grid-area allows for concise notation. My advice: in page layouts use named lines or 1 / -1, and keep span for cards and exhibits. You will combine all of this in the Abu Simbel project at the end of the module. In the sandbox below, a temple portal is waiting: define grid-template-areas for it, assign the elements to the areas, and then try the same with named lines.

Remember: a named line is an inscription carved into the temple plan, and it will not get lost even when the pharaoh orders another chamber to be built.

Code for this lesson: index.html
1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>Grid Template Areas</title>
7    <link rel="stylesheet" href="style.css">
8</head>
9<body>
10    <div class="portal">
11        <header class="portal-header">Temple of Knowledge</header>
12        <nav class="portal-nav">
13            <a href="#">Home</a>
14            <a href="#">Pyramids</a>
15            <a href="#">Pharaohs</a>
16            <a href="#">Hieroglyphs</a>
17        </nav>
18        <section class="portal-hero">Hero Section - Discover the secrets</section>
19        <main class="portal-content">
20            <h2>Main Content</h2>
21            <p>Here you will find knowledge about ancient Egypt.</p>
22        </main>
23        <aside class="portal-sidebar">
24            <h3>Sidebar</h3>
25            <p>Fun facts and additional information.</p>
26        </aside>
27        <footer class="portal-footer">Temple Footer</footer>
28    </div>
29    <!-- Task: Define grid-template-areas and assign the elements -->
30</body>
31</html>

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. What is the minmax() function used for in CSS Grid?

  2. 2. How do you define 3 rows in CSS Grid - the first with a fixed height of 100px, the second flexible, and the third automatic?

These are 2 of 3 questions for this lesson. Solve the rest in the game.

Hands-on tasks in the game

  • Code editor

    Use grid-column: span 2 and grid-row: span 2 to create featured items that stretch across multiple cells.

  • Horizontal ordering

    Arrange the responsive repeat() with auto-fill and minmax():

  • Click in order

    Click in order the elements of a CSS Grid declaration with rows and columns

Useful articles