Register to get access to free programming courses with interactive exercises

Arrangement of elements in the grid CSS: Layout on the Grid

In the last lesson, we created a 12-column grid. In this case, all the elements in it could only be placed one after the other and had the width of one column. Of course, in real projects, this is a rare situation. Often, each element has its unique arrangement, and rarely do they stand just one after the other horizontally.

In one of the first lessons, we mentioned that all grid lines have ordinal numbers. Each grid line has two values:

  • A number for counting from left to right
  • A number for counting from right to left

And in the latter case, the numbers have a negative value. Let's see what it looks like on the example of a regular grid:

Grid line numbering

There are five vertical lines in this grid. The first line has two ordinal numbers: 1 and -5. Also, there are four horizontal lines. The lowest of them has the ordinal numbers 4 and -1.

We can use these numbers to bind elements to specific grid lines. Note that when using Grid we focus much less on notions like the width and heights of elements.

Now, we give these two characteristics away to the columns and rows. The size of the element inside the grid depends on them.

Let's go back to the example from the last lesson. We implemented a 12-column grid with three elements inside:

Now, we know the ordinal numbers of all grid lines and can place our elements in the following order:

  • The first item will occupy 12 columns, starting with the grid line number 1. It'll take up two whole rows
  • The second element should be located below the first element and will take up four columns, starting with the first
  • The third element will occupy the remaining eight columns next to the second element

The result is a typical two-column layout structure. There are four properties in CSS Grid Layout for positioning elements along grid lines:

  • grid-column-start — indicates the initial vertical Grid-line of the element's location.
  • grid-column-end — indicates the final vertical Grid-line of the element's location. Note that the value indicates before which column to place the item. The column specified in this property is not activated. You should add a new column to include the specified one. For example, you need to enter 13 for a 12-column layout to include the last column
  • grid-row-start — indicates the initial horizontal grid line of the element's location
  • grid-row-end — indicates the final horizontal grid-line the property specifies before which row to place the element

Using these properties, we can achieve two goals:

  • To set the initial positions from which we draw the element
  • To set the final positions, which give us the width of the element

Let's set the necessary properties for all three blocks. Let's add some semantics:

Note that we set grid-column-start for the header. It may seem redundant since the block already starts from the first column. It is true if no end grid line is specified. If you remove the grid-column-start property, it's as if the element starts expanding from right to left instead of left to right:

We can make these properties more convenient because there are abbreviated ways to enter them. They allow you to write start and end values using just one property. The grid-column property specifies the start and end strips horizontally. We use grid-row to do the same vertically. The value is the start and end strip, separated by slash /.

If we use abbreviations, we can write the example above as follows:

