Putting linear-gradient over an image - html

How exactly would I do this?
https://jsfiddle.net/4f2646gx/2/
What I want to do is place the linear gradient lines over the image.
What it looks like now:
The end result should look like this:
<style>
#img1 {
position: absolute;
clip-path: circle(85px at center);
top: 54%;
left: 72%;
transform: translate(-50%, -50%);
}
#img2 {
position: absolute;
top: 54%;
left: 72%;
transform: translate(-50%, -50%);
}
</style>
<div style="width: 260px; height: 194px; cursor: pointer;background-color: #000000 ;background-image: linear-gradient( to right,transparent 0, transparent 83px,#0059dd 83px, #0059dd 86px, transparent 86px, transparent 174px, #0059dd 174px, #0059dd 177px, transparent 177px,transparent 260px ); border: 3px solid #0059dd;">
<div style="position:relative; width:180px; height:180px">
<img id="img1" width="170" height="113" src="https://i.imgur.com/BO6KOvw.jpg">
<img id="img2" width="180" height="180" src="https://i.imgur.com/4HJbzEq.png">
</div>
</div>

I'd put all of it in one container, use absolute positioning to layer the elements. Also your background-color style of the gradient element needs to be transparent, otherwise you've got a black box with lines over your image and you can't see it. In this example, you'll also notice that border is moved to the top level container.
#container {
background-color: black;
position:relative;
width:260px;
height:194px;
padding: 0;
border: 3px solid #0059dd;
}
#img1,#img2 {
user-select: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#img1 {
clip-path: circle(85px at center);
}
#grad {
position: absolute;
top: 0;
left: 0;
width: 260px;
height: 194px;
cursor: pointer;
background-color: transparent;
background-image: linear-gradient( to right,transparent 0, transparent 83px,#0059dd 83px, #0059dd 86px, transparent 86px, transparent 174px, #0059dd 174px, #0059dd 177px, transparent 177px,transparent 260px );
}
<div id="container">
<img id="img1" width="170" height="113" src="https://i.imgur.com/BO6KOvw.jpg">
<img id="img2" width="180" height="180" src="https://i.imgur.com/4HJbzEq.png">
<div id="grad"></div>
</div>

