CSS Grid Container - Bless you

CSS Grid Container Billboard

Where has this little Gem been hiding?

Sometimes I find myself in a spot of bother... and then I find something like this, that gets me out of the shit.

Even though I really like this blog software (Chyrp-Lite), there are some limitations (challenges/opporunities).

The way that the article excerpt is displayed on the home page is essentially the same as it is displayed when viewing the actual article.

The difference is that the home page only shows < 1000 characters (or upto a MORE string).

The way that an article is structured is something like this:

<article>
	<section class="body">
		<h2>Article Title</h2>
		<p><img src="example.jpg"></p>
		<p>Line1</p>
		<p>Line2</p>
	</section>
	<footer>
		<div>TAGS</div>
		<div>META DATA</div>
	</footer>

The problem comes when you want the same article content to be displayed differently on the home page (to that of viewing the full article).

CSS Grid Container Layout

For instance on my home page I have the image element first, then the title, then 1 line of the article, then tags etc.

The HTML order/structure that I am given doesn't look that flexible. (Yay).

Of course, CSS Grid Containers to the rescue.

The beauty of a Grid Container is that you can define a container (in CSS) and then use more CSS to pick elements off of the page and place them in the Container -- where you want them.

In the case above, this is how I used CSS Grid Containers to restructure the look of the data on the home page.

    body.route_index article section.body {
        display: grid;
        grid-template-columns: 330px auto;   /* 300px image width + 30px margin */
        grid-template-rows: 50px 70px 110px;  /* All need to add up to above height 200px + 30px margin*/
    }

Defining the container

To define a container is simple, you just need to change an elements display to grid (using CSS). I chose section element, but it probably could have been the article element too.

As can be seen above, I selected the element by using CSS rules (body.route_index article section.body). Note: The Body element has a class added to it called route_index. This is specific to Chyrp-Lite - your body element won't have this.

Next, I needed to define what the container would look like. I knew that I wanted an image that had a max height of 300px to exist on the left side, the header at the top of the right side, and 1 line of content underneath.

I defined the first columns width to 330px. This allowed for my 300px image and a 30px gap. Note: The CSS Grid Container has a grid_gap style but it applies the gap to the whole Grid -- which I did not want.

I set the second column to Auto as it's width should take up the rest of the horizontal space.

Now that I had my columns setup I needed to define my rows. I needed a row for the title, the 1 line from the content and then a spacer to make up the rest of the height. As can be seen above (in the CSS rule) I defined my row heights as:

  1. First row: 50px
  2. Second row: 70px
  3. Third row: 110px (I ended up changing this to auto later --- let it work out how much room it needs)

Done. The container is setup.

Assigning elements to Grid positions

    body.route_index article section.body h2 {
        grid-column: 2;
        grid-row: 1;
        width: max-content;
    }

Once again I use a CSS rule to select the element (H2 element) that I want to assign to a cell in the grid. I tell CSS that this element should be placed in Row 1 Column 2.

Note: The width: max-content only affects the H2 element. By default, the H2 element (being a heading) will try and take up the whole line. It was giving me some grief so I used CSS to select only the Content. Try it out for yourself to see the difference. Very useful.

    body.route_index article section.body p:nth-of-type(1) {
        grid-column: 1;
        grid-row: 1 / span 3;
    }
    body.route_index article section.body p:nth-of-type(1) img {
        max-width: 300px;
    }

I think that moving the IMG element gave me the most pleasure. In the past doing this was impossible -- without changing code.

I assigned the Paragraph (that the IMG element was wrapped in) to Column 1, and told the Grid that it will take up 3 rows (span 3).

The next rule just ensures that the IMG only can have a max-width of 300px (leaving 30px for the gap).

    body.route_index article section.body p:nth-of-type(2) {
        grid-column: 2;
        grid-row: 2;
    }
    body.route_index article section.body p:nth-of-type(3) {
        display: none;
    }

The next Paragraph element contained the first line from the articles excerpt. I assigned this to Row 2, Column 2.

Just in case a second line was present, I changed its display to none (to hide it from the view).

I love CSS.

    body.route_index article footer div:first-child {
        position: absolute;
        top: 188px;
        left: 360px;
    }

Finally, I positioned the TAGS in an absolute position.

I did this because I knew how my layout was structured and in other views (i.e. on an iPhone) I needed to positon the TAGS elsewhere.

To do this I ensured that the article element has a position of relative so that the TAGS position would be based on it.

And that is how it is done.

Media Rules

As I wanted my layouts to fit nicely on most devices, I ended up using a number of Media Rules and redefined the above in each of those rules.

If you view my site on most devices using portrait or landscape you will see how the view changes.

View the CSS on this page to see what I have done.

I hope that you have found this helpful.

Further Reading: W3Schools CSS Grid Container article

Example

<!DOCTYPE html>
<html>
<head>
<style>
.grid-container {
	display: grid;
	grid-template-columns: 330px auto;
	grid-template-rows: 50px 70px 110px;
	grid-gap: 10px;
	background-color: #000;
	margin: 10px;
	padding: 10px;
}
.grid-container div {
	background-color: #fff;
}
.grid-container div:nth-of-type(1) {
	grid-column: 2;
	grid-row: 1;
}
.grid-container div:nth-of-type(2) {
	grid-column: 1;
	grid-row: 1 / span 3;
}
.grid-container div:nth-of-type(3) {
	grid-column: 2;
	grid-row: 2;
}
.grid-container div:nth-of-type(4) {
	display: none;
}

</style>
</head>
<body>
<div class="grid-container">
  <div><i>TITLE</i></div>
  <div>IMAGE</div>
  <div>LINE1</div>
  <div>PADDING</div>
</div>
</body>
</html>