Related
This question already has answers here:
How to center an element horizontally and vertically
(27 answers)
Closed 6 months ago.
I'm trying to make a responsive hexagon image frame, but I'm stuck on aligning the inner hexagon. Does anyone know how to center the inner hexagon? Here's my code:
.inner {
background-color: red;
width: 95%;
height: 0%;
padding-bottom: 98%;
margin-top: auto;
margin-bottom: auto;
}
.outer {
background-color: mediumspringgreen;
width: 12%;
height: 0%;
padding-bottom: 13%;
}
.hexagon {
display: flex;
justify-content: center;
align-items: center;
position: relative;
-webkit-clip-path: polygon( 50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
}
<div class="hexagon outer">
<div class="hexagon inner">
<img src="https://placekitten.com/400/400" class="absolute inset-0 h-full w-full" alt="" />
</div>
</div>
My result:
Expected result:
It seems as you use the padding only for your inner div, the outer div only gets that height. I would have a container that you put the width on, then you can add padding to your outer hexagon and absolutely position your inner hexagon:
.container {
width: 12%;
}
.inner {
background-color: red;
width: calc(100% - 10px);
/* can change this to be a percentage if you want a variable width border. with calc, the border will always be half of what you subtract */
height: calc(100% - 10px);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.outer {
background-color: blue;
width: 100%;
padding-top: 100%;
position: relative;
}
.hexagon {
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
}
.img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
<div class="container">
<div class="hexagon outer">
<div class="hexagon inner">
<img src="https://placekitten.com/400/400" class="img">
</div>
</div>
</div>
From comments solution using aspect ratio instead of padding and inset instead of calc on the width of inner:
.container {
width: 12%;
}
.inner {
background-color: red;
/* insets the element 5px from the edges of
the element against which its positioned: */
inset: 5px;
position: absolute;
}
.outer {
/* allows one dimension to be set (here 'inline-size'/'width'),
and the other dimension ('block-size'/'height') will be
an equal width: */
aspect-ratio: 1;
background-color: blue;
/* logical property, equivalent to 'width' in the English -
left-to-right - language: */
inline-size: 100%;
position: relative;
}
.hexagon {
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
}
.img {
width: 100%;
object-fit: cover;
}
<div class="container">
<div class="hexagon outer">
<div class="hexagon inner">
<img src="https://placekitten.com/400/400" class="img">
</div>
</div>
</div>
Try it:
.inner {
background-color: red;
width: 95%;
height: 0%;
padding-bottom: 98%;
margin-top: auto;
margin-bottom: auto;
}
.outer {
background-color: mediumspringgreen;
width: 12%;
height: 0%;
padding-bottom: 13%;
}
.hexagon {
display: flex;
justify-content: center;
align-items: center;
-webkit-clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
position: absolute;
top: 50%;
left: 50%;
-moz-transform: translateX(-50%) translateY(-50%);
-webkit-transform: translateX(-50%) translateY(-50%);
transform: translateX(-50%) translateY(-50%);
}
<div class="hexagon outer">
<div class="hexagon inner">
<img src="https://placekitten.com/400/400" class="absolute inset-0 h-full w-full" alt="" />
</div>
</div>
I am trying to apply clip-path on three items which are aligned next to each other. Since paths are calculating the space between each other based on the non-clipped div shape, there is an unwanted gap. In the code below when I apply the commented styles in .class2 I get a close result of what I want, but then it's no longer responsive. Any other way to get the similar result with a more suitable approach ?
https://codepen.io/SpoyrazY/pen/erbKXx
HTML
<div class="class1">
<h1>1</h1>
</div>
<div class="class2">
<h1>2</h1>
</div>
<div class="class3">
<h1>3</h1>
</div>
CSS
.class1{
background-image:url(https://dummyimage.com/600x400/66ccff/fff&text=+);
width: 33.33333333%;
height: 400px;
float: left;
-webkit-clip-path: polygon(0 0, 100% 0, 85% 100%, 0 100%);
clip-path: polygon(0 0, 100% 0, 85% 100%, 0 100%);
text-align: center;
color: white;
}
.class2{
background-image:url(https://dummyimage.com/600x400/66ff66/fff&text=+);
width: 33.33333333%;
height: 400px;
float: left;
-webkit-clip-path: polygon(15% 0, 100% 0%, 85% 100%, 0%, 100%);
clip-path: polygon(15% 0, 100% 0%, 85% 100%, 0% 100%);
/*
margin-left: -90px;
margin-right: -90px;
width: 42.7%;
-webkit-clip-path: polygon(12% 0, 100% 0%, 85% 100%, 0%, 100%);
clip-path: polygon(12% 0, 100% 0%, 88% 100%, 0% 100%);
*/
text-align: center;
color: white;
}
.class3{
background-image:url(https://dummyimage.com/600x400/ff99ff/fff&text=+);
width: 33.33333333%;
height: 400px;
float: left;
-webkit-clip-path: polygon(15% 0, 100% 0, 100% 100%, 0 100%);
clip-path: polygon(15% 0, 100% 0, 100% 100%, 0 100%);
text-align: center;
color: white;
}
This happens due to clip-path. you can achieve your result by setting scale in a custom class. so your html will be like this
<div class="class1 block">
<h1>1</h1>
</div>
<div class="class2 block">
<h1>2</h1>
</div>
<div class="class3 block">
<h1>3</h1>
</div>
Add some lines of css
.block {
transform: scale(1.35);
transform-origin: top;
}
working fiddle here
I have an issue with a transition effect in Safari and could use some help. My CSS hover swaps background images, as it should, but the hover image 'jumps' from its position, up and to the left (which I don't want to happen). Thanks.
Structure:
.sidebar .widget {
height: 276px;
width: 326px;
background:url('/wp-content/themes/a-theme/svg/polygon-image.svg') no-repeat center center;
background-size: 100%;
}
.sidebar .widget:hover {
background:url('/wp-content/themes/a-theme/svg/polygon-image-hover.svg') no-repeat center center;
background-size: 100%;
transition: 0.5s ease-in-out;
}
<div class="sidebar">
<aside id="black-studio-tinymce-18" class="widget widget_black_studio_tinymce">
<div class="textwidget">
<h3 style="text-align: center;">Sample Text<br></h3>
</div>
</aside>
</div>
avoid browsers bugs and clean:
.sidebar .widget {
height: 276px;
width: 326px;
background-repeat:no-repeat;
background-position: center center;
background-image:url(/wp-content/themes/a-theme/svg/polygon-image.svg);
background-size: 100%;
transition:background-image 0.5s ease-in-out;
}
.sidebar .widget:hover {
background-image:url(/wp-content/themes/a-theme/svg/polygon-image-hover.svg);
}
From your help, I modified my CSS to get exactly what I needed. I had a background image of a polygon shape and a graphic in the middle of it. I kept the graphic and used a CSS polygon for the shape, instead, and now my hover effect works in Firefox, Chrome, and Safari.
See my CSS below and thanks again for the replies.
sidebar .widget {
background: url('/wp-content/uploads/2017/08/image.png') no-repeat center center;
background-color: rgba(255, 165, 0, 0.85);
background-size: 70%;
-webkit-clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
height: 276px;
width: 326px;
display: flex;
justify-content: center;
align-items: center;
}
.sidebar .widget:hover {
background: url('/wp-content/uploads/2017/08/image.png') no-repeat center center;
background-color: rgba(108, 218, 244, 0.8);
background-size: 80%;
-webkit-clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
height: 276px;
width: 326px;
transition: 0.5s ease-in-out;
}
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>
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>