Using perspective and transform ruins my site at different resolutions - css

I'm trying to create a 3D responsive mockup for a sign with perspective and transform, but I'm having some difficulty.
This is what I'm trying to do:
It looks good but when I'm changing my screen size it looks terrible:
I really don't know how to make it responsive.
This is my code up to now:
#import url('https://fonts.googleapis.com/css?family=Pacifico');
* {
padding: 0;
margin: 0;
font-family: 'Pacifico', cursive;
}
.mockup {
position: relative;
width: 100%;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-perspective: 500px;
perspective: 500px;
}
.mockup--background {
width: 100%;
}
.mockup--crop {
position: absolute;
top: 30%;
left: 14%;
width: 52%;
padding: 1.8% 0;
font-size: 3em;
text-align: center;
background: rgb(141,126,127);
color: #fff;
text-shadow: -1px 0px #bab1b2,
-2px 1px #bab1b2,
-3px 2px #bab1b2,
-5px 3px #bab1b2,
-5px 4px #bab1b2,
-6px 5px #bab1b2;
background: -moz-linear-gradient(45deg, rgba(141,126,127,1) 0%, rgba(169,160,165,1) 100%);
background: -webkit-linear-gradient(45deg, rgba(141,126,127,1) 0%,rgba(169,160,165,1) 100%);
background: linear-gradient(45deg, rgba(141,126,127,1) 0%,rgba(169,160,165,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#8d7e7f', endColorstr='#a9a0a5',GradientType=1 );
}
.perspective {
transform: rotateY(22deg) rotateX(6deg) skewY(22deg) skewX(-2deg);
}
<div class="mockup">
<img class="mockup--background" src="https://designshack.net/wp-content/uploads/screenshot_1-o-1024x681.png" />
<div class="mockup--crop perspective">
Mock Up
</div>
</div>
Fiddle demo

After a lot of fine-tuning, I think I've got it fit perfectly
Fiddle
The HTML now only consists of two elements
<div class="mockup">
<div class="mockup--crop">Mock Up</div>
</div>
I've removed the img tag because the image is clearly a background-image, so I figured it'd be semantically correct to move it to the CSS
.mockup{
position: relative;
perspective: 150vw;
padding-bottom: 66.5%;
background-image: url('https://designshack.net/wp-content/uploads/screenshot_1-o-1024x681.png');
background-size: 100% 100%;
}
.mockup--crop {
position: absolute;
top: 16.125%;
left: 17.5%;
width: 63.2%;
height: 28.8%;
background-image: linear-gradient(to bottom right, #8D7E7F 0%, #A9A0A5 100%);
text-align: center;
font-size: 10vw;
color: #FFF;
text-shadow: -.1vw .1vw #BAB1B2,-.2vw .2vw #BAB1B2,-.3vw .3vw #BAB1B2,-.4vw .4vw #BAB1B2,-.5vw .5vw #BAB1B2,-.6vw .6vw #BAB1B2,-.7vw .7vw #BAB1B2,-.8vw .8vw #BAB1B2,-.9vw .9vw #BAB1B2,-1vw 1vw #BAB1B2;
transform: rotateZ(18.7deg) rotateY(47.5deg) rotateX(32.9deg);
transform-origin: 0 0;
}
.mockup has a padding-bottom of 66.5%, which is the ratio of the image (100 / (1024 / 681)). It also has a perspective of 150vw. This is a value I've come to as I was tweaking the transforms etc.
I've moved .mockup--crop's upper left corner to the upper left corner of the sign in the background, and gave it perspective-origin: 0 0;, so that I could easily transform it with a fixed, correct point. The rest is self explanatory.
#noJavaScript

Related

Creating a diagonal line/section/border with CSS

I am trying to create a diagonal line on a webpage, to act as a section/section break. This is essentially a split colour section. I cant use an image as if the page gets enlarged, the image is going to pixelate. So i need to be able to draw a diagonal line directly at the bottom of the div, like the image below.
I have tried using a border, however i cannot get the actual break to be in the middle, rather than the right or left hand side.
Is there a way to draw diagonal lines in CSS? As you can see, i need to create a div that is 90px high and have the split/diagonal line in that div. I can then have a look at adding the image, but the main issue is not knowing whether this is possible with CSS.
With an svg, it is pretty simple :
svg {
display: block;
width: 100%;
height: 90px;
background: yellow;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 10" preserveAspectRatio="none">
<polygon points="100 0 100 10 0 10" />
</svg>
Note that I used the preserveAspectRatio="none" attribute so that the shape can have 100% width and keep 90px height
And here with a monkey image :
div {
position: relative;
}
svg {
display: block;
width: 100%;
height: 90px;
background: yellow;
}
img {
height: 50px;
position: absolute;
top: 0; bottom: 0;
left: 0; right: 0;
margin: auto;
background: #fff;
border-radius: 50%;
padding: 10px;
}
<div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 10" preserveAspectRatio="none">
<polygon points="100 0 100 10 0 10" />
</svg>
<img src="http://images.clipartpanda.com/monkey-clipart-black-and-white-16981-monkey-face-svg.svg" alt="" />
</div>
You can do this without any clipping and just using borders in a unique way. This should also be cross-browser compatible, but I haven't tested it across everything
Initially divided this into 2 separate divs / triangles and joined them, but thanks to web-tiki and kaiido perfected it to use only 1 div and minimal CSS
*{
border: 0;
padding: 0;
margin: 0;
}
#gradient {
width: 0;
height: 0;
border-style: solid;
border-width: 90px 100vw 0 0;
border-color: yellow black transparent transparent;
transform: scale(1.0001);
}
<div id="gradient"></div>
Original Answer using multiple divs:
*{
border: 0;
padding: 0;
margin: 0;
}
#container {
width: 100%;
position: relative;
}
#container div {
position: absolute;
}
#top-triangle {
width: 0;
height: 0;
border-style: solid;
border-width: 90px 100vw 0 0;
border-color: yellow transparent transparent transparent;
}
#bottom-triangle {
width: 0;
height: 0;
border-style: solid;
border-width: 0 0 90px 100vw;
border-color: transparent transparent black transparent;
}
<div id="container">
<div id="top-triangle"></div>
<div id="bottom-triangle"></div>
</div>
Use a linear gradient
div {
height: 90px;
background-image: linear-gradient(to bottom right, yellow, yellow 50%, black 50%, black);
}
<div></div>
You can use CSS3 clip:
.yellow {
width: 100%;
height: 90px;
background: yellow;
-webkit-clip-path: polygon(100% 0, 0 0, 0 100%);
clip-path: polygon(100% 0, 0 0, 0 100%);
}
.black {
width: 100%;
height: 90px;
background: black;
-webkit-clip-path: polygon(100% 0, 0 100%, 100% 99%);
clip-path: polygon(100% 0, 0 100%, 100% 99%);
margin-top: -90px;
}
<div class="yellow"></div>
<div class="black"></div>
Demo: http://jsfiddle.net/zLkrfeev/2/
It's not widely supported by the browsers: http://caniuse.com/#feat=css-clip-path
if you want to put diagonal border in column you can do it this way and its 100% responsive. your requirement might be different though. I put it transparent image which contains white diagonal border in that section's right column.
<div id="wrapper">
<div class="h-row">
<div class="h-left">
</div>
<div class="h-right">
<div class="hr-box"></div>
</div>
</div>
</div>
<style>
.h-row{display: table; table-layout: fixed; height: 100%; width: 100%;}
.h-left,
.h-right{display: table-cell; vertical-align: top; height:250px;}/*height is just for demo purpose you can remove it ofcourse and fill the content */
.h-left{background: #e9eae2; padding: 50px 83px 15px 165px; width: 69%;}
.h-right{background: #7acec3 url('https://previews.dropbox.com/p/thumb/AAMv9WREPIx2AXUVhzCrK5Hl1jxf3ofX0teck9P94bG_SCjB28QPmKqXuchYyjp_xFMjMrGLzRYHh0O9wBOZJMZW9L_97lScKB22dgco9eGMJ1PCBbFepUcDkPg3aUE_1ONik2rKQ2SgRvtUgdq8nA_Ev1gxLxq8yWcXNKOdxKGBNOqe4FTHnbAgGy-JD4UtwZliw8c0fmNah8rydlD4JetFxNubkUyW4I_Q-XRL5qjW9A/p.png?size=1280x960&size_mode=3') no-repeat center center/ 100% 100%; padding: 50px 165px 15px 0; width: 31%; position: relative;}
.h-left .row{margin:0 -44px;}
</style>
https://codepen.io/neel555nc/pen/LgjoOg
You can do this using a gradient.
body {
height: 200px;
margin: 0 0 20px 0;
background-color: transparent;
background-size: 20px 20px;
background-image:
-webkit-repeating-linear-gradient(-45deg, black, black 1px, transparent 1px, transparent 14px);
background-image:
-moz-repeating-linear-gradient(-45deg, black, black 1px, transparent 1px, transparent 14px);
background-image:
-o-repeating-linear-gradient(-45deg, black, black 1px, transparent 1px, transparent 14px);
background-image:
repeating-linear-gradient(-45deg, black, black 1px, transparent 1px, transparent 14px);
}
JSFiddle

3D Box Shadow effect

So I know how to do a basic box shadow with CSS3. You can see that in the top of the graphic below.
The effect I'm trying to achieve is a 3D box shadow, as shown in the bottom of the graphic below.
Any ideas on how to do this with CSS3 box shadows?
Unfortunately box shadows are effectively just flat layers. However you can apply multiple box shadows to create this effect.
.box-shadow-3d{
box-shadow: 1px 1px 0px #999,
2px 2px 0px #999,
3px 3px 0px #999,
4px 4px 0px #999,
5px 5px 0px #999,
6px 6px 0px #999;
}
you can use pseudo element for as shadow
div {
background: black;
height: 100px;
width: 100px;
position: relative;
}
div:after,
div:before {
content: '';
background: grey;
position: absolute;
}
div:after {
width: 100%;
height: 20px;
left: 10px;
bottom: 0;
transform: translatey(100%) skewx(45deg);
}
div:before {
width: 20px;
height: 100%;
right: 0;
transform: translatex(100%) skewy(45deg);
top: 10px;
}
<div></div>
Here is a real 3D shadow using perspective and pseudo-element :before.
body {
background: lightblue;
}
.foo {
position: relative;
display: inline-block;
-webkit-perspective: 1000px;
-moz-perspective: 1000px;
persepctive: 1000px;
margin: 20px;
margin-top: 50px;
}
.foo .box {
transform: rotateY(-40deg);
height: 350px;
width: 250px;
background-color: black;
}
.foo:before {
content: "";
top: -15px;
position: absolute;
width: 50px;
height: 375px;
background-color: grey;
transform: translateX(215px) translateY(2.7px) rotateY(55deg)
}
<div class="foo">
<div class="box"></div>
</div>
You can stack the horizontal/vertical offsets of several box-shadows, each slightly bigger than the previous one. The more shadows you add, the more pronounced the effect. Here is a fiddle example.
div {
background: black;
height: 100px;
width: 100px;
box-shadow: 0 01px gray,
01px 0 gray,
01px 02px gray,
02px 01px gray,
02px 03px gray,
03px 02px gray,
03px 04px gray,
04px 03px gray,
04px 05px gray,
05px 04px gray,
05px 06px gray,
06px 05px gray;
}
I had some problems with these two options, so I adapted some diagonal gradients from Lea Verou's excellent book CSS Secrets. I thought about creating a gradient inside a right and bottom border via border-image, but that property does not allow edge targeting, à la border-right-image, etc.
So, I settled on using a pseudo element with two truncated corners, which seems to work pretty well. You have to be careful to adjust the width of the gradient to be 1.414 the size of half the padding, since this would be the diagonal of a square (square root of two). Also, since that's a pseudo element, be careful of the right placement. Interested to hear what you folks think.
div {
background: #bbb;
padding: 1em 1.2em;
width: 50%;
margin: 0 auto;
color: #111;
font: 150%/1.2 Georgia, Palatino, Times, serif;
position: relative;
}
div:after {
content:" ";
position:absolute;
top:0;
left: 0;
width:100%;
height:100%;
padding: 1.42em; /* (square root of gradient position) */
background: #000; /* Fallback if not supported */
background: linear-gradient(-135deg, transparent 2em, #000 0) top right,
linear-gradient(#000, #000) padding-box bottom right,
linear-gradient(45deg, transparent 2em, #000 0) bottom left;
/*I have avoided adding -webkit-, -moz and -0 prefixs for linear-gradient. You may put them in later to be extra safe*/
background-size: 50% 50%; /* There is no reason to paint the upper left quadrant, so I didn't. */
background-repeat: no-repeat;
-webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box;
/* Many people use border-box as default these days. Unfortunately, the box cannot be sized using border-box settings with the combination of padding in ems and percentages. So this is reset to content-box, just in case. */
z-index: -1; /* To keep the shadow behind the div*/
<div>This is a short sentence to demonstrate that our little div is responsive.</div>
Here's a little implementation, inspired by #Vitorino fernandes, in stylus...
offset = 10
border = 3
.offsetbox
margin offset
padding offset
text-align center
box-shadow inset 0 0 0 unit(border,px) black
background white
display inline-block
position relative
&:after,
&:before
content ''
background black
position absolute
&:after
width 100%
height offset
transform translatey(100%) skewx(-45deg)
right (offset/2)
bottom 0
&:before
height 100%
width offset
transform: translatex(-100%) skewy(-45deg)
left 0
top (offset/2)
I added some clip paths to #Vittorino fernandes code, to avoid white space between pseudos and make it sharper.
I added some 1px adjustments to avoid bad svg rendering problems.
You can use the variable called shadow-dimension to set the shadow width and height.
I Put it on a codePen:
https://codepen.io/silviamalavasi/pen/XWqeWEq
:root {
--shadow-dimension: 20px;
--blue: #0039a6;
}
.box-container {
position: relative;
}
.box-container>div {
border: 2px solid var(--blue);
}
.box-container>div:after, .box-container>div:before {
content: '';
background-color: var(--blue);
position: absolute;
}
.box-container>div:before {
width: calc(var(--shadow-dimension) + 1px);
height: calc(100% + 100px + 1px);
left: calc(var(--shadow-dimension) * -1);
transform: skewy(-45deg);
top: calc(0.5*var(--shadow-dimension));
clip-path: polygon(0% 0%, 100% 0%, 100% calc(100% - 100px - 2px + var(--shadow-dimension)), 0% calc(100% - 100px - 2px));
}
.box-container>div:after {
width: calc(100% + 100px);
height: calc(var(--shadow-dimension) + 1px);
left: calc(-0.5*var(--shadow-dimension) - 100px);
bottom: 1px;
transform: translateY(100%) skewx(-45deg);
clip-path: polygon(100px 0%, 100% 0%, 100% 100%, calc(100px + 2px) 100%);
}

How do you style triangular mask in CSS?

I have been looking at how to do this "inverse triangular" background using css. I am referring to the white diagonal parts on the bottom, on top of the background (fixed) image.
The most I've gotten is to shapes, which aren't apparently a good solution having in mind that it is for a responsive design. I don't care if when the window is narrower there is just one diagonal, as long as there is no horizontal scroll. But shapes and its absolute width mess that up.
I apologize if this is a silly/common/often asked thing. I haven't been able to find it, most probably due to lack of technical term. Thank you very much :)
EDIT: The page keeps scrolling down! There is content below the diagonals/triangles. The triangles are not the bottom of the page.
Here's the fiddle with something similar and responsive: http://jsfiddle.net/BLbu5/
HTML:
<body>
<div id="triangle-holder">
<div id="triangle-1"></div>
<div id="triangle-2"></div>
</div>
</body>
CSS:
body {
background-image: url('http://miriadna.com/desctopwalls/images/max/Ideal-landscape.jpg');
margin: 0;
padding: 0;
}
#triangle-1 {
width: 0;
height: 0;
border-bottom: 30vw solid red;
border-right: 100vw solid transparent;
float: left;
}
#triangle-2 {
width: 0;
height: 0;
border-bottom: 30vw solid red;
border-left: 100vw solid transparent;
}
#triangle-holder {
position: absolute;
bottom: 0;
}
Read about the technique here: https://css-tricks.com/examples/ShapesOfCSS/
Hope it works!
You'd achieve the same result with a 'background img' with following styling:
#bg{
position: fixed;
top: 0px;
bottom: 0px;
width: 100%;
height: 100%;
z-index:-1;
-webkit-clip-path: polygon(
0 50%, 45% 90%, 100% 50%, 100% 0, 0 0
);
-moz-clip-path: polygon(
0 50%, 45% 90%, 100% 50%, 100% 0, 0 0
);
-ms-clip-path: polygon(
0 50%, 45% 90%, 100% 50%, 100% 0, 0 0
);
clip-path: polygon(
0 50%, 45% 90%, 100% 50%, 100% 0, 0 0
);
}
and in html you would add:
<img id = 'bg' src = 'path.jpg'> </img>
I would recommend using html canvas and either a rectangle with a triangle clip region or two inverted right-angle triangles positioned against the bottom edges.
This would require javascript.
Other than that you could use some CSS tricks like this: http://jsfiddle.net/pgLP2/
This would not be very elegant as it would require manual handling positions and dimension.
HTML:
<div class="content">Some Content</div>
<div id="toptriangle"></div>
CSS:
body {
color: white;
background-color: #666666;
}
.content {
text-align: center;
}
#toptriangle {
position: relative;
width: 0px;
height: 0px;
top: 100px;
left: -10px;
border-right: 500px solid white;
border-top: 300px solid transparent;
border-left: 500px solid white;
border-bottom: 400px solid white;
}

Make an arrow shape with responsive width and only CSS

I'm trying to make a container that has an upward arrow attached to it. I am familiar with the border drawing trick and think that's a likely solution, but it only works for known sizes I think, since you have to specify border in em or px.
The shape I would like to make is this:
.
/ \
/ \
/ \
| flex |
| |
Where the content area can flex to different sizes as a percentage of a parent container.
Here is the CSS, with the problem area flagged:
.metric {
display: inline-block;
position: relative;
height: 150px;
width: 50%;
background: lawngreen;
}
.metric:after {
position: absolute;
top: -25px;
left: 0;
content: '';
background: white;
width: 100%;
height: 0;
border: 75px solid white; /* this fixed width is the problem */
border-top: none;
border-bottom: 25px solid lawngreen;
box-sizing: border-box;
}
Here is the jsfiddle: http://jsfiddle.net/C8XJW/2/
Do you guys know any way to pull this off?
Here is another posibility.
This one does the trick with gradient backgrounds. You need 2 of them, so that the diagonal is easily achieved:
Relevant CSS:
.metric:before, .metric:after {
position: absolute;
top: -25px;
content: '';
width: 50%;
height: 25px;
}
.metric:before {
left: 0px;
background: linear-gradient(to right bottom, transparent 50%, lawngreen 50%);
}
.metric:after {
right: 0px;
background: linear-gradient(to left bottom, transparent 50%, lawngreen 50%);
}
Updated Fiddle
The differences with Simple As Could Be solution:
Pro Transparent corners (relevant if you have a background)
Con Worse browser support
Here's one great solution. Bascially, you make the arrow always centered, and bigger than you'd ever need it, but lop off the overflow.
Here's the JSFiddle:
http://jsfiddle.net/nBAK9/4/
And here's the interesting code:
.metric:after {
position: absolute;
top: 0;
left: 50%;
margin-left: -250px; /* max expected width /2 */
content: '';
background: white;
width: 500px; /* max expected width */
height: 0;
border: 250px solid white; /* max expected width /2 */
border-top: none;
border-bottom: 50px solid #cf6; /* This size adjusts the slope of the triangle */
box-sizing: border-box;
}
Not sure you can, I played with it found that since em inherits from parents you can play a bit with it.
body{
font-size: 3em;
}
div {
width: 0;
height: 0;
border-style: solid;
border-width: 0 3em 4em 7em;
border-color: transparent transparent #007bff transparent;
-webkit-transform:rotate(360deg)
}
Fiddle
.top-arrow:before, .top-arrow:after {
position: absolute;
top: -25px;
content: '';
width: 50%;
height: 25px;
}
.top-arrow:before {
left: 0px;
background: linear-gradient(to right bottom, transparent 50%, black 50%);
}
.top-arrow:after {
right: 0px;
background: linear-gradient(to left bottom, transparent 50%, black 50%);
}
<div class="top-arrow"></div>

How can I show only corner borders?

I'm wondering if it's possible in CSS to make a border but only for corner. Something like this:
**** ****
* *
* *
CONTENT
* *
* *
**** ****
You can achieve that using multiple linear gradients as a background image.
div {
width: 100px;
height: 100px;
background:
linear-gradient(to right, black 4px, transparent 4px) 0 0,
linear-gradient(to right, black 4px, transparent 4px) 0 100%,
linear-gradient(to left, black 4px, transparent 4px) 100% 0,
linear-gradient(to left, black 4px, transparent 4px) 100% 100%,
linear-gradient(to bottom, black 4px, transparent 4px) 0 0,
linear-gradient(to bottom, black 4px, transparent 4px) 100% 0,
linear-gradient(to top, black 4px, transparent 4px) 0 100%,
linear-gradient(to top, black 4px, transparent 4px) 100% 100%;
background-repeat: no-repeat;
background-size: 20px 20px;
}
<div></div>
Assuming <div id="content">CONTENT</div> and that CONTENT includes at least one HTML node.
#content {position:relative}
#content:before, #content:after, #content>:first-child:before, #content>:first-child:after {
position:absolute; content:' ';
width:80px; height: 80px;
border-color:red; /* or whatever colour */
border-style:solid; /* or whatever style */
}
#content:before {top:0;left:0;border-width: 1px 0 0 1px}
#content:after {top:0;right:0;border-width: 1px 1px 0 0}
#content>:first-child:before {bottom:0;right:0;border-width: 0 1px 1px 0}
#content>:first-child:after {bottom:0;left:0;border-width: 0 0 1px 1px}
Here's a Fiddle
I would use overlapping divs.
One with square corners.
And the Other with rounded corner (so it doesn't hide the corners of the first one).
#div1 {
position:absolute;
top:9px;
left:9px;
height:100px;
width:100px;
background-color:white;
border:1px solid black;
}
#div2 {
position:relative;
top:-1px;
left:-1px;
height:102px;
width:102px;
background-color:white;
border-radius: 15px;
}
<div id="div1" />
<div id="div2" />
Result:
An enhanced solution provided by #web-tiki:
http://jsfiddle.net/webtiki/y3EfP/147/
Here is an idea using gradient and CSS variables where you can easily control the shape of your border:
.box {
--b: 5px; /* thickness of the border */
--c: red; /* color of the border */
--w: 20px; /* width of border */
border: var(--b) solid #0000; /* space for the border */
--_g: #0000 90deg,var(--c) 0;
--_p: var(--w) var(--w) border-box no-repeat;
background:
conic-gradient(from 90deg at top var(--b) left var(--b),var(--_g)) 0 0 / var(--_p),
conic-gradient(from 180deg at top var(--b) right var(--b),var(--_g)) 100% 0 / var(--_p),
conic-gradient(from 0deg at bottom var(--b) left var(--b),var(--_g)) 0 100% / var(--_p),
conic-gradient(from -90deg at bottom var(--b) right var(--b),var(--_g)) 100% 100% / var(--_p);
/*Irrelevant code*/
width:200px;
height:100px;
box-sizing:border-box;
margin:5px;
display:inline-flex;
font-size:30px;
justify-content:center;
align-items:center;
text-align:center;
}
<div class="box">
some content
</div>
<div class="box" style="--c:blue;--w:40px;--b:2px">
some content
</div>
<div class="box" style="--c:green;--w:30%;--b:8px">
some content
</div>
<div class="box" style="--c:black;--w:50%;--b:3px">
some content
</div>
<div class="box" style="--c:purple;--w:10px;--b:10px">
some content
</div>
<div class="box" style="--c:orange;--w:calc(50% - 10px);--b:4px">
some content
</div>
You can also have a complex coloration if you combine this with mask:
.box {
--b: 5px; /* thickness of the border */
--c: red; /* color of the border */
--w: 20px; /* width of border */
padding: var(--b); /* space for the border */
position:relative;
/*Irrelevant code*/
width:200px;
height:100px;
box-sizing:border-box;
margin:5px;
display:inline-flex;
font-size:30px;
justify-content:center;
align-items:center;
text-align:center;
}
.box::before {
content :"";
position: absolute;
inset: 0;
background: var(--c,red);
--_g: #0000 90deg,#000 0;
--_p: var(--w) var(--w) no-repeat;
--mask:
conic-gradient(from 90deg at top var(--b) left var(--b),var(--_g)) 0 0 / var(--_p),
conic-gradient(from 180deg at top var(--b) right var(--b),var(--_g)) 100% 0 / var(--_p),
conic-gradient(from 0deg at bottom var(--b) left var(--b),var(--_g)) 0 100% / var(--_p),
conic-gradient(from -90deg at bottom var(--b) right var(--b),var(--_g)) 100% 100% / var(--_p);
-webkit-mask: var(--mask);
mask: var(--mask);
}
<div class="box">
some content
</div>
<div class="box" style="--c:repeating-linear-gradient(45deg,red,blue);--w:40px;--b:2px">
some content
</div>
<div class="box" style="--c:repeating-linear-gradient(90deg,#000 0 5px,transparent 5px 10px);--w:30%;--b:8px">
some content
</div>
<div class="box" style="--c:conic-gradient(red,green,yellow);--w:50%;--b:3px">
some content
</div>
<div class="box" style="--c:purple;--w:10px;--b:10px">
some content
</div>
<div class="box" style="--c:repeating-linear-gradient(45deg,orange 0 5px,blue 5px 10px);--w:calc(50% - 10px);--b:4px">
some content
</div>
And why not with radius:
.box {
--b: 5px; /* thickness of the border */
--c: red; /* color of the border */
--w: 20px; /* width of border */
--r: 25px; /* radius */
padding: var(--b); /* space for the border */
position:relative;
/*Irrelevant code*/
width:200px;
height:100px;
box-sizing:border-box;
margin:5px;
display:inline-flex;
font-size:30px;
justify-content:center;
align-items:center;
text-align:center;
}
.box::before {
content: "";
position: absolute;
inset: 0;
background: var(--c,red);
padding: var(--b);
border-radius: var(--r);
-webkit-mask:
linear-gradient( 0deg,#000 calc(2*var(--b)),#0000 0) 50% var(--b)/calc(100% - 2*var(--w)) 100% repeat-y,
linear-gradient(-90deg,#000 calc(2*var(--b)),#0000 0) var(--b) 50%/100% calc(100% - 2*var(--w)) repeat-x,
linear-gradient(#000 0 0) content-box,
linear-gradient(#000 0 0);
-webkit-mask-composite: destination-out;
mask-composite: exclude;
}
<div class="box">
some content
</div>
<div class="box" style="--c:repeating-linear-gradient(45deg,red,blue);--w:40px;--b:2px;--r:40px;">
some content
</div>
<div class="box" style="--c:repeating-linear-gradient(90deg,#000 0 5px,transparent 5px 10px);--w:30%;--b:8px">
some content
</div>
<div class="box" style="--c:conic-gradient(red,green,yellow);--w:50%;--b:3px">
some content
</div>
<div class="box" style="--c:purple;--w:10px;--b:10px;--r:0px">
some content
</div>
<div class="box" style="--c:repeating-linear-gradient(45deg,orange 0 5px,blue 5px 10px);--w:calc(50% - 10px);--b:4px;--r:10px">
some content
</div>
SVG
This is another great alternative if you now want to start using vectors to allow for great responsiveness.
<svg viewBox="0 0 100 100" width="50px">
<path d="M25,2 L2,2 L2,25" fill="none" stroke="black" stroke-width="3" />
<path d="M2,75 L2,98 L25,98" fill="none" stroke="black" stroke-width="3" />
<path d="M75,98 L98,98 L98,75" fill="none" stroke="black" stroke-width="3" />
<path d="M98,25 L98,2 L75,2" fill="none" stroke="black" stroke-width="3" />
</svg>
SVG is a great tool to use. Some of the advantages of using SVG in this case are:
Curve control
Fill control (opacity, color)
Stroke control (width, opacity, color)
Amount of code
Time to build and maintain the shape
Scalable
No HTTP request (if used inline like in the example)
Browser support for inline SVG goes back to Internet Explorer 9. See canIuse for more information.
You could absolutely position four <div>s, one in each corner, each with the appropriate two borders.
.corners {
position: relative;
width: 50px; /* for demo purposes */
padding: 10px;
}
.top, .bottom {
position: absolute;
width: 20px;
height: 20px;
pointer-events: none;
}
.top {
top: 0;
border-top: 1px solid;
}
.bottom {
bottom: 0;
border-bottom: 1px solid;
}
.left {
left: 0;
border-left: 1px solid;
}
.right {
right: 0;
border-right: 1px solid;
}
<div class="corners">
<div class="top left"></div>
<div class="top right"></div>
<div class="bottom right"></div>
<div class="bottom left"></div>
content goes here
</div>
Here are a couple of methods to create this effect without using any extra pseudo/real elements. One thing to note is that both these approaches would work only in modern browsers because they use CSS3 properties.
Using border-image: The border-image property makes it pretty easy to create such effects. The approach is as follows:
Create a transparent image which has borders just in the corner like here.
Set this image as the border-image-source and let the browser take care of the rest :) Since the default value for border-image-repeat is stretch, the browser would stretch the original image to fit the container even if the container becomes large.
The value set for the border-image-width property determines how thick the borders are.
.bordered {
background-color: beige;
border-image-source: url("http://i.stack.imgur.com/s2CAw.png");
border-image-slice: 1;
border-image-width: 5px;
}
.square {
height: 150px;
width: 150px;
}
.large-square {
height: 350px;
width: 350px;
}
/* Just for demo */
div {
margin-bottom: 10px;
}
<div class='bordered square'></div>
<div class='bordered large-square'></div>
Advantages:
Needs no extra elements (pseudo or real) which means less cluttered markup, pseudo elements can be used for other needs.
Is reasonably responsive. That is browser will adapt the borders even if container's dimensions change.
Drawbacks:
Relatively lower browser support. If IE10- support is needed then this is a no-go.
Since the border image is getting stretched, if the original image's canvas is a square and the container is a rectangle then the borders would look wider at top and bottom than left and right.
.bordered {
background-color: beige;
border-image-source: url("http://i.stack.imgur.com/s2CAw.png");
border-image-slice: 2;
border-image-width: 5px;
}
.small-square {
height: 75px;
width: 75px;
}
.square {
height: 150px;
width: 150px;
}
.large-square {
height: 350px;
width: 350px;
}
.rectangle {
height: 150px;
width: 250px;
}
.large-rectangle {
height: 150px;
width: 350px;
}
/* Just for demo */
div {
margin-bottom: 10px;
}
<div class='bordered small-square'></div>
<div class='bordered square'></div>
<div class='bordered large-square'></div>
<div class='bordered rectangle'></div>
<div class='bordered large-rectangle'></div>
Using background-image: The background-image property can also be used with linear-gradient images to produce the effect. The approach is as follows:
Create four linear-gradient images (two for top, bottom and two for left, right). These gradients would start with required color and continue to be that color for as many pixels as the width/height of the border image. After that it should be transparent.
For top and bottom borders, gradient's direction should be to right. For left and right borders, it should be to bottom.
The background-size value determines the thickness of the border. For top and bottom borders, the size of the gradient image would be 100% in X-axis and 5px (thickness) in Y-axis. For left and right borders, the size would 5px (thickness) in X-axis and 100% in Y-axis.
The background-repeat should be set to repeat-x for the top, bottom borders and to repeat-y for left and right borders.
The background-position is set to (-1 * half the size of the color in gradient) in the X or Y-axis as appropriate. This is to make half of the colored area appear on one side of the element while the other half appears on the other side (because gradient is repeating).
.bordered.square {
height: 150px;
width: 150px;
}
.bordered.rectangle {
height: 150px;
width: 250px;
}
.bordered {
background-color: beige;
background-image: linear-gradient(to right, black 30px, transparent 30px), linear-gradient(to right, black 30px, transparent 30px), linear-gradient(to bottom, black 30px, transparent 30px), linear-gradient(to bottom, black 30px, transparent 30px);
background-size: 100% 5px, 100% 5px, 5px 100%, 5px 100%;
background-position: -15px 0%, -15px 100%, 0% -15px, 100% -15px;
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
}
/* Just for demo */
div {
margin-bottom: 10px;
}
<div class='bordered square'></div>
<div class='bordered rectangle'></div>
Advantages:
Needs no extra elements (pseudo or real) which means less cluttered markup, pseudo elements can be used for other needs.
Is reasonably responsive as the width of the color in gradient is fixed. If the width of the borders dashes need to change according to the container's dimensions then we can change the pixels value in gradient to percentage (with a few more minor changes) like in below snippet.
.bordered.square {
height: 150px;
width: 150px;
}
.bordered.large-square {
height: 250px;
width: 250px;
}
.bordered {
background-color: beige;
background-image: linear-gradient(to right, black 10%, transparent 10%), linear-gradient(to right, black 10%, transparent 10%), linear-gradient(to bottom, black 10%, transparent 10%), linear-gradient(to bottom, black 10%, transparent 10%);
background-size: 90% 5px, 90% 5px, 5px 90%, 5px 90%;
background-position: 0% 0%, 0% 100%, 0% 0%, 100% 0%;
background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
}
/* Just for demo */
div {
margin-bottom: 10px;
}
<div class='bordered square'></div>
<div class='bordered large-square'></div>
Drawbacks:
Relatively better browser support. If IE9- support is needed then this is a no-go.
If percentage based gradient is used then the same drawback with rectangles as mentioned for border-image would be applicable here also.
clip-path
Using two div's on top of each other.
And adding a clip-path to div that is in the back you can create a border like effect.
.wrapper {
display: inline-block;
background-color: black;
line-height: 0px;
-webkit-clip-path: polygon(0% 100%, 30% 100%, 30% 70%, 70% 70%, 70% 100%, 100% 100%, 100% 70%, 70% 70%, 70% 30%, 100% 30%, 100% 0%, 70% 0%, 70% 30%, 30% 30%, 30% 0%, 0% 0%, 0% 30%, 30% 30%, 30% 70%, 0% 70%);
clip-path: polygon(0% 100%,
30% 100%,
30% 70%,
70% 70%,
70% 100%,
100% 100%,
100% 70%,
70% 70%,
70% 30%,
100% 30%,
100% 0%,
70% 0%,
70% 30%,
30% 30%,
30% 0%,
0% 0%,
0% 30%,
30% 30%,
30% 70%,
0% 70%);
}
.wrapper {} .wrapper div {
display: inline-block;
height: 150px;
width: 150px;
margin: 10px;
background-color: white;
}
<div class="wrapper">
<div></div>
</div>
two pseudo elements
Using two large pseudo elements you can create the border effect.
.cut-border {
position: relative;
display: inline-block;
border: 5px solid black;
width: 150px;
height: 150px;
}
.cut-border::before {
content: "";
position: absolute;
height: calc(100% + 10px);
width: 50%;
background-color: white;
top: -5px;
left: 25%;
}
.cut-border::after {
content: "";
position: absolute;
height: 50%;
width: calc(100% + 10px);
background-color: white;
top: 25%;
left: -5px;
}
<div class="cut-border"></div>
An option that no one has mentioned so far is using multiple box-shadow to simulate that type of border. You would need one box-shadow for each corner:
div {
width: 150px;
height: 150px;
padding: 10px;
box-shadow:
-80px -80px 0 -70px black,
80px -80px 0 -70px black,
-80px 80px 0 -70px black,
80px 80px 0 -70px black;
}
<div>I am a box with borders only in the corners.</div>
It works by having four shadows (top-left, top-right, bottom-right, bottom-left) and reducing their size with a negative spread-radius (blur-radius will remain as zero):
box-shadow: offset-x offset-y [blur-radius] [spread-radius] [color];
While this is will work (even on IE!) and it is a simple method (no need for additional elements or pseudo-elements), it has two big shortfalls:
You need to know the size of the box to adjust the values of the box-shadow accordingly (or at least have a general idea to adjust the values of the shadows, because they don't accept percentages).
The corners will not be exactly squared. Instead, they will be proportional to the box size. This could be avoided by using 8 shadows instead of 4, but things get messy then.
In the end, using background gradients may be a better option and provides "more control" because it is all within the box. It could be achieved just with 4 linear-gradients (some answers indicate 8):
div {
--size: 32px;
width: 100px;
height: 100px;
padding: 10px;
background:
linear-gradient(blue var(--size), transparent 0 calc(100% - var(--size)), blue 0) 0 0 / 4px 100%,
linear-gradient(blue var(--size), transparent 0 calc(100% - var(--size)), blue 0) 100% 0 / 4px 100%,
linear-gradient(to right, blue var(--size), transparent 0 calc(100% - var(--size)), blue 0) 0 0 / 100% 4px,
linear-gradient(to right, blue var(--size), transparent 0 calc(100% - var(--size)), blue 0) 0 100% / 100% 4px
;
background-repeat: no-repeat;
}
<div>I am a box with borders only in the corners.</div>
I found this question, but I was not satisfied with the border-radius approach: As I was using more thick borders, the effect was not as good as I wanted to. I managed to create another solution, without images, and without any extra markup:
.box {
/* fake border */
position: relative;
overflow: hidden;
box-shadow: inset 0px 0px 0px 10px green;
padding: 1em;
}
.box:before {
/* this element will hide the fake border on the top and bottom */
content:'';
display: block;
position: absolute;
border-top:10px solid white;
border-bottom:10px solid white;
/* height = border-width x2 */
height:calc(100% - 20px);
top:0;
/* width = size of fake-border x2 */
width: calc(100% - 36px);
/* left = size of fake-border */
left:18px;
}
.box:after {
/* this element will hide the fake border on the left and right */
/* the rules for width, heigth, top and left will be the opposite of the former element */
display: block;
position: absolute;
content:'';
border-right:10px solid white;
border-left:10px solid white;
height:calc(100% - 36px);
width: calc(100% - 20px);
top:18px;
left: 0;
}
Here's a JSFiddle with this example: https://jsfiddle.net/t6dbmq3e/
Hope it helps.
Here is something that i did recently with content centred both vertically and horizontally.
The HTML
<div class="column">
<div class="c-frame-wrapper">
<div class="c-frame-tl"></div>
<div class="c-frame-tr"></div>
<div class="c-frame-br"></div>
<div class="c-frame-bl"></div>
<div class="c-frame-content">
© Copyright 2015 - Company name<br /><br />
St Winifrids St,<br />
The Saints, Harrogate HG1 5PZ, UK<br />
</div>
</div>
</div>
The CSS
.c-frame-wrapper {
width: 250px;
height: 100px;
font-size:11px;
color: $dark-grey-lighten-70;
/* center align x axis */
right: auto;
left: 50%;
transform: translateX(-50%);
}
.c-frame-tl {
top: 0;
left: 0;
position: absolute;
width:10px;
height:10px;
border-width: 3px;
border-style: solid none none solid;
border-color: #eb0000;
}
.c-frame-tr {
top: 0;
right: 0;
position: absolute;
width:10px;
height:10px;
border-width: 3px;
border-style: solid solid none none;
border-color: #eb0000;
}
.c-frame-br {
bottom: 0;
right: 0;
position: absolute;
width:10px;
height:10px;
border-width: 3px;
border-style: none solid solid none;
border-color: #eb0000;
}
.c-frame-bl {
bottom: 0;
left: 0;
position: absolute;
width:10px;
height:10px;
border-width: 3px;
border-style: none none solid solid;
border-color: #eb0000;
}
.c-frame-content {
width:100%;
text-align: center;
/*center alignment x and y*/
position: absolute;
top: 50%;
left: 50%;
bottom: auto;
right: auto;
transform: translate(-50%,-50%);
}
JSFiddle
i think the best solution is the pseudo element method. Nice and clean and doesn't pollute the html with (too many) extra elements.
I created this sass mixin using the code above, for a copy&paste solution:
#mixin corner-borders($corner-width: 1px, $corner-size: 5px, $color-border: grey, $color-background: white) {
position: relative;
border: $corner-width solid $color-border;
background-color: $color-background;
&::before {
content: "";
z-index: 0;
position: absolute;
top: -$corner-width;
bottom: -$corner-width;
left: $corner-size;
right: $corner-size;
background-color: $color-background;
}
&::after {
content: "";
z-index: 0;
position: absolute;
top: $corner-size;
bottom: $corner-size;
left: -$corner-width;
right: -$corner-width;
background-color: $color-background;
}
}
Then you can use it like this:
html:
<div class="border">
<div class="content">
Content
</div>
</div>
SCSS
.border {
#include corner-borders;
}
.content {
position: relative;
z-index: 1;
}
You need the z-index & relative position in there so the content sits on top of the pseudo elements.
I made a codepen demo here: http://codepen.io/timrross/pen/XMwVbV
I took Majid Laissi's answer and modified to be more understandable, simple and easy to modify.
img{
width:70px;
height:70px;
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}
.custom-corners {
position: relative;
width: 150px;
height: 150px;
background-color: white;
border: 1px solid black;
}
.custom-corners:before {
content: '';
position: absolute;
top: -1px;
left: -1px;
border: 1px solid #fff;
height: 100%;
width: 100%;
border-radius: 10%;
}
.custom-corners:after {
content: '';
position: absolute;
bottom: -1px;
right: -1px;
border: 1px solid #fff;
height: 100%;
width: 100%;
border-radius: 10%;
}
<div class="custom-corners">
<img src="https://cdn.logo.com/hotlink-ok/logo-social-sq.png" alt="">
</div>
Ok as i suck in CSS i think i'll not be able to do it myself but i do that and it seems work :
<div id="half" style="position:absolute; top:0; left:0; width:30px; height:30px; overflow:visible; border-top:3px solid #F00; border-left:3px solid #06F;"></div>
<div id="half" style="position:absolute; bottom:0; right:0; width:30px; height:30px; overflow:visible; border-bottom:3px solid #F00; border-right:3px solid #06F;"></div>
And it seems to be working ;-) Sorry for disturb and thanks for your help.
There is no clean css way to just give the corners a border, but you could try to mimic the effect. Something like this perhaps: http://jsfiddle.net/RLG4z/
<div id="corners">
<div id="content">
content
</div>
</div>
#corners {
width: 200px;
height: 50px;
border-radius: 10px;
background-color: red;
margin: 10px;
}
#content {
background-color: white;
border-radius: 15px;
height: 30px;
padding: 10px;
}
due to the difference in border radius, the background color of the underlying div shows trough, giving the effect of a border on the corners.
Personally I think i would work with background images to achieve this, for better controle of the result.
This is your picture:
HTML:
<div class="shell">
<div class="top">
<div class="clear">
<div class="left">
****
</div>
<div class="right">
****
</div>
</div>
<div class="clear">
<div class="left">
*
</div>
<div class="right">
*
</div>
</div>
<div class="clear">
<div class="left">
*
</div>
<div class="right">
*
</div>
</div>
</div>
<div class="content">
<p>CONTENT</p>
</div>
<div class="bottom">
<div class="clear">
<div class="left">
*
</div>
<div class="right">
*
</div>
</div>
<div class="clear">
<div class="left">
*
</div>
<div class="right">
*
</div>
</div>
<div class="clear">
<div class="left">
****
</div>
<div class="right">
****
</div>
</div>
</div>
and CSS:
.shell { width: 200px;}
.left{ float:left; }
.right{float:right; }
.clear { clear: both; line-height: 10px; }
.content { line-height: 10px; text-align: center; }
Here is a modified version of the above answer, this version has relative positioned parent and absolute positioned child so we can add the on hover effect.
http://jsfiddle.net/3jo5btxd/
HTML:
<div id="div1"><div id="div2"><img src="http://placekitten.com/g/82/82"></div></div>
CSS:
#div1 {
position: relative;
height: 100px;
width: 100px;
background-color: white;
border: 1px solid transparent;
}
#div2 {
position: absolute;
top: -2px;
left: -2px;
height: 84px;
width: 84px;
background-color: #FFF;
border-radius: 15px;
padding: 10px;
}
#div1:hover {
border: 1px solid red;
}
I liked #Tims approach, but it forced me to set a background color to the box, which I did not want, since I it to put the focus on a background image object.
In my case I only needed 2 edges also, which makes it possible to structure it a little different.
I therefore structured it a little different, that makes it more flexible and still works in every browser.
The solution does not work if you need 4 corners, but just wanted to leave it here for future searchers.
:root {
--border-width: 5px;
--corner-size: 20px;
--border-color: red;
}
.box-corners {
position:relative;
}
.box-corners::before,
.box-corners::after {
content: "";
position: absolute;
width:var(--corner-size);
height:var(--corner-size);
border:var(--border-width) solid var(--border-color);
}
.box-corners::before {
left: 0;
top: 0;
border-bottom:none;
border-right:none;
}
.box-corners::after {
bottom: 0;
right: 0;
border-left:none;
border-top:none;
}
/* ############## THIS IS JUST OPTIONAL FOR THE HOVER EFFECT ############# */
.box-corners {
transition:background-color 0.3s ease-in-out;
}
.box-corners:hover {
background:rgba(0, 0, 0, 0.5)!important;
}
.box-corners::before,
.box-corners::after {
box-sizing:border-box;
transition:width 0.3s ease-in-out, height 0.3s ease-in-out;
}
.box-corners:hover::before,
.box-corners:hover::after {
width:100%;
height:100%;
}
<div class="box-corners" style="width:300px;height:300px;background:#f7f7f7;" />
Hover effect
You only need the first part of the css code to make the edges work.
The second part just allows to easily add a nice hover effect, that you could also just remove, if you don't need it.
Without CSS Variables and Sass
If you don't want to use css variables, you can just replace the variables with hardcoded values.
If you want to make a sass mixin out of it, just wrap it in a #mixin call and replace the vars with sass variables.
.border_coners {
background:
linear-gradient(to right, #e5e5e5 1px, transparent 1px) 0 0,
linear-gradient(to right, #e5e5e5 1px, transparent 1px) 0 100%,
linear-gradient(to left, #e5e5e5 1px, transparent 1px) 100% 0,
linear-gradient(to left, #e5e5e5 1px, transparent 1px) 100% 100%,
linear-gradient(to bottom, #e5e5e5 1px, transparent 1px) 0 0,
linear-gradient(to bottom, #e5e5e5 1px, transparent 1px) 100% 0,
linear-gradient(to top, #e5e5e5 1px, transparent 1px) 0 100%,
linear-gradient(to top, #e5e5e5 1px, transparent 1px) 100% 100%;
background-repeat: no-repeat;
background-size: 50px 50px;
}
I adapted the border radius approach, but I didn't want to use absolute positioning or have to know the size of the content.
Fortunately setting a negative margin in all directions provides everything we need:
.corner-borders {
border: 1px solid #ccc;
}
.corner-borders-reveal {
border-radius: 20%; /* or any other size */
border: 1px solid white;
margin: -1px;
padding: 4px;
}

Resources