Trying to create a transparent triangle div with a colored border.
css
#down {
display: block;
position: fixed;
left: 0; right: 0;
width: 0; height: 0;
margin: 0 auto;
border-left: 55px solid transparent;
border-right: 55px solid transparent;
z-index: 20;
bottom: 0;
border-bottom: 55px solid rgba(250,250,250,0.75);
}
putting a div on-top another div ruins the transparency
You can also use gradients and/or transform:
on left: square + border-top/left + transform + gradient to draw the bottom border:
on middle : yours
on right : border-bottom + gradient for the triangle top borders
both extra example can hold content such as font icone / text / image .
body {
background:tomato;
}
#rotate {
position:fixed;
border:solid turquoise;
border-bottom:none;
border-right:none;
bottom:7px;
left:calc(50% - 180px);
height:75px;
width:75px;
transform-origin: bottom left;
transform:rotate(45deg);
background:linear-gradient(to bottom right, transparent calc(50% - 3px), turquoise calc(50% - 3px), turquoise 50%, transparent 50% );
}
#bg-gradient {
position:fixed;
bottom:5px;
left: calc(50% + 70px) ;
border-bottom:solid turquoise;
background:linear-gradient(to bottom right, transparent 50%, turquoise 50%, turquoise calc(50% + 3px), transparent calc(50% + 3px) ),linear-gradient(to bottom left, transparent 50%, turquoise 50%, turquoise calc(50% + 3px), transparent calc(50% + 3px) ) right
;
background-repeat:no-repeat;
background-size:50% 100%;
height:55px;
width:110px;
}
#down {
display: block;
position: fixed;
left: 0; right: 0;
width: 0; height: 0;
margin: 0 auto;
border-left: 55px solid transparent;
border-right: 55px solid transparent;
z-index: 20;
bottom: 5px;
border-bottom: 55px solid rgba(250,250,250,0.75);
}
<div id="down"></div>
<div id="rotate"></div>
<div id="bg-gradient"></div>
Notice that a rotated square at bottom can have half being hidden
This is usually done with border tricks, and those are not really helpful for this
You need others techniques for that.
For instance, see this CSS
body {
background: linear-gradient(90deg, lightblue, yellow)
}
.trapezoid {
left: 50px;
top: 50px;
position: absolute;
height: 100px;
width: 500px;
background-color: transparent;
}
.trapezoid:before {
content: '';
width: 57%;
height: 100%;
left: -4%;
position: absolute;
border-color: red;
border-style: solid;
border-width: 3px 0px 3px 3px;
-webkit-transform: skewX(-20deg);
}
.trapezoid:after {
content: '';
width: 59%;
height: 100%;
right: -4%;
position: absolute;
border-color: red;
border-style: solid;
border-width: 3px 3px 3px 0px;
-webkit-transform: skewX(20deg);
}
This is a very easy solution, but it uses CSS transform which isn't supported by IE lower than 9.0.
Remember that this triangle is at the very bottom of the page, so a rotated square can be used.
#down {
display: block;
position: fixed;
left: 0; right: 0;
bottom: -47px;
width: 80px;
height: 80px;
margin: 0 auto;
border: 0;
z-index: 20;
background-color: rgba(250,250,250,0.75);
-ms-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
border: 3px solid #ffaa33;
}
#down-inner { /* Must be rotated back */
width: 100%;
height: 100%;
-ms-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
}
body {
background-color: #e7e7e7;
color: #444444;
font-family: Arial, sans-serif;
}
<div id="down">
<div id="down-inner">A rotated square</div>
</div>
I was able to resolve this with fewer lines of code.
body {
background: url(https://images.unsplash.com/photo-1500390365106-166bb67248d6?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2434&q=80) no-repeat top; background-size: cover;
min-height: 300px;
}
.triangle {
position: absolute;
top: 25%;
left: 30%;
height: 158px;
width: 182px;
background: white;
clip-path: polygon(50% 0%, 0% 100%, 1.75% 100%, 50% 3%, 97.5% 98.35%, 1.75% 98.35%, 1.75% 100%, 100% 100%);
}
<div class="triangle"></div>
The hexagon version is also shown here:
https://codepen.io/smeyer/pen/gOPmxqm
You can play with the numbers to alter the border width.
Related
So I've managed to create a CSS Triangle with 3 different coloured borders. It can be seen here: https://codepen.io/nuul/pen/oNbeZey
CSS code:
$bg: #0000e5
$color: ((#00007c, #0000e5), (#0000b0, #0000e5), (#0000ff, #0000e5))
#mixin linear-gradient($direction, $gradients...)
background-image: linear-gradient($direction, $gradients...)
#function colorL($some-color, $num)
#return nth($some-color, $num)
#for $i from 1 through length($color)
.sq-#{$i}
#include linear-gradient(colorL(nth($color, $i), 2) 60%, colorL(nth($color, $i), 1) 75%)
$height: 9px
$width: $height * 3.47
body
background: #3D4849
.blueCore
position: absolute
left: 5px
top: 15px
.sq-wrapper
width: $width
height: $height
font-size: 0
display: inline-block
clip-path: polygon(50% 0%, 0 100%, 100% 100%)
position: absolute
left: 0
top: $height
transform-origin: 50% 0
.sq-1-wrapper
transform: rotate(0deg)
.sq-2-wrapper
transform: rotate(240deg)
.sq-3-wrapper
transform: rotate(-240deg)
.sq
width: 100%
height: 100%
.blueBlock
background-color: #0000e5
border: 3px solid
border-top-color: #0000ff
border-right-color: #00007c
border-bottom-color: #00007c
border-left-color: #0000ff
width: 42px
height: 42px
position: relative
z-index: 10
Though I am happy with the result, I am still wondering if the CSS code for this can be simplified (since there is a lot of CSS code needed for just a triangle). Perhaps with a :before :after? The looks should stay the same
Any thoughts?
ps: You can ignore the square around it, I just want to put it in a div for future usage
Thanks!
In terms of your question, I wouldn't recommend using CSS for this and maybe in this situation, an image or even font-awesome would be more efficient. However, you could possibly tweak something like below. It uses two elements to create this shape.
.outer {
position: relative;
height: 200px;
width: 200px;
background: dimgray;
}
.outer:before {
/*Bottom Border Here*/
content: "";
position: absolute;
height: 10%;
width: 90%;
left: 5%;
top: 88%;
z-index: 10;
background: darkblue;
transform: perspective(100px) rotateX(60deg);
}
.outer:after {
/*Triangle Background*/
content: "";
position: absolute;
width: 0;
left: 10px;
bottom: 10px;
border-top: 0;
border-left: 90px solid transparent;
border-right: 90px solid transparent;
border-bottom: 150px solid blue;
}
.inner {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
.inner:before {
content: "";
position: absolute;
height: 10%;
width: 90%;
left: -17%;
top: 50%;
background: lightblue;
/*Left border colour here*/
transform: rotate(121deg) perspective(100px) rotateX(60deg);
}
.inner:after {
content: "";
position: absolute;
height: 10%;
width: 90%;
right: -18%;
top: 50%;
background: rgb(0, 0, 220);
/*right border colour here*/
transform: rotate(-120deg) perspective(100px) rotateX(60deg);
}
/*demo only*/
.outer:hover:before { background: darkred;}
.outer:hover:after { border-bottom-color: red;}
.outer:hover .inner:before { background: tomato;}
.outer:hover .inner:after { background: rgb(220, 0, 0);}
<div class="outer">
<div class="inner"></div>
</div>
one element and responsive solution:
.box {
width: 200px;
display: inline-flex;
background:
conic-gradient(at 50% 20px, red 150deg, #0000 0 210deg, green 0)
blue;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.box::before {
content: "";
padding-top: calc(86.6% - 10px);
width: 100%;
box-sizing: border-box;
border:solid transparent;
border-bottom-color: gold;
border-width: 0 18px 10px 18px;
}
<div class="box"></div>
<div class="box" style="width:150px;"></div>
<div class="box" style="width:50px;"></div>
I’m trying to realise a couples of element with this design :
I also want to have a border radius like this :
What I managed to do :
For the first div, I didn’t managed to do inner box shadow for the ::before arrow and box shadow for the ::after arrow
For the last div, I managed to do it but when I try to change the size of the arrow to make it larger, the box-shadows is not working anymore...
body {
background-color: white;
}
.test{
margin-top: -30px!important;
}
.test2{
z-index:13;
}
.test3{
z-index:12;
}
.test4{
z-index:11;
}
.test5{
z-index:10;
}
.triangle {
position: relative;
margin: 3em;
padding: 1em;
box-sizing: border-box;
background: white;
box-shadow: 0px 3px 10px 0 black;
}
.triangle::before{
content: "";
position: absolute;
width: 0;
height: 0;
margin-left: -0.5em;
top: 0;
left: 40%;
width: 0;
height: 0;
border-style: solid;
border-width: 20px 50px 0 50px;
border-color: lightgrey transparent transparent transparent;
//box-shadow: 0px 3px 10px 0 black;
}
.triangle::after{
content: "";
position: absolute;
width: 0;
height: 0;
margin-left: -0.5em;
bottom: -20px;
left: 40%;
width: 0;
height: 0;
border-style: solid;
border-width: 20px 50px 0 50px;
border-color: lightgrey transparent transparent transparent;
//box-shadow: 0px 3px 10px 0 black;
}
.toto::after{
content: "";
position: absolute;
width: 0;
height: 0;
margin-left: -0.5em;
bottom: -2em;
left: 50%;
box-sizing: border-box;
border: 1em solid black;
border-color: transparent transparent lightgrey lightgrey;
transform-origin: 0 0;
transform: rotate(-45deg);
box-shadow: -3px 3px 3px 0 rgba(0, 0, 0, 0.4);
}
<div class="triangle test2">Inner box shadow for before content not working</div>
<div class="triangle test test3">box shadow for after content not working</div>
<div class="triangle test test4">Content 3</div>
<div class="triangle test test5">Content 4</div>
<div class="triangle toto">Managed to do it but the arrow is not editable(I want to make it longer)</div>
Anyone already had this issue or know how to solve this problem?
This is suitable for clip-path
.box {
margin: 50px;
height: 100px;
position:relative;
z-index:0;
filter: drop-shadow(0 0 5px #000);
}
.box::before {
content:"";
position:absolute;
z-index:-1;
top:0;
left:0;
right:0;
bottom:0;
background: #f2f2f2;
clip-path: polygon(
0 0,
calc(50% - 20px) 0, 50% 20px, calc(50% + 20px) 0, /* top arrow */
100% 0,
100% calc(100% - 20px),
calc(50% - 20px) calc(100% - 20px), 50% 100%, calc(50% + 20px) calc(100% - 20px), /* bottom arrow */
0 calc(100% - 20px));
}
<div class="box"></div>
With CSS variables you can easily handle it:
.box {
--w:40px; /* width of the arrow */
--h:20px; /* height of the arrow */
margin: 50px;
height: 100px;
padding:var(--h) 0;
position:relative;
z-index:0;
filter: drop-shadow(0 0 5px #000);
}
.box::before {
content:"";
position:absolute;
z-index:-1;
top:0;
left:0;
right:0;
bottom:0;
background: #f2f2f2;
clip-path: polygon(
0 0,
calc(50% - var(--w)/2) 0, 50% var(--h), calc(50% + var(--w)/2) 0, /* top arrow */
100% 0,
100% calc(100% - var(--h)),
calc(50% - var(--w)/2) calc(100% - var(--h)), 50% 100%, calc(50% + var(--w)/2) calc(100% - var(--h)), /* bottom arrow */
0 calc(100% - var(--h)));
}
<div class="box"></div>
<div class="box" style="--w:60px;"></div>
<div class="box" style="--w:200px;--h:40px"></div>
To add border radius you can edit like below:
.box {
--w: 40px; /* width of the arrow */
--h: 20px; /* height of the arrow */
--r: 30px; /* radius */
margin: 50px;
height: 100px;
padding: var(--h) 0;
position: relative;
z-index: 0;
filter: drop-shadow(0 0 5px #000);
}
.box::before,
.box::after {
content: "";
position: absolute;
z-index: -1;
left: 0;
right: 0;
background: #f2f2f2;
}
.box::before {
top: 0;
bottom: var(--h);
border-radius: var(--r);
clip-path: polygon( 0 0, calc(50% - var(--w)/2) 0, 50% var(--h), calc(50% + var(--w)/2) 0, 100% 0, 100% 100%, 0 100%);
}
.box::after {
bottom: 0;
height: var(--h);
clip-path: polygon( 0 0, 100% 0, calc(50% - var(--w)/2) 0, 50% 100%, calc(50% + var(--w)/2) 0);
}
<div class="box"></div>
<div class="box" style="--w:60px;--r:20px"></div>
<div class="box" style="--w:200px;--h:40px;--r:60px"></div>
You may use filter / drop-shadow
https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/drop-shadow
The drop-shadow() CSS function applies a drop shadow effect to the input image. Its result is a <filter-function>.
possible use :
body {
background-color: white;
}
.test {
margin-top: -30px!important;
}
.test2 {
z-index: 13;
}
.test3 {
z-index: 12;
}
.test4 {
z-index: 11;
}
.test5 {
z-index: 10;
}
.triangle {
position: relative;
margin: 3em;
padding: 1em;
box-sizing: border-box;
background: white;
filter: drop-shadow(0px 3px 10px black);
}
.triangle::after {
content: "";
position: absolute;
width: 0;
height: 0;
margin-left: -0.5em;
bottom: -20px;
left: 40%;
width: 0;
height: 0;
border-style: solid;
border-width: 20px 50px 0 50px;
border-color: white transparent transparent transparent;
}
.toto::after {
content: "";
position: absolute;
width: 0;
height: 0;
margin-left: -0.5em;
bottom: -2em;
left: 50%;
box-sizing: border-box;
border: 1em solid black;
border-color: transparent transparent white white;
transform-origin: 0 0;
transform: rotate(-45deg);
}
<div class="triangle test2">Inner box shadow for before content not working</div>
<div class="triangle test test3">box shadow for after content not working</div>
<div class="triangle test test4">Content 3</div>
<div class="triangle test test5">Content 4</div>
<div class="triangle toto">Managed to do it but the arrow is not editable(I want to make it longer)</div>
I want to make the following design:
I tried with :after and :before but it does not work. Here’s my current code:
.design {
background: #ea053a;
display: inline-block;
height: 155px;
margin-left: 33px;
margin-right: 40px;
position: relative;
width: 228px;
}
.design:before {
border-top: 43px solid #ea053a;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
margin-right: 40px;
content: "";
height: 0;
left: 0;
position: absolute;
top: 55px;
margin-top: 100px;
width: 128px;
}
<div class="design"></div>
How could I leave it the same as the original design and with the following two properties?:
box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.2);
background-image: linear-gradient(to bottom, #ea053a, #d0021b);
Here is an idea with skew transformation and drop-shadow filter. You simply need some extra element to correctly have the gradient. The trick is to invert the skew to keep the gradient direction correct (not needed if we deal with solid color)
.box {
width: 150px;
height: 150px;
position: relative;
z-index:0;
overflow: hidden;
filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
}
.box span {
position: absolute;
z-index:-1;
top: 0;
width: 50%;
height: 100%;
overflow: hidden;
}
.box span:first-of-type {
left: 0;
transform: skewY(35deg);
transform-origin: top right;
}
.box span:last-of-type {
right: 0;
transform: skewY(-35deg);
transform-origin: top left;
}
.box span::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to bottom, blue , red );
transform-origin: inherit;
}
.box span:first-of-type::before {
transform: skewY(-35deg);
}
.box span:last-of-type::before {
transform: skewY(35deg);
}
p {
margin:0;
color:#fff;
font-size:45px;
line-height:100px;
text-align:center;
}
<div class="box">
<span></span><span></span>
<p>29</p>
</div>
Here is how we can do with a left or right gradient. In this case we don't need extra elements because the skew will not affect the direction:
.box {
width: 150px;
height: 150px;
position: relative;
z-index:0;
overflow: hidden;
filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
}
.box:before,
.box:after{
content:"";
position: absolute;
z-index:-1;
top: 0;
width: 50%;
height: 100%;
overflow: hidden;
background:linear-gradient(to right,blue,red);
background-size:200% 100%;
}
.box:before{
left: 0;
transform: skewY(35deg);
transform-origin: top right;
}
.box:after{
right: 0;
transform: skewY(-35deg);
transform-origin: top left;
background-position:right;
}
p {
margin:0;
color:#fff;
font-size:45px;
line-height:100px;
text-align:center;
}
<div class="box">
<p>29</p>
</div>
And here is with an arbitrary gradient:
.box {
--g:linear-gradient(45deg,blue,red 60%,yellow); /* gradient coloration*/
width: 150px;
height: 150px;
margin:15px;
display:inline-block;
position: relative;
z-index:0;
overflow: hidden;
filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
}
.box span {
position: absolute;
z-index:-1;
top: 0;
width: 50%;
height: 100%;
overflow: hidden;
}
.box span:first-of-type {
left: 0;
transform: skewY(35deg);
transform-origin: top right;
}
.box span:last-of-type {
right: 0;
transform: skewY(-35deg);
transform-origin: top left;
}
.box span::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--g);
background-size:200% 100%;
transform-origin: inherit;
}
.box span:first-of-type::before {
transform: skewY(-35deg);
}
.box span:last-of-type::before {
transform: skewY(35deg);
background-position:right;
}
p {
margin:0;
color:#fff;
font-size:45px;
line-height:100px;
text-align:center;
}
<div class="box">
<span></span><span></span>
<p>29</p>
</div>
<div class="box" style="--g:linear-gradient(-62deg,blue,red 60%,yellow)">
<span></span><span></span>
<p>29</p>
</div>
Since each element is taking 50% of the width we make the background to be 200% to have its size as the main container then we adjust the position to create the illusion of one background. It's like each element will show half of the main background.
An optimized version using mask
.box {
width: 150px;
height: 150px;
filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
}
.box > div {
height: 100%;
background: linear-gradient(35deg, blue, red);
-webkit-mask:
linear-gradient(#fff, #fff) top/100% 70%,
linear-gradient(to bottom right, #fff 49.5%, transparent 50%) bottom right/50% 30%,
linear-gradient(to bottom left, #fff 49.5%, transparent 50%) bottom left /50% 30%;
mask:
linear-gradient(#fff, #fff) top/100% 70%,
linear-gradient(to bottom right, #fff 49.5%, transparent 50%) bottom right/50% 30%,
linear-gradient(to bottom left, #fff 49.5%, transparent 50%) bottom left /50% 30%;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
}
p {
margin: 0;
color: #fff;
font-size: 45px;
line-height: 100px;
text-align: center;
}
<div class="box">
<div>
<p>29</p>
</div>
</div>
Or clip-path
.box {
width: 150px;
height: 150px;
filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
}
.box > div {
height: 100%;
background: linear-gradient(35deg, blue, red);
clip-path:polygon(0 0,100% 0,100% 70%,50% 100%,0 70%);
}
p {
margin: 0;
color: #fff;
font-size: 45px;
line-height: 100px;
text-align: center;
}
<div class="box">
<div>
<p>29</p>
</div>
</div>
You can use clip-path as I did. Here is my solution.
.design {
background: #ea053a;
-webkit-clip-path: polygon(50% 0%, 100% 0, 100% 75%, 50% 100%, 0% 75%, 0 0);
clip-path: polygon(50% 0%, 100% 0, 100% 75%, 50% 100%, 0% 75%, 0 0);
height: 155px;
width: 155px;
}
.month {
text-align:center;
padding: 1rem 0 .25rem 0;
color:#fff;
font-weight:bold;
font-size: 18px;
}
.day {
text-align: center;
font-size: 60px;
font-weight:bold;
color: #fff;
}
<div class="design">
<div class="month">Diciembre</div>
<div class="day">29</div>
</div>
If you change your CSS to the following minor changes, then you can achieve the result that you have expected:
.design {
background: #ea053a;
display: inline-block;
height: 100px;
margin-left: 33px;
margin-right: 40px;
position: relative;
width: 180px;
}
.design:before {
border-top: 43px solid #ea053a;
border-left: 90px solid transparent;
border-right: 90px solid transparent;
margin-right: 40px;
content: "";
height: 0;
left: 0;
position: absolute;
top: 0px;
margin-top: 100px;
width: 0;
}
Here is the working of the above CSS:
.design {
background: #ea053a;
display: inline-block;
height: 100px;
margin-left: 33px;
margin-right: 40px;
position: relative;
width: 180px;
}
.design:before {
border-top: 43px solid #ea053a;
border-left: 90px solid transparent;
border-right: 90px solid transparent;
margin-right: 40px;
content: "";
height: 0;
left: 0;
position: absolute;
top: 0px;
margin-top: 100px;
width: 0;
}
<div class="design">
</div>
Hope this was helpful.
My Fiddle
Change to (only changed lines listed, keep everything else as-is):
.design:before {
...
border-left: 114px solid transparent;
border-right: 114px solid transparent;
...
width: 0;
}
Here is my solution to add shadow and gradient to the shape
.design {
background: #ea053a;
display: inline-block;
height: 155px;
margin-left: 33px;
margin-right: 40px;
position: relative;
width: 228px;
filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
}
.triangle {
position: absolute;
height: 100px;
top: 155px;
width: 228px;
-webkit-clip-path: polygon(49% 44%, 0% 100%, 100% 100%);
clip-path: polygon(49% 44%, 0% 100%, 100% 100%);
background-color: #ea053a;
transform: rotate(180deg);
}
<div class="design">
<div class="triangle">
</div>
</div>
I am trying to take this css Octagon and give it a solid red border. However, when i add the border it only works on portion of the shape. Does anyone have a solution for this?
Here is a JS FIDDLE
HTML
<div class='octagonWrap'>
<div class='octagon'></div>
</div>
CSS
.octagonWrap{
width:200px;
height:200px;
float: left;
position: relative;
}
.octagon{
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
overflow: hidden;
}
.octagon:before {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
transform: rotate(45deg);
background: #777;
content: '';
border: 3px solid red;
}
You can modify your own code to work with this. Right now, you have rules for .octagon that should be for .octagon-wrapper, and rules for .octagon::before that should be for .octagon. Just shift the CSS rules and have them apply to their parents, while changing the border property of .octagon::before to inherit from .octagon.
.octagonWrap {
width:200px;
height:200px;
float: left;
position: relative;
overflow: hidden;
}
.octagon {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
overflow: hidden;
transform: rotate(45deg);
background: #777;
border: 3px solid red;
}
.octagon:before {
position: absolute;
/* There needs to be a negative value here to cancel
* out the width of the border. It's currently -3px,
* but if the border were 5px, then it'd be -5px.
*/
top: -3px; right: -3px; bottom: -3px; left: -3px;
transform: rotate(45deg);
content: '';
border: inherit;
}
<div class='octagonWrap'>
<div class='octagon'></div>
</div>
SVG solution
I do not know if using svg is an option,
If it is here is how simple it is done.
<svg viewBox="0 0 75 75" width="200px">
<path d="m5,22 18,-18 28,0 18,18 0,28 -18,18, -28,0 -18,-18z" stroke="red" stroke-width="2" fill="black" />
</svg>
You could use an online calculator (or calculate it manually) to compute the size in which the ratio of the side, and overall height needs to be.
Then by using some pseudos and a span element, you could create this shape via:
.oct {
height: 241px;
width: 100px;
background: none;
position: relative;
-webkit-box-sizing: border-box;
box-sizing: border-box;
border-top: 10px solid tomato;
border-bottom: 10px solid tomato;
margin: 100px auto;
transition: all 0.8s;
}
.oct:before,
.oct:after,
.oct span {
content: "";
position: absolute;
height: inherit;
width: inherit;
background: inherit;
-webkit-box-sizing: inherit;
box-sizing: inherit;
border: inherit;
top: -10px;
z-index:-1;
}
.oct:before {
left: -100%;
transform: rotate(-45deg);
transform-origin: top right;
}
.oct:after {
left: 100%;
transform: rotate(45deg);
transform-origin: top left;
}
.oct span {
height: inherit;
width: inherit;
background: inherit;
transform: rotate(90deg);
}
.oct:hover {
transform: rotate(180deg);
}
<div class="oct">
<span></span>
</div>
You can do that very effectively with clip-path
.octagonWrap {
background: red;
width: 200px;
height: 200px;
position: absolute;
-webkit-clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
}
.octagon {
position: relative;
background: gray;
width: 190px;
height: 190px;
top: 5px;
left: 5px;
-webkit-clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
}
<div class="octagonWrap">
<div class='octagon'></div>
</div>
Imagine those red lines extending until they touch each other. That square (rotated 45%) has a complete border, you just don't see the "cut off" corners due to the overflow: hidden;
This seems to work (but does so by adding two extra divs, so there may be a better way):
<div class='octagonWrap'>
<div class='octagon'></div>
<div class='vert'> </div>
<div class='hort'> </div>
</div>
and then add tihs css:
.vert {
position: absolute;
left: 60px;
border-top: 3px solid red;
border-bottom: 3px solid red;
height: 194px;
width: 80px;
}
.hort {
position: absolute;
top: 60px;
border-left: 3px solid red;
border-right: 3px solid red;
width: 94px;
height: 80px;
}
You should try using the HTML5 canvas element. You should be able to draw the polygon and then add a stroke to it.
I'm trying to replicate the following shape with no success:
I'm guessing I'll need some :before and :after pseudo elements along with the following css:
#pentagon {
position: relative;
width: 78px;
height:50px;
background:#3a93d0;
}
Using Border Method:
You can do it using the below CSS. The shape is obtained by placing a triangle shape at the bottom of the rectangle using :after pseudo element. The triangular part is achieved using border method.
.pentagon {
height: 50px;
width: 78px;
background: #3a93d0;
position: relative;
}
.pentagon:after {
border: 39px solid #3a93d0;
border-top-width: 15px;
border-color: #3a93d0 transparent transparent transparent;
position: absolute;
top: 50px;
content: '';
}
<div class="pentagon"></div>
Using CSS Transforms:
This approach uses rotate, skewX and hence would need a fully CSS3 compliant browser to work properly. The advantage of this approach is that it allows borders to be added around the shape unlike when using border method. The drawback is that it needs additional calculations for the angles.
It is a modified version of the short triangle method mentioned in this CodePen demo by web-tiki.
.pentagon {
position: relative;
height: 50px;
width: 78px;
background: #3a93d0;
}
.pentagon:before {
position: absolute;
content: '';
top: 12px;
left: 0;
width: 46px;
height: 38px;
background: #3a93d0;
transform-origin: 0 100%;
transform: rotate(29deg) skewX(-30deg);
}
.pentagon.bordered {
background: white;
border: 1px solid #3a93d0;
}
.pentagon.bordered:before {
width: 44px;
height: 37px;
background: white;
border: 1px solid #3a93d0;
border-color: transparent #3a93d0 #3a93d0 transparent;
transform: rotate(29deg) skewX(-30deg);
}
/* Just for demo */
.pentagon {
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="pentagon"></div>
<div class="pentagon bordered"></div>
Using CSS Skew Transforms:
This approach uses just skew() (along both X and Y axes) and does not need any complex angle calculations. It just needs the dimensions and position of the pseudo-element to be adjusted as the dimension of the parent changes.
.pentagon {
position: relative;
height: 50px;
width: 78px;
border: 1px solid #3a93d0;
border-bottom: none;
background: aliceblue;
}
.pentagon:before {
position: absolute;
content: '';
top: 10px; /* parent height - child height -1px */
left: -1px;
width: 39px;
height: 39px; /* width of parent/2 */
border-right: 1px solid #3a93d0;
border-bottom: 1px solid #3a93d0;
background: aliceblue;
transform-origin: 0 100%;
transform: matrix(1, 0.414213562373095, -1, 0.41421356237309515, 0, 0);
}
<div class="pentagon">
</div>
The above snippet uses matrix transform because as per MDN, the skew(x, y) is removed and should not be used anymore. The Matrix Resolutions site can be used to obtain the equivalent matrix function. The matrix function for rotate(45deg) skew(-22.5deg, -22.5deg) is
matrix(1, 0.414213562373095, -1, 0.41421356237309515, 0, 0).
Using Clip Path:
Here is another approach to creating the pentagon shape with clip-path. Either a pure CSS clip-path or one with inline SVG can be used depending on required browser support. CSS clip-path is supported only by Webkit browsers at present.
IE (all versions) do not support either the CSS or the SVG clip-path.
.pentagon {
position: relative;
width: 75px;
height: calc(75px / 1.414);
background: #3a93d0;
}
.pentagon.css {
-webkit-clip-path: polygon(0% 0%, 0% 66%, 50% 100%, 100% 66%, 100% 0%);
clip-path: polygon(0% 0%, 0% 66%, 50% 100%, 100% 66%, 100% 0%);
}
.pentagon.svg {
-webkit-clip-path: url(#clipper);
clip-path: url(#clipper);
}
.pentagon.bordered:after {
position: absolute;
content: '';
height: calc(100% - 2px);
width: calc(100% - 2px);
left: 1px;
top: 1px;
background: white;
}
.pentagon.css.bordered:after {
-webkit-clip-path: polygon(0% 0%, 0% 66%, 50% 100%, 100% 66%, 100% 0%);
clip-path: polygon(0% 0%, 0% 66%, 50% 100%, 100% 66%, 100% 0%);
}
.pentagon.svg.bordered:after {
-webkit-clip-path: url(#clipper);
clip-path: url(#clipper);
}
/* Just for demo */
.pentagon {
margin: 10px;
}
<svg width="0" height="0">
<defs>
<clipPath id="clipper" clipPathUnits="objectBoundingBox">
<path d="M0,0 0,0.66 0.5,1 1,0.66 1,0z" />
</clipPath>
</defs>
</svg>
<h3>CSS Clip Path</h3>
<div class="pentagon css"></div>
<div class="pentagon bordered css"></div>
<h3>SVG Clip Path</h3>
<div class="pentagon svg"></div>
<div class="pentagon bordered svg"></div>
You can try an alternate approach using transform scaleX and rotate: 45deg;. This makes it very easy to create the bottom part of the shape.
transform: scaleX() rotate(45deg);
Working
*sorry for bad quality gif! :(
Sans border:
Fiddle
#pent{
height: 50px;
width: 100px;
position: relative;
background-color: deepskyblue;
}
#pent:before{
content: '';
position: absolute;
bottom: 0;
left: 0;
width:45px;
height:45px;
-webkit-transform-origin: 0 100%;
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
transform-origin: 0 100%;
-webkit-transform: scaleX(1.57) rotate(45deg);
-moz-transform: scaleX(1.57) rotate(45deg);
-ms-transform: scaleX(1.57) rotate(45deg);
transform: scaleX(1.57) rotate(45deg);
background-color: deepskyblue;
}
<div id="pent"></div>
With border :
Fiddle
#pent{
height: 50px;
width: 100px;
position: relative;
border: 1px solid black;
border-bottom: 0;
}
#pent:before{
content: '';
position: absolute;
bottom: 0;
left: -1px;
width:45px;
height:45px;
-webkit-transform-origin: 0 100%;
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
transform-origin: 0 100%;
-webkit-transform: scaleX(1.57) rotate(45deg);
-moz-transform: scaleX(1.57) rotate(45deg);
-ms-transform: scaleX(1.57) rotate(45deg);
transform: scaleX(1.57) rotate(45deg);
border: 1px solid black;
border-top: 0;
border-left: 0;
}
<div id="pent"></div>
See a demo - basically it uses css triangles and a pseudo element to give a place for the triangle.
.shape {
position: relative;
width: 78px;
height:30px;
background:#3a93d0;
}
.shape:after {
content: '';
display: block;
position: absolute;
top: 100%;
width: 0;
height: 0;
border-style: solid;
border-width: 25px 39px 0 39px;
border-color: #3a93d0 transparent transparent transparent;
}
<style>
#pentagon
{
position: relative;
width: 54px;
border-width: 40px 18px 0;
border-style: solid;
border-color: #3a93d0;
}
#pentagon:after {
border-color: #3a93d0 transparent transparent;
border-style: solid;
border-width: 21px 45px 0;
content: "";
height: 0;
left: -17px;
position: absolute;
top: 0;
width: 0;
}
</style>
if you dont want to use css3 you can do it with css
only problem is this implementation is not responsive. :(
<pre>
<div class="moregrey"></div>
<div class="arrowdown"></div>
.moregrey
{
width: 1000px;
height: 30px;
background: #3f3f40;
}
.arrowdown
{
border-top:50px solid #3f3f40;
border-left:500px solid transparent;
border-bottom:500px solid transparent;
border-right:500px solid transparent;
display:block;
width:0px;
height:10px;
}
</pre>
<pre>
http://jsfiddle.net/jmqoj5nh/1/
</pre>