3

I am trying to create a grid of images that display descriptions over a faded-out version of the image when the user hovers over said image. My current progress can be seen below and at this JSFiddle.

div#grid-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: 25px;
  width: 95%;
  margin: 15px auto;
  
  div {
    margin: auto;
    overflow: hidden;
    // cursor: pointer;
    background-color: black;
    color: white;
    
    img {
      height: auto;
      max-width: 100%;
    }
    
    p {
      display: none;
      position: relative;
      padding: 0;
      top: -40px;
      left: 10px;
      margin: 0;
    }
    
    &:hover {
      
      img {
        opacity: 0.35;
      }
      
      p {
        display: block;
      }
    }
  }
}
<h2>Grid Test</h2>
<div id="grid-container">
  <div class="">
    <img src="http://i.imgur.com/kEmy7gp.jpg" alt="A Rock" />
    <p>A beautiful rock structure.</p>
  </div>
  <div class="">
    <img src="http://i.imgur.com/kEmy7gp.jpg" alt="A Rock" />
    <p>A beautiful rock structure.</p>
  </div>
  <div class="">
    <img src="http://i.imgur.com/kEmy7gp.jpg" alt="A Rock" />
    <p>A beautiful rock structure.</p>
  </div>
  <div class="">
    <img src="http://i.imgur.com/kEmy7gp.jpg" alt="A Rock" />
    <p>A beautiful rock structure.</p>
  </div>
  <div class="">
    <img src="http://i.imgur.com/kEmy7gp.jpg" alt="A Rock" />
    <p>A beautiful rock structure.</p>
  </div>
  <div class="">
    <img src="http://i.imgur.com/kEmy7gp.jpg" alt="A Rock" />
    <p>A beautiful rock structure.</p>
  </div>
  <div class="">
    <img src="http://i.imgur.com/kEmy7gp.jpg" alt="A Rock" />
    <p>A beautiful rock structure.</p>
  </div>
  <div class="">
    <img src="http://i.imgur.com/kEmy7gp.jpg" alt="A Rock" />
    <p>A beautiful rock structure.</p>
  </div>
</div>

As you can see in my example JSFiddle, what I am doing currently has these nasty black bars, as well as a resizing issue due to the relative placement popping up. I can get rid of the relative black bar using margin-bottom, but it still doesn't fix my issue with needless resizing.

Ideally, I would like to have an entire div over the image so I could position things within that div, but I have no idea how I could go about that without making a complete mess. I would like some assistance with how I could go about this logically with the following constraints:

  • I'd prefer to not use JavaScript, but I am not 100% against it. But certainly no frameworks.
  • I do not want to make the images background-images of my divs.
  • The images must be resizable. (though it may be worth noting that the initial size of the images is known)
Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
tedm1106
  • 127
  • 1
  • 10

3 Answers3

2

There are two reasons for the problem.

Problem #1: position: relative

Your paragraph element is being relatively positioned over the image.

div#grid-container div p {
    display: none;
    position: relative;
    padding: 0;
    top: -40px;
    left: 10px;
    margin: 0;
}

The problem is that relative positioning does not remove an element from the normal flow. Therefore, even though you're using top and left to position the text, the original space for the element remains in place (full explanation).

You need to remove the element from the normal flow so it doesn't occupy space in the container. Use position: absolute and make the parent the bounding box with position: relative.

div {
    margin: auto;
    overflow: hidden;
    background-color: black;
    color: white;
    position: relative;  /* new */

p {
    display: none;
    position: absolute; /* adjusted */
    padding: 0;
    bottom: 40px;       /* adjusted */
    left: 10px;
    margin: 0;
}

revised demo 1


Problem #2: vertical-align: baseline

Your image elements are children of grid items. This means they don't participate in grid layout. They exist in block layout, where inline-level elements are automatically given baseline alignment with the vertical-align property (source).

That's why there's a small gap underneath the images (full explanation).

To fix the problem, override the default with vertical-align: top.

img {
  height: auto;
  max-width: 100%;
  vertical-align: top;  /* new */
}

revised demo 2

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
1

What you could do, is using the :after property on the div to position a half transparent dark background on top of the image and make benefit of the usage of position: absolute; on the paragraph element. See below and this updated demo on JSFiddle. Read more about :after on MDN.

div {
    margin: auto;
    overflow: hidden;
    // cursor: pointer;
    color: white;
    position: relative;

    img {
      display: block;
      height: auto;
      max-width: 100%;
    }

    &:hover:after {
      position: absolute;
      display: block;
      content: '';
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
      background-color: rgba(0,0,0,.25);
    }

    p {
      display: none;
      position: absolute;
      padding: 0;
      bottom: 10px;
      left: 10px;
      margin: 0;
      z-index: 1;
    }
Roy
  • 7,811
  • 4
  • 24
  • 47
0

You should remove the background-color in the div and put it in the p, and set the display to block in the p with an opacity of 0, in hover change the opacity to 0.65, and add a padding-left to the p and reduce the margin top:

    div#grid-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: 25px;
  width: 95%;
  margin: 15px auto;

  div {
    margin: auto;
    overflow: hidden;
    // cursor: pointer;

    color: white;

    img {
      height: auto;
      max-width: 100%;
    }

    p {
      opacity: 0;
      position: relative;
      padding: 0;
      top: -20px;
      left: 0px;
      margin: 0;
      padding-left: 10px;
      background-color: black;
    }

    &:hover {

      img {
        opacity: 0.35;
      }

      p {
        opacity: 0.65;
      }
    }
  }
}

You could even play with the opacity of the image, I would put at least 0.75

janmbaco
  • 340
  • 4
  • 11