CSS Borders, Unwanted Gaps and Sub-Pixel Rendering Issues

Viewed 227

I'm designing a blog post preview tile for my personal website. Whatever I try to do, there is always a gap between the image and its own bottom border, or a gap between the image and the border of the container. It appears on mobile, when zooming, and when scaling. It's a really simple design and I'm going crazy and can't figure out how to get it to work. I know it's related to sub pixel rendering issues. Please help me! I would either like the gap gone or to render as the same color as the border so it doesn't look jank.

body {
    background: rgba(255, 225, 172, 1);
    display: grid;
    grid-template-rows: [row-start] 1fr [row-end row2-start] 6fr [row2-end row3-start] 1fr [row3-end];
    grid-template-columns: [col-start] 1fr [col-end];
    row-gap: 60px;
    padding-left: 120px;
    padding-right: 120px;
}

.blog_preview_container {
    grid-row: 2;
    grid-column: 1;
    height: 354px !important;
    display: flex;
    flex-flow: row wrap;
    justify-content: space-between;
}

.blog_preview_titlecard {
    height: 352px;
    width: 272px;
}

.blog_tile {
    height: 340px !important;
    width: 240px !important;
    margin: 1px;
    background-color: white;
    border: 6px solid black;
    box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.65);
    color: white;
    display: inline;
    overflow: hidden;
    cursor: pointer;
    transform: scale(1);
}

.blog_tile:hover {
    transform: scale(1.05);
}

.blog_tile_image {
    display: block;
    border-bottom: 6px solid black;
}

.blog_tile_text {
    height: 138px;
    font-family: 'nunito', sans-serif;
    font-size: 1rem;
    font-weight: 900;
    margin: 0;
    padding: 16px;
}
<body>
  <div class="blog_preview_container">
    <img class="blog_preview_titlecard" src="https://example.com/titlecard_location">
    <div class="blog_tile">
      <img class="blog_tile_image" src="https://example.com/img_location">
      <p class="blog_tile_text">Text Goes Here</p>
    </div>
  </div>
</body>

4 Answers

I play with this image and it seems like you can just change the background-color of your blog_tile as black will remedy it.

body {
    background: rgba(255, 225, 172, 1);
    display: grid;
    grid-template-rows: [row-start] 1fr [row-end row2-start] 6fr [row2-end row3-start] 1fr [row3-end];
    grid-template-columns: [col-start] 1fr [col-end];
    row-gap: 60px;
    padding-left: 120px;
    padding-right: 120px;
}

.blog_preview_container {
    grid-row: 2;
    grid-column: 1;
    height: 354px !important;
    display: flex;
    flex-flow: row wrap;
    justify-content: space-between;
}

.blog_preview_titlecard {
    height: 352px;
    width: 272px;
}

.blog_tile {
    height: 340px !important;
    width: 240px !important;
    margin: 0px;
    border: 6px solid black;
    box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.65);
    color: white;
    background-color: white;

}

.blog_tile:hover {
    transform: scale(1.05);
    margin-top: 0px;
    background-color: black;
}

.blog_tile img {    
    height: 340px;
    width: 242px;
    object-fit: cover;
    margin: -1px 0px 0px -1px;
    
    }

.blog_tile_image {
    display: block;
    border-bottom: 6px solid black;
}

.blog_tile_text {
    height: 138px;
    font-family: 'nunito', sans-serif;
    font-size: 1rem;
    font-weight: 900;
    margin: 0;
    padding: 16px;
    color: white;
}
<body>
  <div class="blog_preview_container">
    <img class="blog_preview_titlecard" src="https://media.istockphoto.com/photos/picturesque-morning-in-plitvice-national-park-colorful-spring-scene-picture-id1093110112?k=20&m=1093110112&s=612x612&w=0&h=3OhKOpvzOSJgwThQmGhshfOnZTvMExZX2R91jNNStBY=">
    <div class="blog_tile">
      <img class="blog_tile_image" src="https://media.istockphoto.com/photos/picturesque-morning-in-plitvice-national-park-colorful-spring-scene-picture-id1093110112?k=20&m=1093110112&s=612x612&w=0&h=3OhKOpvzOSJgwThQmGhshfOnZTvMExZX2R91jNNStBY=">
      <p class="blog_tile_text">Text Goes Here</p>
    </div>
  </div>
