Petri
Petri

Reputation: 37

CSS Shape-outside with two images

I'm trying to get two images float next to each other with the shape-outside property. To be specific, I have two triangle-shaped .png images, which would make up a rectangle if put next to each other. Img1 should be on the left and Img2 on the right, and they're cut so that the diagonal goes from top right to bottom left.

With shape-outside I managed to get the text "hug" the diagonal border of the images, so something is working alright. The darn images just won't pop next to each other.

<style>
.myclass {
    height: auto;
    width: 100%;
}

.myclass img:first-child {
    -webkit-shape-outside: polygon(0 0, 0 100%, 100% 0);
    float: left;
    width: 80%;
    background-color: lightgray;
    -webkit-clip-path: polygon(0 0, 0 100%, 100% 0);
}

.myclass img:nth-child(2) {
    -webkit-shape-outside: polygon(100% 0, 100% 100%, 0 100%);
    float: right;
    width: 80%;
    background-color: lightgray;
    -webkit-clip-path: polygon(100% 0, 100% 100%, 0 100%);
}
</style>

<div class='myclass'>
    <img src='img/img1.png'>
    <img src='img/img2.png'>
</div>

<div class='myclass'>
    <img src='img/img1.png'>
    <img src='img/img2.png'>
</div>

I realize that I could achieve this by doing the image in Photoshop but for linking functionality I'd prefer them to stay as separate elements. Also, absolute positioning could work but that would require quite a lot of media queries as I want the site to be responsive and the amount of this kind of blocks varies and can be quite a few.

Upvotes: 1

Views: 1448

Answers (1)

Harry
Harry

Reputation: 89750

Reason:

The reason why they images don't pop up next to each other is because they both have width: 80%. The clip-path applied to the element will clip into the required shape and the shape-outside setting will make inline text wrap around based on the shape but neither of them will change the shape of the bounding box of the img elements (which will remain square/rectangular).

In the below screenshot, the darker overlay (on top of the image) is the shape created through shape outside setting whereas the lighter overlay (it is there above the image also but is invisible due to the darker overlay's presence) represents the bounding box of the element and it is still rectangular.

enter image description here

This means that both the images can't be placed on the same line and so the second will automatically get pushed below. They can never be set on the same line as long as their combined width is > 100%. When the width of the two img elements is set to 50%, we can see that both of them appear on same line and that inline text wraps around in accordance with the shape on either side. So, there is nothing actually wrong with the shape-outside or the clip-path.

.myclass {
  clear: both;
  height: auto;
  width: 100%;
}
.myclass img:first-child {
  float: left;
  width: 50%;
  background-color: lightgray;
  -webkit-shape-outside: polygon(0% 0%, 0% 100%, 100% 0%);
  -webkit-clip-path: polygon(0% 0%, 0% 100%, 100% 0%);
}
.myclass img:nth-child(2) {
  float: right;
  width: 50%;
  background-color: lightgray;
  -webkit-shape-outside: polygon(100% 0%, 100% 100%, 0% 100%);
  -webkit-clip-path: polygon(100% 0%, 100% 100%, 0% 100%);
}
<div class='myclass'>
  <img src='http://lorempixel.com/800/200/nature/1'>
  <img src='http://lorempixel.com/800/200/nature/2'>
  Lorem ipsum dolor sit amet, some very lengthy inline content which is added to demonstrate how the content wraps around in accordance with the shapes.
</div>


Solution 1: Absolute Positioning

One solution to your problem is to use absolute positioning (I did see your statement in question but it is still an option). But then there is no need for shape-outside property itself because there is nothing to wrap around.

.myclass {
  position: relative;
  height: auto;
  width: 100%;
}
.myclass img:first-child {
  position: absolute;
  width: 100%;
  background-color: lightgray;
  -webkit-clip-path: polygon(0% 0%, 0% 100%, 100% 0%);
}
.myclass img:nth-child(2) {
  position: absolute;
  right: 0px;
  width: 100%;
  background-color: lightgray;
  -webkit-clip-path: polygon(100% 0%, 100% 100%, 0% 100%);
}
<div class='myclass'>
  <img src='http://lorempixel.com/800/200/nature/1'>
  <img src='http://lorempixel.com/800/200/nature/2'>
</div>


Solution 2: SVG recommended

As Paulie_D had mentioned in comments, your best bet would be to use SVG if you don't want to use absolute positioning. While we would still need to give (x,y) coordinates for the image tags as though we are doing absolute positioning, SVGs are by default responsive (they auto-adapt) and so the need for responsiveness is handled implicitly.

svg image:nth-of-type(1) {
  -webkit-clip-path: url(#clipper-left);
  clip-path: url(#clipper-left);
}
svg image:nth-of-type(2) {
  -webkit-clip-path: url(#clipper-right);
  clip-path: url(#clipper-right);
}
svg {
  width: 100vw;
  height: 40vh;
}
body {
  margin: 0;
  padding: 0;
}
<svg viewBox='0 0 900 400' preserveAspectRatio="none">
  <defs>
    <clipPath clipPathUnits="objectBoundingBox" id="clipper-left">
      <path d="M0,0 1,0 0,1z" />
    </clipPath>
    <clipPath clipPathUnits="objectBoundingBox" id="clipper-right">
      <path d="M1,0 0,1 1,1z" />
    </clipPath>
  </defs>
  <image xlink:href="http://lorempixel.com/900/400/nature/1" x="0" y="0" height="400px" width="900px" />
  <image xlink:href="http://lorempixel.com/900/400/nature/2" x="0" y="0" height="400px" width="900px" />
</svg>

Upvotes: 1

Related Questions