Creating a background-image gradient triangle that is horizontally centered - html

I want to create a triangle pointing down in css by using clip-path: polygon(...) and apply a gradient on it using background-image: linear-gradient(...).
This all works fine but I need this shape as the background of my web page.
It needs to always be centered and it needs to clip/cut off the left and right edges that do not fit in the browser window. The triangle should not re-scale itself; I want to preserve the steepness of the triangle's edges and the height of the triangle should not change:
As illustrated, the triangle should stay the same width and height even when the browser window is too small to contain it.
So far I have:
div.main-background {
position: absolute;
z-index: -1;
top: 0;
height: 500px;
width: 100%;
background-image: linear-gradient(to bottom, #65AAB0, #AEE2B6);
background-attachment: fixed;
background-position-x: center;
background-size: 1400px 500px;
clip-path: polygon(50% 80%, 0 0, 1400px 0);
}
<div class="main-background"></div>
but this is clearly wrong.

You can do this with SVG
html,
body {
margin: 0
}
svg {
width: 100%;
}
<svg viewBox="0 0 1920 400" height="400" preserveAspectRatio="xMidYMax slice">
<defs>
<linearGradient id="Gradient1" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="#65AAB0"></stop>
<stop offset="100%" stop-color="#AEE2B6"></stop>
</linearGradient>
</defs>
<polygon points="0,0 960,400 1920,0" fill="url(#Gradient1)"></polygon>
</svg>

Using viewport units, is this what you want? Works on any resolution.
div.main-background {
position: absolute;
z-index: -1;
top: 0;
left: 0;
right: 0;
height: 35.71vw;
background-image: linear-gradient(to bottom, #65AAB0, #AEE2B6);
background-attachment: fixed;
background-position: center;
clip-path: polygon(50% 80%, 0 0, 100vw 0);
}
<div class="main-background"></div>

You can try multiple background like below. I made the triangle to have a width of 600px and a height of 300pxthat you can easily adjust.
body {
background:
linear-gradient(to bottom right,transparent 49.8%,#fff 50%) calc(50% + 150px) 0 /300px 300px,
linear-gradient(to bottom left, transparent 49.8%,#fff 50%) calc(50% - 150px) 0 /300px 300px,
linear-gradient(to bottom, #65AAB0, #AEE2B6)top center/ 600px 300px;
background-repeat:no-repeat;
}
Easier with CSS variable :
body {
--w:800px;
--h:300px;
background:
linear-gradient(to bottom right,transparent 49.8%,#fff 50%) calc(50% + calc(var(--w)/4)) 0 /calc(var(--w)/2) var(--h),
linear-gradient(to bottom left, transparent 49.8%,#fff 50%) calc(50% - calc(var(--w)/4)) 0 /calc(var(--w)/2) var(--h),
linear-gradient(to bottom, #65AAB0, #AEE2B6)top center/ var(--w) var(--h);
background-repeat:no-repeat;
}

You are going about it the wrong way. Your div contains no content and is thus simply decorative cruft. If you want a page background of certain appearance, then whatever appearance the background should have, goes into the background property of the document element (typically body, or html).
Get rid of your useless div.main-background which serves no purpose whatsoever, and use the following background image, either standalone (in its own SVG file) or inline using a data: URI:
<?xml version="1.0" ?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1">
<polygon fill="lime" points="0,0 0.5,0.4 1,0" />
</svg>
The following CSS declaration will use the above as a background image, from your explanation the background size should be a definite length (as opposed to one relative to viewport dimensions), I will use 40em because I didn't pick any clues from your question:
body {
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1"><polygon fill="lime" points="0,0 0.5,0.4 1,0" /></svg>');
background-size: 40em;
background-repeat: no-repeat;
background-position: top center;
}
Alternatively, you can use a standalone SVG file, then your background rule will be different:
background: url(<URL-of-SVG-file>);
You can add the gradient easily by editing SVG content, it's a basic SVG feature, one of the other answers here even demonstrates how.

Maybe you can use that kind of trick with just CSS and an after pseudo-element:
body {
overflow: hidden;
}
.arrow-down {
--w:800px;
--h:300px;
position: relative;
width: var(--w);
height: var(--h);
margin-left: 50%;
transform: translate(-50%, 0);
background-image: linear-gradient(to bottom, #65AAB0, #AEE2B6);
}
.arrow-down::after{
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border: solid white;
border-width: calc(var(--h)/2) calc(var(--w)/2);
border-top-color: transparent;
}
<body>
<div class="arrow-down"></div>
</body>
Of course, you can tweak width and height to better suit your needs.

Related

Border-radius failed to round clipped div corners [duplicate]

I want to be able to round out the 3 leftmost corners on this shape that I have created, any idea how that can be done?
div {
position: absolute;
z-index: 1;
width: 423px;
height: 90px;
background-color: #b0102d;
color: white;
right: 0;
margin-top: 10vw;
-webkit-clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}
<div></div>
use inset with round property :
inset(0% 45% 0% 45% round 10px)
An SVG filter can round any kind of clip-path. You simply need to apply it to a parent element. Adjust the stdDeviation to control the radius:
.box {
width: 423px;
height: 90px;
background-color: #b0102d;
color: white;
clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}
.parent {
filter: url('#goo');
overflow:hidden;
position: fixed;
right:-50px;
z-index: 1;
margin-top: 10vw;
}
<div class="parent">
<div class="box"></div>
</div>
<svg style="visibility: hidden; position: absolute;" width="0" height="0" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="goo"><feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9" result="goo" />
<feComposite in="SourceGraphic" in2="goo" operator="atop"/>
</filter>
</defs>
</svg>
Related: https://stackoverflow.com/a/65485455/8620333
I've recently found success experimenting with approaches like this...
SVG
<svg width="0" height="0">
<defs>
<clipPath id="clipped">
<circle cx="var(--myRad)" cy="var(--myRad)" r="var(--myRad)"></circle>
<circle cx="var(--myRad)" cy="calc(var(--myHeight) - var(--myRad))" r="var(--myRad)"></circle>
<circle cx="calc(var(--myWidth) - var(--myRad))" cy="calc(var(--myHeight) - var(--myRad))" r="var(--myRad)"></circle>
<circle cx="calc(var(--myWidth) - var(--myRad))" cy="var(--myRad)" r="var(--myRad)"></circle>
<rect y="var(--myRad)" width="var(--myWidth)" height="calc(var(--myHeight) - (2 * var(--myRad)))"></rect>
<rect x="var(--myRad)" width="calc(var(--myWidth) - (2 * var(--myRad)))" height="var(--myHeight)"></rect>
</clipPath>
</defs>
</svg>
CSS
.clipped {
--myWidth: 100vw;
--myHeight: 10rem;
--myRad: 2rem;
clip-path: url(#clipped);
}
I found this useful as compared to using border-radius with overflow set to hidden, because this approach doesn't create a BFC or break things like sticky position and css perspective effects. Also, this allows you to "inset" the position of the svg paths to clip inside the element with a "corner-radius" if you want.
You can also mess around with the circle to get some different effects.
-webkit-clip-path: circle(60.0% at 50% 10%);
clip-path: circle(50.0% at 50% 50%);
Codepen
Too bad you can't combine the polygon and circle... or maybe you can and I haven't played around with it enough to figure it out. HTH
clip-path: inset(45% 0% 33% 10% round 10px)
I don't have a comment option yes, so I'm writing it as an answer..
you need to write as many points as possible to round the corner. Nothig else...
for, example a few more points to make lower part bit rounder:
-webkit-clip-path: polygon(100% 0%, 100% 100%, 100% 100%, 25% 100%, 5% 70%,1% 60%, 0% 50%, 25% 0%);
oh, yes, or SVG as comment people here.. :)
You could use a child element and do a nested clip-path on that and the child's pseudo element. The parent will do a polygon clip on the shape first, then the pseudo will have an ellipse to round the borders. The clips will have a combined effect.
.parent, .parent div, .parent div:before {
width: 423px;
height: 90px;
position: absolute;
}
.parent {
right: 0;
background-image: linear-gradient(to right, transparent 210px, #b0102d 210px);
margin-top: 15vh;
}
.parent div {
clip-path: polygon(100% 0%, 100% 100%, 25% 100%, 0 50%, 25% 0);
}
.parent div:before {
content: "";
background-color: #b0102d;
clip-path: ellipse(200px 45px at 210px);
}
<div class="parent">
<div></div>
</div>
Here is the demo with some adaptations to illustrate what's going on:
.parent, .parent div, .parent div:before {
width: 423px;
height: 90px;
position: absolute;
}
.parent {
right: 0;
background-image: linear-gradient(to right, transparent 210px, yellow 210px);
margin-top: 15vh;
}
.parent div {
background-color: blue;
clip-path: polygon(90% 0%, 90% 100%, 25% 100%, 0 50%, 25% 0);
}
.parent div:before {
content: "";
background-color: #b0102d;
clip-path: ellipse(200px 45px at 210px);
}
<div class="parent">
<div></div>
</div>
The horizontal size and position of the ellipse can be used to get a different effect on the edges. Note that the background starting postion of the parent needs to be adjusted to the same value as the placement of the ellipse (last value in the clip-path) because it fills up whatever gets clipped off on the right side. This can be visualised by removing background-color: blue from .parent div in the second demo.
Here is an additional Codepen to to try it out.

Creating a Diagonal Mask Effect

I'm wondering how I would go about creating a diagonal mask like effect. The mask would show all in the top left corner, hide the middle part, then show all in the bottom right corner. In the example, the mask would be on the .container element and mask out any children in the div as well.
I've looked at resources online, specifically here, and can't get this effect to work on non-image elements. Is there a different type of property to use in CSS to achieve this effect? I was thinking maybe SVG, but I'd like it to adapt to the width and height of the element, and wasn't sure how to pull that off.
JS Fiddle
.container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
mask: gradient(linear, left top, right bottom,
color-stop(0.00, rgba(0,0,0,1)),
color-stop(0.35, rgba(0,0,0,1)),
color-stop(0.50, rgba(0,0,0,0)),
color-stop(0.65, rgba(0,0,0,1)),
color-stop(1.00, rgba(0,0,0,1)));
}
.shape {
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
background: red;
}
<div class="container">
<div class="shape"></div>
</div>
The mask would look something like this image.
Maybe so?
.container {
width:50%;
height:50%;
}
.rect1 {
fill: url('#grad1');
}
<div class="container">
<svg class="the-svg" viewBox="0 0 200 200" >
<defs>
<linearGradient id="grad1" x1="0" x2="1.0" y1="0" y2="1.0" >
<stop offset="0%" stop-color= "white"/>
<stop offset="35%" stop-color="white"/>
<stop offset="50%" stop-color="black"/>
<stop offset="65%" stop-color="white"/>
<stop offset="100%" stop-color="white"/>
</linearGradient>
</defs>
<rect class="rect1" x="0" y="0" width="100%" height="100%" />
</svg>
</div>
The solution is adaptive and works in all browsers, including Edge
Using mask-image works here. Updated JSFiddle.
.container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
-webkit-mask-image: linear-gradient(-45deg, black 0%, transparent 35% , transparent 50%, transparent 65%, black 100%);
mask-image: linear-gradient(-45deg, black 0%, transparent 35% , transparent 50%, transparent 65%, black 100%);
}

CSS: Custom shape having angled borders

I have a custom fancy footer created with html and css. See it here: https://jsfiddle.net/fb6qdvrw/
To create the triangles I use :before and :after like this:
#footer .layer-4.bg-secondary:before {
content: '';
position: absolute;
top: 0;
right: 0;
left: 100%;
border-top: 120px solid transparent;
border-left: 120px solid #FFFFFF;
width: 0;
}
#footer .layer-4.bg-secondary:after {
content: '';
position: absolute;
top: 10px;
right: 0;
left: 100%;
border-top: 120px solid transparent;
border-left: 120px solid #ffcf87;
width: 0;
}
The problem I want to solve is the white line / border thickness. I need it to have the same thickness for diagonal and horizontal line. Is this possible in my case? I see I am limited to triangles and rectangles, but I think there must be a solution. For the moment my fancy footer is ugly because of this.
CSS Based Approaches:
Below are a couple of pure CSS based methods to create this shape:
1 - Skewed Transformation:
You can create this shape by using CSS3 skew() transformations.
Required HTML:
All we need is 2 elements inside footer i.e:
<div class="footer">
<div class="top"></div>
<div class="bottom"></div>
</div>
We will then use ::before and ::after pseudo elements for each child element to draw skewed overlays on the respective element:
Output:
Working Example:
body {margin: 0;}
.footer {
position: relative;
padding-top: 100px;
overflow: hidden;
}
.top,
.bottom {
position: relative;
height: 50px;
}
.bottom {
margin-top: 10px;
}
.top::before {
transform-origin: left top;
transform: skew(45deg);
position: absolute;
background: green;
height: 100px;
width: 145px;
content: '';
top: 100%;
right: 0;
}
.bottom:before {
transform-origin: right bottom;
transform: skew(45deg);
position: absolute;
background: blue;
height: 150px;
bottom: 100%;
width: 95px;
content: '';
left: 0;
}
.top::after,
.bottom::after {
transform-origin: left bottom;
transform: skew(45deg);
position: absolute;
background: green;
right: -100px;
left: 100px;
content: '';
bottom: 0;
top: 0;
}
.bottom:after {
transform-origin: right bottom;
background: blue;
right: 100px;
left: -100px;
}
<div class="footer">
<div class="top">
</div>
<div class="bottom">
</div>
</div>
2- Linear-Gradient:
In this approach we will use CSS linear-gradient() function to draw this shape on the element as a background. As we can apply multiple background images on an element so we will divide this shape in small parts and draw them on the element with precisely controlled sizes and positions.
We can divide this shape in 4 parts and draw them each having specific size and position.
Below is a step by step procedure to create this shape:
Required HTML:
We need only one block level element (div) possibly having some class i.e:
<div class="shape"></div>
Step 1:
First of all, lets try to create the long skewed shape on the bottom of the element.
Necessary CSS:
div {
background-image: linear-gradient(-135deg, transparent 50px, blue 50px);
background-repeat: no-repeat;
background-size: 100% 50px;
background-position: right 75px bottom;
}
We will have the following output:
Step 2:
Now we will draw the large triangular shape on the left bottom:
Necessary CSS:
div {
background-image: linear-gradient(-135deg, transparent 50px, blue 50px),
linear-gradient(-135deg, transparent 135px, blue 135px);
background-size: 100% 50px, 180px 200px;
background-position: right 75px bottom, left bottom;
}
This will create the following output:
Step 3:
Now we will draw the upper triangular bar with following CSS:
div {
background-image: linear-gradient(-135deg, transparent 50px, blue 50px),
linear-gradient(-135deg, transparent 135px, blue 135px),
linear-gradient(45deg, transparent 50px, green 50px);
background-size: 100% 50px, 180px 200px, 100% 50px;
background-position: right 75px bottom, left bottom, left 75px bottom 60px;
}
And we will have the following output:
Step 4:
Finally, we will draw the right bottom triangular image:
div {
background-image: linear-gradient(-135deg, transparent 50px, blue 50px),
linear-gradient(-135deg, transparent 135px, blue 135px),
linear-gradient(45deg, transparent 50px, green 50px),
linear-gradient(45deg, transparent 50px, green 50px);
background-size: 100% 50px, 180px 200px, 100% 50px, 150px 100px;
background-position: right 75px bottom, left bottom, left 75px bottom 60px, right bottom;
}
This will create the following shape:
Working Example:
div {
background-image: linear-gradient(-135deg, transparent 50px, blue 50px),
linear-gradient(-135deg, transparent 135px, blue 135px),
linear-gradient(45deg, transparent 50px, green 50px),
linear-gradient(45deg, transparent 50px, green 50px);
background-repeat: no-repeat;
background-size: 100% 50px, 180px 200px, 100% 50px, 150px 100px;
background-position: right 75px bottom, left bottom, left 75px bottom 60px, right bottom;
height: 200px;
}
<div class="shape"></div>
SVG Based Approach:
Polygon Shape:
We can use SVG's polygon element to draw this shape as well:
polygon element draws a closed shape by connecting straight line segments. This element takes single points argument which contains a list of points
Necessary Code:
<svg width="400" height="140" viewBox="0 0 400 140">
<polygon points="0,0 80,100 300,100 330,140 0,140" />
<polygon points="53,50 85,90 305,90 343,140 400,140 400,50" />
</svg>
Working Example:
body {margin: 0;}
svg {
height: auto;
width: 100%;
}
<svg width="400" height="140" viewBox="0 0 400 140">
<polygon points="0,0 80,100 300,100 330,140 0,140" fill="blue" />
<polygon points="53,50 85,90 305,90 343,140 400,140 400,50" fill="green" />
</svg>
Useful Resources:
CSS3 Transforms: Specs, MDN
Linear Gradient: Specs, MDN
SVG: Specs, MDN

How to accomplish this shape with angled cuts at the bottom and an image background in CSS?

I have read up on various methods and played with the Clippy tool, the problem is the browser support just isn't there yet. What would be the best method for accomplishing the look of the image below with CSS? I am trying to add a shape as bottom-border as you can see in the image below right after the blue background image. Is there a way I can do this that most recent major browsers support through CSS?
What I've tried (doesn't seem to work in Chrome and others):
.element {
-webkit-clip-path: polygon(50% 0%, 100% 0, 100% 86%, 75% 100%, 0 85%, 0 0);
clip-path: polygon(50% 0%, 100% 0, 100% 86%, 75% 100%, 0 85%, 0 0);
}
The desired result would look something like:
Both dippas' answer and the demo in misterManSam's comment are good but they would work only if the page background is a solid color (which can then be used as border's color or within the gradient). They would run into problems when the page's background is either an image (or) a gradient and they should show through the cutout portion of the shape.
For such cases I would recommend using SVG instead of CSS because it is so complex to create it with CSS that it is not actually worth the effort. Though you've asked for CSS, I will detail these SVG methods here just in case you want to use them (or atleast some future readers might find it helpful).
With SVG:
With SVG we can either create a path and fill it with the image (or) use a SVG mask for creating the shape. (Note: CSS clip-path using SVG is still a no-go due to lack of support in IE.)
Below snippet uses SVG path element to create the shape and then fill it with the image.
svg {
height: 200px;
width: 100%;
}
path {
fill: url(#image);
}
/* Just for demo */
path:hover{
cursor: pointer;
}
body {
min-height: 100vh;
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<svg viewBox='0 0 1024 200' preserveAspectRatio='none'>
<defs>
<pattern id='image' height='200' width='1024' patternUnits='userSpaceOnUse'>
<image xlink:href='http://lorempixel.com/1024/200/nature/3' height='200' width='1024' />
</pattern>
</defs>
<path d='M0,0 1024,0 1024,150 716.8,200 0,150z' />
</svg>
The following snippet uses SVG mask. The difference between using a path with an image fill and a mask is the hover area. With a path the hover effects are restricted to the shape boundary whereas with a mask, the image is still a rectangle (or square) and so hover effects are triggered even outside.
svg {
height: 200px;
width: 100%;
}
image {
mask: url(#masker);
}
/* Just for demo */
image:hover{
cursor: pointer;
}
body {
min-height: 100vh;
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<svg viewBox='0 0 1024 200' preserveAspectRatio='none'>
<defs>
<mask id='masker' x='0' y='0' width='1024' height='200'>
<polygon points='0,0 1024,0 1024,200 0,200z' fill="#fff" />
<path d='M0,150 716.8,200 1024,150 1024,200 0,200z' fill="#000" />
</mask>
</defs>
<image xlink:href='http://lorempixel.com/1024/200/nature/3' height='200' width='1024' />
</svg>
With CSS:
The below option is our best bet with pure CSS but unfortunately it has poor browser support. It uses CSS linear-gradient as mask images to hide the portions that are not required. This method works only in Webkit powered browsers for now and so is a no-go.
.shape {
height: 200px;
width: 100%;
background-image: url(http://lorempixel.com/1200/200/nature/3);
-webkit-mask-image: linear-gradient(to top right, transparent 49.5%, white 50.5%), linear-gradient(to top left, transparent 49.5%, white 50.5%), linear-gradient(white, white);
mask-image: linear-gradient(to top right, transparent 49.5%, white 50.5%), linear-gradient(to top left, transparent 49.5%, white 50.5%), linear-gradient(white, white);
-webkit-mask-size: 70.5% 30%, 30% 30%, 100% 70%;
-webkit-mask-position: bottom left, bottom right, top left;
-webkit-mask-repeat: no-repeat;
}
body {
min-height: 100vh;
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<div class='shape'></div>
Other attempts to produce a transparent cut run into problems if the shape has to be responsive. For example, the below snippet uses very complex transformations, positioning etc to achieve this shape but it is not responsive (view in full page mode). I wouldn't have recommended this method even if the shape was responsive (due to complexities involved) but the lack of responsiveness means this is a no-go.
.shape {
position: relative;
height: 200px;
width: 100%;
overflow: hidden;
}
.shape-left,
.shape-right,
.shape img {
position: absolute;
height: 100%;
}
.shape-left {
width: 75%;
transform: skewY(5deg);
overflow: hidden;
}
.shape-left img {
top: -7%;
bottom: 0px;
width: 133.3%;
transform: skewY(-5deg);
}
.shape-left,
.shape-left img {
transform-origin: bottom right;
backface-visibility: hidden;
}
.shape-right {
right: 0%;
width: 25%;
transform: skewY(-10deg);
overflow: hidden;
}
.shape-right img {
top: -13.5%;
left: -300%;
width: 400%;
transform: skewY(10deg);
}
.shape-right {
transform-origin: bottom left;
backface-visibility: hidden;
}
/* just for demo */
.reference {
height: 200px;
width: 100%;
}
.reference img {
height: 100%;
width: 100%;
}
* {
box-sizing: border-box;
}
body {
min-height: 100vh;
background-image:radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<div class='shape'>
<div class='shape-left'>
<img src='http://lorempixel.com/800/200/nature/3' />
</div>
<div class='shape-right'>
<img src='http://lorempixel.com/800/200/nature/3' />
</div>
</div>
<hr>
<div class='reference'>
<img src='http://lorempixel.com/800/200/nature/3' />
</div>
Note: This may have been the item that misterManSam was referring to in comments but I feel the needs are a bit different here even though both involve creating unusual borders.
you can use a background-image on a div and two shapes using it pseudo-selectors :before/:after
Something like this:
.bg {
background: url(http://lorempixel.com/1600/900) no-repeat center top;
min-height: 100px;
min-width: 200px;
position: relative
}
.bg:before {
content: "";
border-bottom: 65px solid white;
border-right: 575px solid rgba(0, 0, 0, 0);
position: absolute;
left: 0;
bottom: 0;
}
.bg:after {
content: "";
border-bottom: 65px solid white;
border-left: 200px solid rgba(0, 0, 0, 0);
position: absolute;
right: 0;
bottom: 0;
}
<div class="bg"></div>
I think the easiest way to do it is with pseudo elements on the parent div element. This is basic CSS knowledge and can be implemented very easily. The parent div needs to have the position: relative; property set and the rest is done by the ::before and ::after elements.
.background::before {
transform: rotate(10deg);
position: absolute;
}
Example
Hope this helps.

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.
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.
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>