To avoid adding any unnecessary markup, you can add a pseudo-element to your container div. Forked JSBin.
<style>
#img1, #img2 {
position: absolute;
top: 54%;
left: 72%;
transform: translate(-50%, -50%);
}
#img1 {
clip-path: circle(85px at center);
}
.circle-gradient {
width: 260px;
height: 194px;
cursor: pointer;
background-color: #000000;
border: 3px solid #0059dd;
position: relative;
}
.circle-gradient:before {
content: '';
position: absolute;
width: 100%;
height: 100%;
z-index: 2;
background-image: linear-gradient( to right,transparent 0, transparent 83px,#0059dd 83px, #0059dd 86px, transparent 86px, transparent 174px, #0059dd 174px, #0059dd 177px, transparent 177px,transparent 260px );
}
</style>
<div class="circle-gradient">
<div style="position:relative; width:180px; height:180px">
<img id="img1" width="170" height="113" src="https://i.imgur.com/BO6KOvw.jpg">
<img id="img2" width="180" height="180" src="https://i.imgur.com/4HJbzEq.png">
</div>
</div>

Because CSS FTW, you can use the background property to stack multiple images & gradients.
In this code snippet, background-size references each background applied : the last value (120px 120px) sets the size of the sky image.
The good news is that it is supported since IE9!
div{
background:
linear-gradient( to right,transparent 0, transparent 83px,#0059dd 83px, #0059dd 86px, transparent 86px, transparent 174px, #0059dd 174px, #0059dd 177px, transparent 177px,transparent 260px ),
url("https://i.imgur.com/4HJbzEq.png") no-repeat center,
url("https://i.imgur.com/BO6KOvw.jpg") no-repeat center;
background-size: auto, auto, 120px 120px;
width: 260px;
height: 194px;
border: 3px solid #0059dd;
background-color: black;
}
<div></div>

Related

Picture Tag doesn't resize properly on loading two sources (png and webp)

I'm building a website that has a 3D book:
My main goal is to support a png and a webp image for all browsers. If I only load one image all is working fine:
.book-container {
display: flex;
align-items: center;
justify-content: center;
perspective: 600px;
}
#keyframes initAnimation {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(-30deg);
}
}
.book {
width: 200px;
height: 320px;
position: relative;
transform-style: preserve-3d;
transform: rotateY(-30deg);
transition: 1s ease;
animation: 1s ease 0s 1 initAnimation;
}
.book:hover {
transform: rotateY(0deg);
}
.book > :first-child {
position: absolute;
top: 0;
left: 0;
background-color: red;
width: 200px;
height: 320px;
transform: translateZ(25px);
background-color: #01060f;
border-radius: 0 2px 2px 0;
box-shadow: 5px 5px 20px #E5E4E2;
}
.book::before {
position: absolute;
content: ' ';
background-color: blue;
left: 0;
top: 3px;
width: 48px;
height: 314px;
transform: translateX(172px) rotateY(90deg);
background: linear-gradient(90deg,
#fff 0%,
#f9f9f9 5%,
#fff 10%,
#f9f9f9 15%,
#fff 20%,
#f9f9f9 25%,
#fff 30%,
#f9f9f9 35%,
#fff 40%,
#f9f9f9 45%,
#fff 50%,
#f9f9f9 55%,
#fff 60%,
#f9f9f9 65%,
#fff 70%,
#f9f9f9 75%,
#fff 80%,
#f9f9f9 85%,
#fff 90%,
#f9f9f9 95%,
#fff 100%
);
}
.book::after {
position: absolute;
top: 0;
left: 0;
content: ' ';
width: 200px;
height: 320px;
transform: translateZ(-25px);
background-color: #01060f;
border-radius: 0 2px 2px 0;
box-shadow: -10px 0 50px 10px #666;
}
<a
class="book-container"
href="#"
target="_blank"
rel="noreferrer noopener">
<div class="book">
<img
alt="My Cover"
src="https://i.stack.imgur.com/1MPyO.png"
/>
</div>
</a>
But when I add the picture element to support both, the image loses the resize:
.book-container {
display: flex;
align-items: center;
justify-content: center;
perspective: 600px;
}
#keyframes initAnimation {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(-30deg);
}
}
.book {
width: 200px;
height: 320px;
position: relative;
transform-style: preserve-3d;
transform: rotateY(-30deg);
transition: 1s ease;
animation: 1s ease 0s 1 initAnimation;
}
.book:hover {
transform: rotateY(0deg);
}
.book > :first-child {
position: absolute;
top: 0;
left: 0;
background-color: red;
width: 200px;
height: 320px;
transform: translateZ(25px);
background-color: #01060f;
border-radius: 0 2px 2px 0;
box-shadow: 5px 5px 20px #E5E4E2;
}
.book::before {
position: absolute;
content: ' ';
background-color: blue;
left: 0;
top: 3px;
width: 48px;
height: 314px;
transform: translateX(172px) rotateY(90deg);
background: linear-gradient(90deg,
#fff 0%,
#f9f9f9 5%,
#fff 10%,
#f9f9f9 15%,
#fff 20%,
#f9f9f9 25%,
#fff 30%,
#f9f9f9 35%,
#fff 40%,
#f9f9f9 45%,
#fff 50%,
#f9f9f9 55%,
#fff 60%,
#f9f9f9 65%,
#fff 70%,
#f9f9f9 75%,
#fff 80%,
#f9f9f9 85%,
#fff 90%,
#f9f9f9 95%,
#fff 100%
);
}
.book::after {
position: absolute;
top: 0;
left: 0;
content: ' ';
width: 200px;
height: 320px;
transform: translateZ(-25px);
background-color: #01060f;
border-radius: 0 2px 2px 0;
box-shadow: -10px 0 50px 10px #666;
}
<a class="book-container"
href="#"
target="_blank"
rel="noreferrer noopener">
<div class="book">
<picture>
<source srcset="https://i.ibb.co/grB6NbQ/THE-BOOK-cover-image.webp" type="image/webp">
<source srcset="https://i.stack.imgur.com/1MPyO.png" type="image/png">
<img
alt="My Cover"
src="https://i.stack.imgur.com/1MPyO.png"/>
</picture>
</div>
</a>
Any idea what should I change? I guess the main issue is in this part of the code:
.book > :first-child {
position: absolute;
top: 0;
left: 0;
background-color: red;
width: 200px;
height: 320px;
transform: translateZ(25px);
background-color: #01060f;
border-radius: 0 2px 2px 0;
box-shadow: 5px 5px 20px #E5E4E2;
}
Here is the full snippet if you want to check it:
https://jsfiddle.net/p01vac52/1/
But I'm not so sure, I didn't expect that the picture element will fully break it. Or do you think it's a better idea to change the source using JS?
As commented,
The srcset attribute selects which image to load based on its size values and device specs, the picture / img elements will still need width/height values to scale the loaded image to the required size.
I added img { width: 100% } to make the image fit inside .book { width: 200px; height: 320px; }.
.book-container {
display: flex;
align-items: center;
justify-content: center;
perspective: 600px;
}
#keyframes initAnimation {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(-30deg);
}
}
.book {
width: 200px;
height: 320px;
position: relative;
transform-style: preserve-3d;
transform: rotateY(-30deg);
transition: 1s ease;
animation: 1s ease 0s 1 initAnimation;
}
img {
width: 100%;
}
.book:hover {
transform: rotateY(0deg);
}
.book> :first-child {
position: absolute;
top: 0;
left: 0;
background-color: red;
width: 200px;
height: 320px;
transform: translateZ(25px);
background-color: #01060f;
border-radius: 0 2px 2px 0;
box-shadow: 5px 5px 20px #E5E4E2;
}
.book::before {
position: absolute;
content: ' ';
background-color: blue;
left: 0;
top: 3px;
width: 48px;
height: 314px;
transform: translateX(172px) rotateY(90deg);
background: linear-gradient(90deg, #fff 0%, #f9f9f9 5%, #fff 10%, #f9f9f9 15%, #fff 20%, #f9f9f9 25%, #fff 30%, #f9f9f9 35%, #fff 40%, #f9f9f9 45%, #fff 50%, #f9f9f9 55%, #fff 60%, #f9f9f9 65%, #fff 70%, #f9f9f9 75%, #fff 80%, #f9f9f9 85%, #fff 90%, #f9f9f9 95%, #fff 100%);
}
.book::after {
position: absolute;
top: 0;
left: 0;
content: ' ';
width: 200px;
height: 320px;
transform: translateZ(-25px);
background-color: #01060f;
border-radius: 0 2px 2px 0;
box-shadow: -10px 0 50px 10px #666;
}
<a class="book-container" href="#" target="_blank" rel="noreferrer noopener">
<div class="book">
<picture>
<source srcset="https://i.ibb.co/grB6NbQ/THE-BOOK-cover-image.webp" type="image/webp">
<source srcset="https://i.stack.imgur.com/1MPyO.png" type="image/png">
<img alt="My Cover" src="https://i.stack.imgur.com/1MPyO.png" />
</picture>
</div>
</a>

How to create a right triangle which has linear-gradient background?

I want to create a right triangle with a linear-gradient background color. Is it possible using CSS?
Below is my code for a right triangle with a single background color.
The same code is also available here https://codepen.io/anon/pen/BMqVbL?editors=1100
<style>
body {
position: relative;
height: 100vh;
width: 100vw;
background: lightgrey;
}
.wrapper {
width: 760px;
height: 35px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.triangle {
border-right-width: 760px;
border-bottom-width: 35px;
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 0;
border-bottom-style: solid;
border-right-style: solid;
border-bottom-color: red;
border-right-color: transparent;
}
</style>
<body>
<div class="wrapper">
<div class="triangle"><!-- ### --></div>
</div>
</body>
I need my triangle to have a linear-gradient background transforming orange into red from left to right. The surroundings of my triangle have to be transparent.
I'd suggest to use the clip-path property instead, so you can reduce and clean the markup and easily use a linear-gradient as the background
Codepen demo
.triangle {
display: block;
max-width: 760px;
height: 35px;
background: linear-gradient(to right, orange, red);
clip-path: polygon(0 0, 100% 100%, 0 100%)
}
<span class="triangle"></span>
As a side note, I've used max-width instead of width, just to show you how you could make it responsive.
I think you are looking for border-image property:
border-image: linear-gradient(to top right, orange, red 50%, transparent 51%, transparent); should work
Demo solution:
.triangle {
border-right-width: 760px;
border-bottom-width: 35px;
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 0;
border-bottom-style: solid;
border-right-style: solid;
border-bottom-color: red;
border-right-color: transparent;
border-image: linear-gradient(to right top, orange, red 50%, transparent 51%, transparent);
}
<div class="wrapper">
<div class="triangle"><!-- ### --></div>
</div>
You can also consider multiple background to create the triangle but without transparency. The trick is to have a triangle on the top of the gradient having the same color as the main background:
.triangle {
max-width: 300px;
height: 50px;
background:
linear-gradient(to top right,transparent 49%,#fff 50%),
linear-gradient(to right, blue, red);
}
<div class="triangle"></div>
Another idea with skew transformation and overflow where you will have transparency:
.triangle {
max-width: 300px;
height: 50px;
overflow:hidden;
}
.triangle:before {
content:"";
display:block;
height:100%;
width:100%;
background: linear-gradient(to right, blue, red);
transform-origin:left;
transform:skewY(10deg);
}
<div class="triangle"></div>
You have also the SVG solution:
svg {
width:300px;
}
<svg viewBox="0 0 300 100">
<defs>
<linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="blue" />
<stop offset="100%" stop-color="red" />
</linearGradient>
</defs>
<polygon points='0,0 300,100 0,100' fill="url(#grad)" />
</svg>
https://codepen.io/vaneetthakur/pen/jdepLx
I have created the right triangle gradient background-color.
Please check below Code -
<div class="gradient-block"></div>
.gradient-block{
width:200px;
height:180px;
-webkit-clip-path: polygon(0 0, 0% 100%, 100% 59%);
clip-path: polygon(0 0, 0% 100%, 100% 59%);
display:inline-block;
background: #8c3310; /* Old browsers */
background: -moz-linear-gradient(top, #8c3310 0%, #bf6e4e 100%);
background: -webkit-linear-gradient(top, #8c3310 0%,#bf6e4e 100%);
background: linear-gradient(to bottom, #8c3310 0%,#bf6e4e 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#8c3310', endColorstr='#bf6e4e',GradientType=0 );
}

Linear gradient not working with div

I am creating trapezoid using following CSS:
.trapezoid {
border-bottom: 100px solid red;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
height: 0;
width: 100px;
background: linear-gradient(red, yellow);
}
<div class='trapezoid'></div>
The linear-gradient attribute is not working. I want the trapezoid as shadow i.e its color should eventually fade away. Can anyone please help me on this?
Or use a transform on a suitably sized element (or pseudo-element).
.trapezoid {
width: 100px;
height: 100px;
margin: auto;
transform: perspective(100px) rotateX(40deg);
background: linear-gradient(red, yellow);
}
<div class='trapezoid'></div>
You cannot apply gradient in this way as you are using border and your element has a height of 0 so background won't be visible.
Instead you can try to use multiple gradient to create the shape:
.trapezoid {
height: 100px;
width: 200px;
background:
linear-gradient(to bottom left,white 50%,transparent 52%) 100% 0/40px 100% no-repeat,
linear-gradient(to bottom right,white 50%,transparent 52%) 0 0/40px 100% no-repeat,
linear-gradient(red, yellow);
}
<div class='trapezoid'></div>
Or use clip-path:
.trapezoid {
height: 100px;
width: 200px;
background: linear-gradient(red, yellow);
-webkit-clip-path: polygon(20% 0%, 80% 0%, 100% 100%, 0% 100%);
clip-path: polygon(20% 0%, 80% 0%, 100% 100%, 0% 100%);
}
<div class='trapezoid'></div>
Another method with skew and pseudo-element:
.trapezoid {
height: 100px;
width: 200px;
position: relative;
}
.trapezoid:before,
.trapezoid:after{
content: "";
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 60%;
background: linear-gradient(red, yellow);
transform:skew(20deg);
transform-origin:bottom right;
}
.trapezoid:after {
left: 0;
transform:skew(-20deg);
transform-origin:bottom left;
}
<div class='trapezoid'></div>

CSS triangles with background photo overlapping complicated sections [duplicate]

I would like to make a transparent arrow over an image. This triangle should be indented in a semi transparent block and show the background image.
Desired output:
.barShow {
background-color: #000;
opacity: 0.5;
}
.barShow:before {
top: 0%;
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-top-color: #999;
border-width: 20px;
margin-left: -20px;
}
<div class="barShow"></div>
The transparent CSS Arrow should be transparent without color.
There are several approaches to make a transparent arrow over an image with CSS. The two I will describe involve pseudo elements to minimize markup and have the same output. You can also see an SVG approach at the end of this answer :
The transparent effect on the black part arround the arrow is made with rgba() colors that allow transparency. But you can use opacity on the pseudo elements if you prefer.
1. SkewX()
You can use the CSS3 skewX() property on two pseudo elements to make the transparent arrow. The main asset of this approach is that the transparent arrow can be responsive but it also allows you to put a border on the black shape and around the traingle.
The responsiveness of the shape is made with the padding-bottom property to maintain it's aspect ratio (this technique is described here).
DEMO
.wrap {
position: relative;
overflow: hidden;
width: 70%;
margin: 0 auto;
}
.wrap img {
width: 100%;
height: auto;
display: block;
}
.arrow {
position: absolute;
bottom: 0;
width: 100%;
padding-bottom: 3%;
background-color: rgba(0, 0, 0, 0.8);
}
.arrow:before,
.arrow:after {
content: '';
position: absolute;
bottom: 100%;
width: 50%;
padding-bottom: inherit;
background-color: inherit;
}
.arrow:before {
right: 50%;
-ms-transform-origin: 100% 100%;
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
-ms-transform: skewX(45deg);
-webkit-transform: skewX(45deg);
transform: skewX(45deg);
}
.arrow:after {
left: 50%;
-ms-transform-origin: 0 100%;
-webkit-transform-origin: 0 100%;
transform-origin: 0 100%;
-ms-transform: skewX(-45deg);
-webkit-transform: skewX(-45deg);
transform: skewX(-45deg);
}
<div class="wrap">
<img src="https://farm8.staticflickr.com/7187/6895047173_d4b1a0d798.jpg" />
<div class="arrow"></div>
</div>
Browser support for the transform : skew() property is IE9+ (see canIuse).
2. Border
The asset of this technique is browser support so if you need IE8 support this one is for you. The drawback is that the shape can't be responsive because border can't use % widths.
DEMO
.wrap {
position: relative;
overflow: hidden;
width: 70%;
margin: 0 auto;
}
.wrap img {
width: 100%;
height: auto;
display: block;
}
.arrow {
position: absolute;
bottom: 0;
width: 100%;
height: 20px;
background-color: rgba(0, 0, 0, 0.8);
}
.arrow:before,
.arrow:after {
content: '';
position: absolute;
bottom: 100%;
width: 50%;
box-sizing: border-box;
}
.arrow:before {
right: 50%;
border-bottom: 20px solid rgba(0, 0, 0, 0.8);
border-right: 20px solid transparent;
}
.arrow:after {
left: 50%;
border-bottom: 20px solid rgba(0, 0, 0, 0.8);
border-left: 20px solid transparent;
}
<div class="wrap">
<img src="https://farm8.staticflickr.com/7187/6895047173_d4b1a0d798.jpg" />
<div class="arrow"></div>
</div>
3. Play with it!
Example : if you can change the black transparent color to the same as your background color (white here), you can make an transparent triangle/arrow with the same background image as the block :
DEMO
.wrap {
position: relative;
overflow: hidden;
width: 50%;
margin: 0 auto;
background-color:#fff;
}
.wrap img {
width: 100%;
height: auto;
display: block;
}
.wrap:before, .wrap:after {
content:'';
position: absolute;
bottom: 0;
width: 50%;
background-color: inherit;
padding-bottom:3%;
}
.wrap:before {
right: 50%;
-ms-transform-origin: 100% 100%;
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
-ms-transform: skewX(45deg);
-webkit-transform: skewX(45deg);
transform: skewX(45deg);
}
.wrap:after {
left: 50%;
-ms-transform-origin: 0 100%;
-webkit-transform-origin: 0 100%;
transform-origin: 0 100%;
-ms-transform: skewX(-45deg);
-webkit-transform: skewX(-45deg);
transform: skewX(-45deg);
}
<div class="wrap">
<img src="https://farm8.staticflickr.com/7187/6895047173_d4b1a0d798.jpg" />
</div>
4. Tooltip with a triangle over an image.
If you need to use this shape over another image, background gradient or whatever non plain color, you will need to use a different approach in order to see the image all around the shape like this:
The point is to use the same image twice. Once in the div element and once in the triangle and to postion them exactly at the same place with absolute positioning. The arrow is made with transform:rotate();.
DEMO
body{
padding-top:100px;
background:url('https://farm8.staticflickr.com/7187/6895047173_d4b1a0d798.jpg')no-repeat center center;
background-size:cover;
}
.wrap, .img {
display:inline-block;
position:relative;
}
.tr{
position:absolute;
overflow:hidden;
top:-25px; left:100px;
width:50px; height:50px;
-webkit-transform:rotate(45deg);
-ms-transform:rotate(45deg);
transform:rotate(45deg);
}
.tr img{
position:absolute;
top:-15px; left:-100px;
-webkit-transform-origin: 125px 40px;
-ms-transform-origin: 125px 40px;
transform-origin: 125px 40px;
-webkit-transform:rotate(-45deg);
-ms-transform:rotate(-45deg);
transform:rotate(-45deg);
}
.img{
overflow:hidden;
width: 600px; height:100px;
}
.img img{
position:absolute;
top:-40px;
}
<div class="wrap">
<div class="img">
<img src="https://farm7.staticflickr.com/6092/6227418584_d5883b0948.jpg" alt="" />
</div>
<div class="tr">
<img src="https://farm7.staticflickr.com/6092/6227418584_d5883b0948.jpg" alt="" />
</div>
</div>
DEMO with box shadows.
5. SVG and cliPath
DEMO using an svg tag and clipPath.
This might be a semanticaly better approach if you are making graphics.
Simple Approach
Use pseudo element with box-shadow and transform: rotate();
Add overflow: hidden; to main div.
Snippet :
body {
margin: 0;
padding: 0;
background: url(http://i.imgur.com/EinPKO3.jpg);
background-size: cover;
}
div {
height: 100px;
width: 100%;
position: absolute;
bottom: 0;
overflow: hidden;
}
div:before {
position: absolute;
top: -50px;
left: calc(50% - 35px);
content: "";
height: 50px;
width: 50px;
background: transparent;
-webkit-transform-origin: 0% 100%;
-moz-transform-origin: 0% 100%;
-ms-transform-origin: 0% 100%;
transform-origin: 0% 100%;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
box-shadow: 0 0 0 5000px rgba(0, 0, 0, 0.6);
}
<div></div>
Here is a solution using CSS clip-path that doesn't overflow the wrapper.
.wrap {
position:relative;
width:480px;
height:270px;
background-image:url(http://placehold.it/480x270);
}
.wrap:after {
content:"";
display:block;
position:absolute;
left:0;
right:0;
bottom:0;
height:50px;
background-color:rgba(0, 0, 0, 0.7);
-webkit-clip-path:polygon(0 0, calc(50% - 30px) 0, 50% 50%, calc(50% + 30px) 0, 100% 0, 100% 100%, 0 100%);
-moz-clip-path:polygon(0 0, calc(50% - 30px) 0, 50% 50%, calc(50% + 30px) 0, 100% 0, 100% 100%, 0 100%);
clip-path:polygon(0 0, calc(50% - 30px) 0, 50% 50%, calc(50% + 30px) 0, 100% 0, 100% 100%, 0 100%);
}
<div class="wrap"></div>
We can make this with linear-gradients. No pseudo-element. I used some CSS variables to control everything easily. This is more flexible.
.a {
/* you can change these variables */
--arrow-width: 20px;
--rgba: rgba(0, 0, 0, 0.5);
--bottom-height: 50px;
width: 100%;
height: 300px;
background: linear-gradient(to right, var(--rgba) 0 calc(50% - var(--arrow-width)), transparent calc(50% - var(--arrow-width)) calc(50% + var(--arrow-width)), var(--rgba) 0 calc(50% + var(--arrow-width) * 2)) 0 calc(100% - var(--bottom-height)) / 100% var(--arrow-width),
linear-gradient(to bottom right, transparent 0 50%, var(--rgba) 50.1% 100%) calc(50% + (var(--arrow-width) / 2)) calc(100% - var(--bottom-height)) / var(--arrow-width) var(--arrow-width),
linear-gradient(to bottom left, transparent 0 50%, var(--rgba) 50.1% 100%) calc(50% - (var(--arrow-width) / 2)) calc(100% - var(--bottom-height)) / var(--arrow-width) var(--arrow-width),
linear-gradient(var(--rgba), var(--rgba)) 0 100%/ 100% calc(var(--bottom-height)),
url(https://picsum.photos/id/600/360) 50% 50% / cover;
background-repeat: no-repeat;
}
<div class="a"></div>
By changing the variables:
.a {
/* you can change these variables */
--arrow-width: 50px;
--rgba: rgba(0, 0, 0, 0.5);
--bottom-height: 70px;
width: 100%;
height: 300px;
background: linear-gradient(to right, var(--rgba) 0 calc(50% - var(--arrow-width)), transparent calc(50% - var(--arrow-width)) calc(50% + var(--arrow-width)), var(--rgba) 0 calc(50% + var(--arrow-width) * 2)) 0 calc(100% - var(--bottom-height)) / 100% var(--arrow-width),
linear-gradient(to bottom right, transparent 0 50%, var(--rgba) 50.1% 100%) calc(50% + (var(--arrow-width) / 2)) calc(100% - var(--bottom-height)) / var(--arrow-width) var(--arrow-width),
linear-gradient(to bottom left, transparent 0 50%, var(--rgba) 50.1% 100%) calc(50% - (var(--arrow-width) / 2)) calc(100% - var(--bottom-height)) / var(--arrow-width) var(--arrow-width),
linear-gradient(var(--rgba), var(--rgba)) 0 100%/ 100% calc(var(--bottom-height)),
url(https://picsum.photos/id/600/360) 50% 50% / cover;
background-repeat: no-repeat;
}
<div class="a"></div>
To better understand the trick here is the gradients with different colors:
.a {
/* you can change these variables */
--arrow-width: 50px;
--bottom-height: 70px;
width: 100%;
height: 300px;
background: linear-gradient(to right, red 0 calc(50% - var(--arrow-width)), transparent calc(50% - var(--arrow-width)) calc(50% + var(--arrow-width)), blue 0 calc(50% + var(--arrow-width) * 2)) 0 calc(100% - var(--bottom-height)) / 100% var(--arrow-width),
linear-gradient(to bottom right, transparent 0 50%, yellow 50.1% 100%) calc(50% + (var(--arrow-width) / 2)) calc(100% - var(--bottom-height)) / var(--arrow-width) var(--arrow-width),
linear-gradient(to bottom left, transparent 0 50%, green 50.1% 100%) calc(50% - (var(--arrow-width) / 2)) calc(100% - var(--bottom-height)) / var(--arrow-width) var(--arrow-width),
linear-gradient(purple, purple) 0 100%/ 100% calc(var(--bottom-height)),
url(https://picsum.photos/id/600/360) 50% 50% / cover;
background-repeat: no-repeat;
}
<div class="a"></div>
Masking:
.a {
/* you can change this variable */
--arrow-width: 30px;
width: 100%;
height: 300px;
--mask: linear-gradient(#000, #000) 0 0/100% calc(100% - var(--arrow-width)) no-repeat,
linear-gradient(to top right, transparent 0 50%, #000 50.1% 100%) calc(50% - var(--arrow-width) / 2) 100% / var(--arrow-width) var(--arrow-width) no-repeat,
linear-gradient(to top left, transparent 0 50%, #000 50.1% 100%) calc(50% + var(--arrow-width) / 2) 100% / var(--arrow-width) var(--arrow-width) no-repeat;
-webkit-mask: var(--mask);
mask: var(--mask);
background: url(https://picsum.photos/id/600/360) 50% 50% / cover;
}
<div class="a"></div>

How to create a heart shape using CSS?

I've found the following CSS in one of the answers here on SO and I was wondering why does it create the desired heart shape:
#heart {
position: relative;
width: 100px;
height: 90px;
}
#heart:before, #heart:after {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 50px;
height: 80px;
background: red;
border-radius: 50px 50px 0 0;
transform: rotate(-45deg);
transform-origin: 0 100%;
}
#heart:after {
left: 0;
transform: rotate(45deg);
transform-origin :100% 100%;
}
<div id="heart"></div>
Please can someone explain?
CSS3 Mon Amour - A 4 Step Love Afair
There are a few steps for creating heart shape using CSS3:
Create a block-level element such as a <div> in your DOM and assign it with id="heart" and apply CSS:
#heart {
position:relative;
width:100px;
height:90px;
margin-top:10px; /* leave some space above */
}
Now using pseudo-element #heart:before we create a red box with one rounded edge like this:
#heart:before {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 52px;
height: 80px;
background: red; /* assign a nice red color */
border-radius: 50px 50px 0 0; /* make the top edge round */
}
Your heart should now look like this:
Let us assign a little rotation to that by adding:
#heart:before {
-webkit-transform: rotate(-45deg); /* 45 degrees rotation counter clockwise */
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0 100%; /* Rotate it around the bottom-left corner */
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
-o-transform-origin: 0 100%;
transform-origin: 0 100%;
}
And we now get:
Already starting to come together :).
Now for the right part we basically need the same shape only rotated
45 degrees clockwise instead of counter clockwise. To avoid code duplication we attach the css
of #heart:before also to #heart:after, and then apply the change
in position and in angle:
#heart:after {
left: 0; /* placing the right part properly */
-webkit-transform: rotate(45deg); /* rotating 45 degrees clockwise */
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transform-origin: 100% 100%; /* rotation is around bottom-right corner this time */
-moz-transform-origin: 100% 100%;
-ms-transform-origin: 100% 100%;
-o-transform-origin: 100% 100%;
transform-origin :100% 100%;
}
And voilĂ ! a complete heart shaped <div>:
Snippet without any prefix:
#heart {
position: relative;
width: 100px;
height: 90px;
margin-top: 10px;
}
#heart::before, #heart::after {
content: "";
position: absolute;
top: 0;
width: 52px;
height: 80px;
border-radius: 50px 50px 0 0;
background: red;
}
#heart::before {
left: 50px;
transform: rotate(-45deg);
transform-origin: 0 100%;
}
#heart::after {
left: 0;
transform: rotate(45deg);
transform-origin: 100% 100%;
}
<div id="heart"></div>
A new idea with less of code:
.heart {
display:inline-block;
width: 200px;
aspect-ratio: 1;
border-image: radial-gradient(red 69%,#0000 70%) 84.5% fill/100%;
clip-path: polygon(-41% 0,50% 91%, 141% 0);
}
<div class="heart"></div>
<div class="heart" style="width:100px"></div>
<div class="heart" style="width:50px"></div>
Using mask, we can apply it to an image:
img {
width: 200px;
aspect-ratio: 1;
object-fit: cover;
--_m: radial-gradient(#000 69%,#0000 70%) 84.5% fill/100%;
-webkit-mask-box-image: var(--_m);
mask-border: var(--_m);
clip-path: polygon(-41% 0,50% 91%, 141% 0);
}
/* fallback until better support for mask-border */
#supports not (-webkit-mask-box-image: var(--_m)) {
img {
--_m:
radial-gradient(circle at 60% 63%,#000 64%,#0000 65%) top left /50% 50% no-repeat,
radial-gradient(circle at 40% 63%,#000 64%,#0000 65%) top right/50% 50% no-repeat,
linear-gradient(#000 0 0) bottom/100% 50% no-repeat;
-webkit-mask: var(--_m);
mask: var(--_m);
}
}
body {
margin: 0;
min-height: 100vh;
display: grid;
grid-auto-flow: column;
place-content: center;
gap: 30px;
background: pink;
filter: drop-shadow(0 0 10px #ff3e60)
}
<img src="https://picsum.photos/id/1027/300/300" alt="the face of a beautiful girl">
<img src="https://picsum.photos/id/64/300/300" alt="another beautiful girl">
Here is another idea using one element and relying on multiple backgrounds to achieve the heart shape. You can also easily adjust the size by only changing the width:
.heart {
width:200px;
background:
radial-gradient(circle at 60% 65%, red 64%, transparent 65%) top left,
radial-gradient(circle at 40% 65%, red 64%, transparent 65%) top right,
linear-gradient(to bottom left, red 43%,transparent 43%) bottom left ,
linear-gradient(to bottom right,red 43%,transparent 43%) bottom right;
background-size:50% 50%;
background-repeat:no-repeat;
display:inline-block;
}
.heart::before {
content:"";
display:block;
padding-top:100%;
}
<div class="heart">
</div>
<div class="heart" style="width:100px">
</div>
<div class="heart" style="width:60px">
</div>
<div class="heart" style="width:30px">
</div>
You can also use mask and you can have any kind of coloration:
.heart {
width:200px;
display:inline-block;
-webkit-mask:
radial-gradient(circle at 60% 65%, red 64%, transparent 65%) top left,
radial-gradient(circle at 40% 65%, red 64%, transparent 65%) top right,
linear-gradient(to bottom left, red 43%,transparent 43%) bottom left ,
linear-gradient(to bottom right,red 43%,transparent 43%) bottom right;
-webkit-mask-size:50% 50%;
-webkit-mask-repeat:no-repeat;
mask:
radial-gradient(circle at 60% 65%, red 64%, transparent 65%) top left,
radial-gradient(circle at 40% 65%, red 64%, transparent 65%) top right,
linear-gradient(to bottom left, red 43%,transparent 43%) bottom left ,
linear-gradient(to bottom right,red 43%,transparent 43%) bottom right;
mask-size:50% 50%;
mask-repeat:no-repeat;
background:linear-gradient(red,blue);
}
.heart::before {
content:"";
display:block;
padding-top:100%;
}
<div class="heart">
</div>
<div class="heart" style="width:100px;background:linear-gradient(45deg,grey 50%,purple 0)">
</div>
<div class="heart" style="width:60px;background:radial-gradient(red,yellow,red)">
</div>
<div class="heart" style="width:30px;background:blue">
</div>
How does it works?
The whole shape is combined using 4 gradients: 2 gradients to create the top part and 2 for the bottom parts. each gradient is taking 1/4 of size and placed at a corner.
Use a different color for each gradient to clearly identify the puzzle
.heart {
width:200px;
background:
radial-gradient(circle at 60% 65%, red 64%, grey 65%) top left,
radial-gradient(circle at 40% 65%, blue 64%, black 65%) top right,
linear-gradient(to bottom left, green 43%,black 43%) bottom left ,
linear-gradient(to bottom right,purple 43%,grey 43%) bottom right;
background-size:50% 50%;
background-repeat:no-repeat;
display:inline-block;
border:5px solid yellow;
}
.heart::before {
content:"";
display:block;
padding-top:100%;
}
<div class="heart">
</div>