Why are images overlapping in CSS Grid?

3.5k Views Asked by At

I'm trying to build a product page with CSS Grid. For some reason my images keep overlapping, instead of being positioned below each other.

I mimicked my code (without all the drupal fluf) in the code below. I have the same issue there. I tried with a single grid and also with grid in a grid (as in my example)

https://jsfiddle.net/e28mc4f5/1/

#mygrid {
 display: grid;
 grid-template-columns: 300px 1fr;
 grid-template-rows: auto;
 grid-template-areas: 
  "images title"
  "images model"
  "images price"
  ;
}

#mygrid .items  {
 background-color: red;
 grid-area: images;
 display: grid;
 grid-template-columns: 100px 200px;
 grid-template-rows: 100px 100px auto;
 grid-template-areas: 
  "thumbs main"
    "thumbs main"
    "thumbs main"
  ;
}

#mygrid .items .item  {
 grid-area: thumbs;

}

#mygrid .items .item img{
  //why are there overlapping??
 width: 100px;
 height: auto;
  
}

#mygrid .items .item:first-child  {
 grid-area: main;
   
}

#mygrid .items .item:first-child img{
 width: 200px;
 height: auto;
}
<div id="mygrid">
  <div class="items">
    <div class="item">
      <img src="http://lorempixel.com/100/100/sports">
    </div>
    <div class="item">
      <img src="http://lorempixel.com/100/100/food">
    </div>
    <div class="item">
      <img src="http://lorempixel.com/100/100/cities">
    </div>
    <div class="item">
      <img src="http://lorempixel.com/100/100/nature">
    </div>
  </div>
  <div class=info>MY TITLE</div>
  <div class=info>My Description</div>
  <div class=prijs>My Price</div>
  
</div>

I'm trying to place all images (except the first) in the first grid column named "thumbs". (this works but fall over each other)

And I'm placing the first image in a second column with a bigger size. (this works)

I'm pretty sure I'm missing something basic, but I've been trying (and googling) for hours. Maybe another pair of eyes can enlighten me.


This is a single-grid version. Here the issue is that the first image will not put itself in the correct location.

https://jsfiddle.net/wrpt5g3b/1/

#mygrid {
 display: grid;
  grid-template-columns: 1fr 2fr 3fr;
 grid-template-rows: 25px 25px 25px auto;
  
 grid-template-areas: 
  "aside main model"
  "aside main price"
  "aside main input"
  "aside . ."
  ;
}

#mygrid .items  {
}

#mygrid .items .item  {
 grid-area: aside;
}

#mygrid .items .item img{
 width: 100px;
 height: auto;
  
}

#mygrid .items .item:first-child  {
 grid-area: main;   //why is this ignoring it's place?
  justify-self: stretch;
}

#mygrid .items .item:first-child img{
 width: 200px;
 //height: auto;
}
#mygrid .title {
  grid-area: model;
 justify-self: stretch;
} 

#mygrid .info {
  grid-area: input;
 justify-self: stretch;
} 

#mygrid .price {
  grid-area: price;
 justify-self: stretch;
} 
<div id="mygrid">
  <div class="items">
    <div class="item">
      <img src="http://lorempixel.com/100/100/sports">
    </div>
    <div class="item">
      <img src="http://lorempixel.com/100/100/food">
    </div>
    <div class="item">
      <img src="http://lorempixel.com/100/100/food">
    </div>
    <div class="item">
      <img src="http://lorempixel.com/100/100/food">
    </div>
  </div>
  <div class=title>MY TITLE</div>
  <div class=info>My Description</div>
  <div class=price>My Price</div>
  
</div>

2

There are 2 best solutions below

4
On BEST ANSWER

The problem is that you are applying the same grid area name to all image containers.

Each .item element is named thumbs.

Your HTML

<div class="items">
  <div class="item">
    <img src="http://lorempixel.com/100/100/sports">
  </div>
  <div class="item">
    <img src="http://lorempixel.com/100/100/food">
  </div>
  <div class="item">
    <img src="http://lorempixel.com/100/100/cities">
  </div>
  <div class="item">
    <img src="http://lorempixel.com/100/100/nature">
  </div>
</div>

Your CSS

#mygrid .items  {
   background-color: red;
   grid-area: images;
   display: grid;
   grid-template-columns: 100px 200px;
   grid-template-rows: 100px 100px auto;
   grid-template-areas: 
                        "thumbs main"
                        "thumbs main"
                        "thumbs main"
   ;
}

.item {
   grid-area: thumbs;
}

.item:first-child  {
   grid-area: main;
}

.item img {
   width: 100px;
   height: auto;
}

.item:first-child img {
   width: 200px;
   height: auto;
}

Here's what's happening

  • The first image container is named main, overriding thumbs. This container is placed in the second column, in accordance with your grid-template-areas rule.
  • The second, third and fourth image containers are named thumbs. Because all three elements have the same name, the first two are ignored and the last one is rendered (per the rules of HTML parsing, which is based generally on the order of appearance in the source document).
  • So, ultimately, there are no overlapping images. What you're getting is image1 in the second column and image4 in the first column.
  • image1 is taller than image4 because it has double the width (per your CSS).

Solution

Give each item a unique grid area name.

#mygrid {
 display: grid;
 grid-template-columns: 300px 1fr;
 grid-template-rows: auto;
 grid-template-areas: 
  "images title"
  "images model"
  "images price"
  ;
}

.items {
 background-color: red;
 grid-area: images;
 display: grid;
 grid-template-columns: 100px 200px;
 grid-template-rows: 100px 100px auto;
 grid-template-areas: 
              "thumbs2 main"
              "thumbs3 main"
              "thumbs4 main"    
  ;
}

.item:first-child   { grid-area: main; }
.item:nth-child(2)  { grid-area: thumbs2; }
.item:nth-child(3)  { grid-area: thumbs3; }
.item:nth-child(4)  { grid-area: thumbs4; }

.item img {
 width: 100px;
 height: auto;
}

.item:first-child img {
 width: 200px;
 height: auto;
}
<div id="mygrid">
  <div class="items">
    <div class="item">
      <img src="http://lorempixel.com/100/100/sports">
    </div>
    <div class="item">
      <img src="http://lorempixel.com/100/100/food">
    </div>
    <div class="item">
      <img src="http://lorempixel.com/100/100/city">
    </div>
    <div class="item">
      <img src="http://lorempixel.com/100/100/nature">
    </div>
  </div>
  <div class=info>MY TITLE</div>
  <div class=info>My Description</div>
  <div class=prijs>My Price</div>
</div>

jsFiddle

2
On

OK, i found the reason for the weirdness.

In case anybody else runs into something similar:

The HTML elements that will be placed in the grid all need to be on the same level in the DOM and be a direct descendant of the grid-element.
When you have html elements in a html element in a grid element, you need to create a new grid element for the lower tier html elements.