</body>

Here's a stripped down example that doesn't involve hard-coding any colors. It uses an absolutely positioned psuedo-element with a border that is overlaid above the image. The container is given a padding amount that is 1px smaller than the border width so it is rendered underneath it. The bottom border of the <img> is then relocated to the top of the <p> below it and the image is given a bottom margin of -1px.

*, *::after, *::before { box-sizing: border-box; }

body {
  background: rgba(255, 225, 172, 1);
  display: grid;
  align-items: center;
  justify-content: center;
}

.blog_tile {
  position: relative;
  display: grid;
  grid-template-rows: max-content 1fr;
  height: 340px;
  width: 240px;
  padding: 5px;
  background-color: white;
  box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.65);
  color: white;
  cursor: pointer;
  overflow: hidden;
}

.blog_tile::after {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  border: 6px solid black;
}

.blog_tile:hover {
  transform: scale(1.05);
}

.blog_tile img {
  display: block;
  margin-bottom: -1px;
  object-fit: cover;
  line-height: 0;
  white-space: collapse;
}

.blog_tile p {
  margin: 0; padding: 3px;
  border-top: 6px solid black;
  color: black;
}
<div class="blog_tile">
  <img src="https://picsum.photos/300">
  <p> TESTING </p>
</div>

Try this may be it will help.

img {
    object-fit: contain;
}

I fixed this by having the tile background color match the border color, and then setting the background of the text with my script instead of background color of the tile. That way when gaps are created it matches the border color and doesn't look weird. Now it looks correct at all scales. it doesn't handle non-cropped images but all the images pulled are autocropped to the correct size in my PHP.

window.onload = () => {
        var colors = ['#ffffff', '#ffbd4b', '#ff634b', '#4b9fff'];
        var nowhitecolors = ['#ffbd4b', '#ff634b', '#4b9fff'];
        document.querySelectorAll('.blog_tile').forEach(
            el => {
                        var randcolor = colors[Math.floor(Math.random() * colors.length)];
                        el.style.backgroundColor = '#ffffff';
                        el.children[1].style.backgroundColor = randcolor;
                        if (randcolor ==='#ffffff') {
                                var randnowhitecolors = nowhitecolors[Math.floor(Math.random() * nowhitecolors.length)];
                                el.style.borderColor = randnowhitecolors;
                                el.children[0].style.borderColor = randnowhitecolors;
                                el.style.backgroundColor =randnowhitecolors;
                                el.style.color = randnowhitecolors;
                        };
                }
        );

};
.blog_preview_container {
    grid-row: 2;
    grid-column: 1;
    height: 354px;
    display: flex;
    flex-flow: row wrap;
    justify-content: center;
    column-gap: 40px;
    row-gap: 40px;
}

.blog_tile {
    height: 340px;
    width: 240px;
    margin-top: 0px;
    border-width: 6px;
    border-style: solid;
    border-radius: 6px;
    box-shadow: 4px 4px 6px rgba(0, 0, 0, 0.65);
    color: white;
    display: inline;
    cursor: pointer;
    transform: scale(1);
}

.blog_tile:hover {
    transform: scale(1.04);
}

.blog_tile img {
    height: 164px;
    width: 240px;
    padding: 0px;
    margin: 0px;
    object-fit: cover;
    border-bottom-width: 6px;
    border-bottom-style: solid;
}

.blog_tile p {
    height: 138px;
    font-family: 'nunito', sans-serif;
    font-size: 1rem;
    font-weight: 900;
    line-height: 22px;
    margin: 0;
    padding: 16px;
}
<body>
  <div class="blog_preview_container">
    <div class="blog_tile">
      <img class="blog_tile_image" src="https://example.com/img_location">
      <p class="blog_tile_text">Text Goes Here</p>
    </div>
  </div>
</body>

Looks great at all screen sizes, no more gaps!

Related