Search code examples
htmlcssimageborderclip-path

Borders of divs shaped as a polygon (with clip-path in CSS) with a background image


I have a simple 100vw-100vh page with 3 images in the background for mobile, and 5 in a different set-up for larger viewports. The way I have it set-up so far:

  • 3 (or 5) div containers, clipped as a polygon in CSS
  • the images set as background-image of each container in CSS, with background-size: cover.

This works fine to display the images, but when I try to add borders to the containers the clipped sides won't get the border, only the "original" bits would (as in, of the sides of the rectangles before clipping).

Is there a way to add them all around?

Note: I have played with background-origin without result. The whole page is set-up with box-sizing: border-box; but it does not seem to impact the result either.

Codepen of my code, for the mobile version (3 images) below.

Many thanks for your help!

PS: I have seen a couple of posts related to the topic to an extent, but not with the background image set-up the same way, and as they were all a bit old I thought wider browser support may help #hope. Sorry for any redundancy I would have missed!

https://codepen.io/aguafresca/pen/abNvyXO?editors=1100

<body> <main>
  <welcome-page>    
    <contacto-link>
      <p>contact details</p>
      </contacto-link>
    </welcome-page>

<background-container id="cont1" class=""></background-container>
<background-container id="cont2" class=""></background-container>
<background-container id="cont3"></background-container>

</main> </body>

CSS:

/* general set-up */
html {
  width: 100vw;
  height: 100vh;
  box-sizing: border-box;
}
*, *:before, *:after, a, main, body {
  box-sizing: inherit;
  margin: 0;
  padding: 0;
}
    
/* setting-up the background */
welcome-page {
  z-index: 2;
  height: 100vh;
  width: 100vw;
  position: absolute;
  top:0;
  left:0;
  background-color: rgba(255, 255, 255, 0.3);
}
background-container {
  display: block;
  z-index: 1;
  position: absolute;
  background-color: dimgray;
  background-size: cover;
  border: red solid 3px;
  background-origin: content-box;
}
#cont1 {
    top: 0;
    left: 0;
    height: 60vh;
    width: 70vw;
    clip-path: polygon(0 0, 100% 0, 0 100%);
    background-image: url("https://images.unsplash.com/photo-1596072181334-1adc75da7717?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ");
  }
  #cont2 {
    top: 0;
    left: 0;
    height: 100vh;
    width: 100vw;
    clip-path: polygon(70% 0, 100% 0, 100% 40%, 30% 100%, 0 100%, 0 60%);
    background-image: url("https://images.unsplash.com/photo-1595680337986-ce4862b497b9?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ");
  }
  #cont3 {
    bottom: 0;
    right: 0;
    height: 60vh;
    width: 70vw;
    clip-path: polygon(100% 0, 100% 100%, 0 100%);
    background-image: url("https://images.unsplash.com/photo-1595035848637-29bd22af4faf?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ");
    border-color: green;
    z-index:10;
  }

/* footer format */
contacto-link {
  display: block;
  position: fixed;
  bottom: 0;
  height: 5vh;
  width:100vw;
  line-height: 5vh;
  background-color: rgba(255, 255, 255, 0.8);
  color: dimgrey;
}

Solution

  • Using an extra wrapper you can consider drop-shadow to simulate the borders.

    Here is an example where I will not really and an extra wrapper but I will use pseudo element for the image:

    body {
      margin: 3px;
      height: calc(100vh - 6px);
      position: relative;
    }
    
    .background-container {
      z-index: 1;
      position: absolute;
      filter:
        drop-shadow(0px 3px 0px red) 
        drop-shadow(3px 0px 0px red) 
        drop-shadow(0px -3px 0px red) 
        drop-shadow(-3px 0px 0px red)
    }
    
    .background-container::before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-size: cover;
    }
    
    #cont1 {
      top: 0;
      left: 0;
      height: 60%;
      width: 70%;
    }
    
    #cont1::before {
      clip-path: polygon(0 0, 100% 0, 0 100%);
      background-image: url("https://picsum.photos/id/10/800/800");
    }
    
    #cont2 {
      top: 0;
      left: 0;
      height: 100%;
      width: 100%;
      z-index:2;
    }
    
    #cont2::before {
      clip-path: polygon(70% 0, 100% 0, 100% 40%, 30% 100%, 0 100%, 0 60%);
      background-image: url("https://picsum.photos/id/1011/800/800");
    }
    
    #cont3 {
      bottom: 0;
      right: 0;
      height: 60%;
      width: 70%;
    }
    
    #cont3::before {
      clip-path: polygon(100% 0, 100% 100%, 0 100%);
      background-image: url("https://picsum.photos/id/1074/800/800");
    }
    <div class="background-container" id="cont1"></div>
    <div class="background-container" id="cont2"></div>
    <div class="background-container" id="cont3"></div>

    And with different coloration:

    body {
      margin: 3px;
      height: calc(100vh - 6px);
      position: relative;
    }
    
    .background-container {
      z-index: 1;
      position: absolute;
      filter:
        drop-shadow(0px 3px 0px var(--c,red)) 
        drop-shadow(3px 0px 0px var(--c,red)) 
        drop-shadow(0px -3px 0px var(--c,red)) 
        drop-shadow(-3px 0px 0px var(--c,red))
    }
    
    .background-container::before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-size: cover;
    }
    
    #cont1 {
      top: 0;
      left: 0;
      height: 60%;
      width: 70%;
      --c:blue;
    }
    
    #cont1::before {
      clip-path: polygon(0 0, 100% 0, 0 100%);
      background-image: url("https://picsum.photos/id/10/800/800");
    }
    
    #cont2 {
      top: 0;
      left: 0;
      height: 100%;
      width: 100%;
      z-index:2;
    }
    
    #cont2::before {
      clip-path: polygon(70% 0, 100% 0, 100% 40%, 30% 100%, 0 100%, 0 60%);
      background-image: url("https://picsum.photos/id/1011/800/800");
    }
    
    #cont3 {
      bottom: 0;
      right: 0;
      height: 60%;
      width: 70%;
      --c:yellow;
    }
    
    #cont3::before {
      clip-path: polygon(100% 0, 100% 100%, 0 100%);
      background-image: url("https://picsum.photos/id/1074/800/800");
    }
    <div class="background-container" id="cont1"></div>
    <div class="background-container" id="cont2"></div>
    <div class="background-container" id="cont3"></div>