.grid-header {
  grid-column: 1 / 13;
  grid-row: 1 / 3;

.grid-aside {
  grid-column: 1 / 5;
  grid-row: 3 / 13;

.grid-main {
  grid-column: 5 / 13;
  grid-row: 3 / 13

There is an interesting technique when positioning elements within strips is to use negative values. Since each strip has two values, we can also refer to them with negative values. It is especially useful when you want to stretch the item to the full width of the container. Instead of counting the number of strips, you can specify -1 as the final value. It will automatically stretch the item to the last strip. You no longer have to keep the number of strips in your head and change them when you change the grid.

As an example, let's stretch the header using a negative final value:

Keyword span

When we make layouts, it is often impractical to keep track of where an element starts and where it ends. It is much clearer to track:

  • The starting strip from which we draw the element
  • The number of columns it should occupy

It's impossible to do this with the tools we know.

To solve this problem, the developers introduced the span keyword. It indicates the number of cells needed for the element when placed inside the grid. Now, instead of specifying the index of the strip where it should end, you can use this syntax: span <number of cells>.

Let's continue working with the two-column layout. When creating the header, we used a negative value to determine the final strip. Let's move on to the two columns below. We can use the keyword span to shorten the code and make it more understandable:

.grid-header {
  grid-column: 1 / -1;
  grid-row: 1 / span 2; /* Specify that the element occupies two columns vertically */

.grid-aside {
  grid-column: 1 / span 4; /* Specify that the element occupies 4 columns horizontally */
  grid-row: 3 / -1;

.grid-main {
  grid-column: 5 / -1;
  grid-row: 3 / -1

Moreover, you can use the keyword span as a value. In this case, the browser will place the element with the number of lines/columns you specified. For example, the following will create a two-column wide element:

.col-2 {
  grid-column: span 2;

It is useful when arranging elements within a grid. With this approach, it's possible to create your framework with classes responsible for the number of columns occupied by a block:

Naming lines

Also, for convenience and readability of your CSS, you can give names to your lines. These can be any names that describe a given line. As we go on, we will work using these names.

It is useful when creating complex layouts because it's not great to constantly remember where the different blocks start and end. The number of errors will increase as the layout becomes complex. In the case of names, everything is simpler, because they clearly describe the grid line with a name that makes sense to the developer.

To create named grid lines, use the following syntax for the grid-template-columns and grid-template-rows properties: [Line name] is the width of the strip after the line. You can set any number of different names directly in the layout. It won't damage the current template.

Let's add named lines to our two-column layout to indicate the beginnings of each area. We use them to designate starting rows and columns. There will be four of these named lines:

  1. header-top — the topmost line from which we draw the site's header
  2. content-begin — the line where the site's main content starts. In this case, it's aside and main. It works great as a header height limiter
  3. sidebar-begin — the left line from which aside will be drawn
  4. main-begin — the line from which main begins. Let's use it to limit the width of aside

Let's substitute the names in the existing CSS and see how they are written:

.grid-12 {
  display: grid;
  grid-template-columns: [sidebar-begin] 1fr repeat(3, 1fr) [main-begin] 1fr repeat(7, 1fr);
  grid-template-rows: [header-top] 1fr 1fr [content-begin] 1fr repeat(9, 1fr);

  height: 100vh;

Let's parse the following line: grid-template-columns: [sidebar-begin] 1fr repeat(3, 1fr) [main-begin] 1fr repeat(7, 1fr);. We can divide it into four parts:

  • [sidebar-begin] 1fr. As described, we create a named line named sidebar-begin and a one-fraction-wide strip
  • repeat(3, 1fr). One entry you've already seen will create three strips with a width of 1 fraction of each
  • [main-begin] 1fr. A named line main-begin_ is created The width of the strip after the line will be one fraction
  • repeat(7, 1fr). Seven strips with a width of one fraction each are created

We can use these names now in the grid-column-start, grid-column-end, grid-row-start, and grid-row-end properties we studied.

It's important to note that even if you name a line, it doesn't lose its index. You can refer to these lines by both their names and indexes (positive or negative).

Creating named grid areas

As well as naming grid lines, we can also name entire areas — sets of several strips connected by single grid lines.

So how can naming areas help with creating layouts? This tool is quite groundbreaking when it comes to creating designs in CSS. This property allows you to name the abstract areas and visualize the grid using those names. One of the disadvantages of this method is that it's a little unwieldy. Let's deal with this more when we do the practice tasks.

We use the grid-template-areas property to create named areas. It takes data wrapped in double quotes as a value. The data in question describes the areas located on the grid. The more columns they occupy, the more times they need to be repeated inside the value. The values are separated by a space.

For the start, we create a grid of six columns. Put a two-column layout in it, as in the previous example. First, let's define the header. It takes up the entire screen width, so we allocate six columns.

Let's call this area, naturally, the header. You can choose whatever name you like for this area. We also need to specify the block that will be the header area. We do it using the grid-area property, the value of which is the area name. In this case, it's header:

.grid-6 {
  display: grid;
  grid-template-areas: "header header header header header header";

.grid-header {
  grid-area: header;

Note that the .grid-6 container lacks the grid-template-columns and grid-template-rows properties. Their job is now the job of the grid-template-areas role. When we specify a certain number of areas in it, we automatically create columns with a one-fraction width. If you need other values, you can always use the grid-template-columns and grid-template-rows properties to set the desired strip widths.

Now we've done the top row. It's time to start on the next row, where we'll place aside and main. To do this, continue to enter values in the grid-template-areas property. Since we need a new row, we do not write inside the value with header. Let's add a space and write new double quotes containing the locations of elements in the next row:

.grid-6 {
  display: grid;
  grid-template-areas: "header header header header header header" "aside aside main main main main";

.grid-header {
  grid-area: header;

.grid-aside {
  grid-area: aside;

.grid-main {
  grid-area: main;

Note that the number of columns must be the same in each row. If you omit this point on any line, the browser will ignore the grid-template-areas property because it can't understand or process what you want.

If more rows are needed, you can continue to add them. It is important if you have non-standard cell sizes. In other cases, we determine the height of blocks by the content within them. It is standard behavior, so you'll know it from designing layouts. In this case, we created a grid of 6 columns and two rows:

CSS allows you to move lines within a property to make it easier to read. It makes the grid-template-areas property more visible. You can also put any number of spaces within the values themselves. We can set the columns in each row below each other:

.grid-6 {
  display: grid;
  grid-template-areas: "header header header header header header"
                       "aside  aside  main   main   main   main";

There are situations when you need an empty cell instead of one of the columns. Since the number of columns in each row must be the same, you can't just delete one of the areas. Instead, grid-template-areas can take a specific value that denotes an empty area. This value is a period — ..

Let us make the header in the current grid one column smaller. It should take up five columns instead of six. In this case, the value of the property will look like this:

.grid-6 {
  display: grid;
  grid-template-areas: "header header header header header ."
                       "aside  aside  main   main   main   main";

Do it yourself

Create a three-column layout consisting of the following:

  • A header.
  • A left sidebar.
  • Main Content.
  • A right sidebar.
  • A footer.

Use both methods when creating. Use Grid-lines first, then Grid-areas. The number of columns in the grid is up to you. In this case, there can't be less than three.

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
hours of theory

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

Health Samurai
Suggested learning programs
Layout with the latest CSS standards
5 months
from scratch
under development
Start at any time

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.