background image, linear gradient jagged edged result needs to be smooth edged - css

I'm trying to make the bottom of an image pointed. I've tried to get this effect by producing two triangles at the bottom. They must be responsive. and after searching all over the internet with a lot of examples that don't work for my requirement this is the best so far I've managed to produce.
body,
html {
height: 100%
}
.image {
width: 1410px;
margin-right: auto;
margin-left: auto;
height: 500px;
overflow: hidden;
position: relative;
}
.pointer {
height: 50px;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}
.triangleWrapper {
width: 50%;
height: 50px;
float: left;
}
.lefttriangle {
width: 100%;
height: 10px;
left: 0px;
top: 0px;
background-image: linear-gradient(to right top, #ffffff 50%, transparent 50%);
}
.righttriangle {
width: 100%;
height: 10px;
right: 0px;
top: 0px;
background: linear-gradient(to left top, #ffffff 50%, transparent 50%)
}
<div class="image">
<img src="http://placekitten.com/1410/500">
<div class="pointer">
<div class="triangleWrapper">
<div style="height: 100%;" class="lefttriangle"></div>
</div>
<div class="triangleWrapper">
<div style="height: 100%;" class="righttriangle"></div>
</div>
</div>
</div>
CodePen Demo
It works exactly how I want it to as it is responsive without the need for media queries. BUT it has a jagged edge on the triangle line that isn't 90deg.
How do I get this to produce a smooth line in most if not all modern browsers? I'm not asking for backward compatibility.
Any help is greatly appreciated!

Unfortunately, this always happens when we use angled linear-gradient images and currently the only way to overcome this behavior seems to be to avoid hard-stopping of the colors (that is, don't make the stop point of one color as the start point of the next). Making the second color start a little farther away from the stop point of the first color would kind of create a blurred area and make it look more smoother. This is still not 100% perfect but is better than having jagged edges.
.lefttriangle {
width: 100%;
height: 10px;
left: 0px;
top: 0px;
background-image: linear-gradient(to right top, #ffffff 48%, transparent 50%); /* note the change of stop and start points */
}
.righttriangle {
width: 100%;
height: 10px;
right: 0px;
top: 0px;
background: linear-gradient(to left top, #ffffff 48%, transparent 50%); /* note the change of stop and start points */
}
body,
html {
height: 100%
}
.image {
width: 1410px;
margin-right: auto;
margin-left: auto;
height: 500px;
overflow: hidden;
position: relative;
}
.pointer {
height: 50px;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}
.triangleWrapper {
width: 50%;
height: 50px;
float: left;
}
.lefttriangle {
width: 100%;
height: 10px;
left: 0px;
top: 0px;
background-image: linear-gradient(to right top, #ffffff 48%, transparent 50%);
}
.righttriangle {
width: 100%;
height: 10px;
right: 0px;
top: 0px;
background: linear-gradient(to left top, #ffffff 48%, transparent 50%);
}
<div class="image">
<img src="http://placekitten.com/1410/500">
<div class="pointer">
<div class="triangleWrapper">
<div style="height: 100%;" class="lefttriangle"></div>
</div>
<div class="triangleWrapper">
<div style="height: 100%;" class="righttriangle"></div>
</div>
</div>
</div>
Alternate Implementations:
Clip Paths: You can use clip-path feature also to produce a similar effect. The advantage of using clip-path is that it is both responsive and also produces a transparent cut. The SVG based clip-path has better browser support than the CSS version. This is not yet supported in IE though.
body,
html {
height: 100%
}
.image {
width: 1410px;
margin-right: auto;
margin-left: auto;
height: 500px;
overflow: hidden;
position: relative;
}
.css-clip {
-webkit-clip-path: polygon(0% 0%, 0% 90%, 50% 100%, 100% 90%, 100% 0%);
clip-path: polygon(0% 0%, 0% 90%, 50% 100%, 100% 90%, 100% 0%);
}
.svg-clip {
-webkit-clip-path: url(#clipper);
-moz-clip-path: url(#clipper);
clip-path: url(#clipper);
}
<!-- CSS Clip-path - Lower browser support -->
<div class="image css-clip">
<img src="http://placekitten.com/1410/500">
</div>
<!-- SVG Clip-path - Better browser support -->
<svg width="0" height="0">
<defs>
<clipPath clipPathUnits="objectBoundingBox" id="clipper">
<path d="M0,0 0,0.9 0.5,1 1,0.9 1,0z" />
</clipPath>
</defs>
</svg>
<div class="image svg-clip">
<img src="http://placekitten.com/1410/500">
</div>
Using CSS Transform: You could also try using the approach mentioned in this answer. It achieves a pointed effect on the left side but it should be easy to adapt it to create a pointed effect on the bottom side.
body,
html {
height: 100%
}
.image {
width: 1410px;
margin-right: auto;
margin-left: auto;
height: 500px;
overflow: hidden;
position: relative;
}
.top-container,
.bottom-container {
position: absolute;
bottom: 0px;
height: 100%;
width: 50%;
overflow: hidden;
backface-visibility: hidden;
}
.top-container {
left: 0px;
transform-origin: right bottom;
transform: skewY(10deg);
}
.bottom-container {
right: 0px;
transform-origin: left bottom;
transform: skewY(-10deg);
background-position: 0% 100%;
}
.top-container:after,
.bottom-container:after {
position: absolute;
content: '';
height: 100%;
width: 100%;
bottom: -62px; /* tan(10) * (width/2) / 2 */
background: url(http://placekitten.com/1410/500);
background-size: 200% 100%;
}
.top-container:after {
left: 0px;
transform: skewY(-10deg);
}
.bottom-container:after {
right: 0px;
transform: skewY(10deg);
background-position: 100% 0%;
}
<div class="image">
<div class='top-container'></div>
<div class='bottom-container'></div>
</div>

Just found an insanely good solution on codepen using calc(50% - 1px)
https://codepen.io/hellonico/pen/xEYXmL
background: linear-gradient(7deg, currentColor calc(50% - 1px), transparent 50%);
No blur whatsoever, just a smooth edge
EDIT: .. apparently not in Safari?..

Related

css top tilted skew with background-image

enter image description here
I want to make a similar effect to this one not changing html code , using only CSS , In HTML i have got only one div with class "square" , Thank you for your support in advance .
i think that is what you want
.container {
font-size: 16px;
background: #fff;
margin: 0 auto;
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-perspective: 28em;
-moz-perspective: 28em;
perspective: 28em;
position: relative;
top: 100px;
}
.box {
position: absolute;
width: 14em;
height: 14em;
left: 50%;
margin-left: -7em;
backface-visibility: hidden;
}
.anim {
transition: all 0.5s ease-in-out;
}
.b0 {
transform: translateX(-11.7em) rotateY(30deg) ;
}
.box img {
width: 100%;
height: 100%;
border-radius: 5px;
}
#media(max-width: 768px) {
.container {
font-size: 12px;
}
}
#media(max-width: 560px) {
.container {
font-size: 8px;
}
}
<div class="container">
<div class="box anim b0">
<img src="http://www.skitzone.com/wp-content/uploads/2010/06/I_am_nothing__in_the_dark_by_islandtime-630x630-500x500.jpg" alt="" />
</div>
</div>
The requirement is to cut the top in a sloping manner.
This snippet does this by putting the linear-gradient that is required for the border into a before pseudo element, using clip-path to get the required cutting off of the top, and putting the image as background on an after pseudo element.
.square {
width: 20vmin;
height: 20vmin;
clip-path: polygon(0 0, 100% 20%, 100% 100%, 0 100%);
position: relative;
}
.square::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(red, blue);
background-image: linear-gradient(to right, #a2ca3c 0%, #0a7cff 50%, #a2ca3c 100%);
z-index: -1;
}
.square::after {
content: '';
position: absolute;
--borderW: 3%;
top: var(--borderW);
left: var(--borderW);
width: calc(100% - (2 * var(--borderW)));
height: calc(100% - (2 * var(--borderW)));
background-image: url(https://pesi.pl/img/main-bg.jpg);
background-size: cover;
background-position: center center;
background-repeat: no-repeat no-repeat;
clip-path: polygon(var(--borderW) var(--borderW), calc(100% - var(--borderW)) calc(20% + var(--borderW)), calc(100% - var(--borderW)) calc(100% - var(--borderW)), var(--borderW) calc(100% - var(--borderW)));
z-index: -1;
}
<div class="square"></div>
Obviously you will want to decide on exactly what width you want the border to be and whether the border is included in the overall size of the .square element (as here).

How to achieve "depth" with a 3d css transform

I am trying to create a "perspective mockup" using CSS. There are a fair amount of tutorials on how to achieve this with 3D layers in Photoshop, but I would like to do it with CSS. Here is an example of what I am trying to achieve:
And here is the code (using the raw image, https://i.imgur.com/foDEYpB.png):
#perspective {
width: 400px;
height: 500px;
position: absolute;
background-image: url("https://i.imgur.com/foDEYpB.png");
background-repeat: no-repeat;
background-size: cover;
top: 50%;
left: 50%;
margin-left: -200px;
margin-top: -250px;
transform: rotate3d(360, 120, -90, 60deg) rotateZ(-30deg);
box-shadow: -15px 15px 20px rgba(0, 0, 0, 0.5);
}
<div id='perspective'></div>
I am pretty close, but am unsure how to achieve the "depth" or "height" where the image looks raised. Zoomed in version of said "depth" where the image is repeated onto the sides:
P.S. if anyone knows the correct name for what I'm referring to as "depth", I'd love to know!
Try adding three type of images to make 3D effects. Use transform property with rotation for images to get the desired result.
Answer reference here.
.perspective {
position: relative;
width: 400px;
height: 500px;
transform-style: preserve-3d;
transition: all 500ms ease-in;
transform: rotateY(20deg) rotateX(60deg) rotateZ(-10deg);
transform: rotateY(15deg) rotateX(50deg) rotateZ(-15deg);
box-shadow: -40px 80px 80px -10px rgba(0, 0, 0, 0.7);
cursor: pointer;
margin-right: 30px;
display: inline-block;
margin-left: 30%;
}
.perspective img {
position: absolute;
top: 0px;
left: 0px;
width: 400px;
height: 500px;
transform: translateZ(16px);
}
.bottom,
.left {
position: absolute;
width: 400px;
height: 500px;
display: block;
transition: all 1s linear;
overflow: hidden;
border-radius: 3px;
transform: translateZ(16px);
filter: brightness(80%)
}
.left {
transform: rotateY(270deg) translateX(-1px);
transform-origin: center left;
width: 18px;
}
.bottom {
transform: rotateX(90deg) translateY(15px) translateZ(-480px);
transform-origin: bottom center;
height: 18px;
}
.bottom img {
transform: rotateX(180deg);
width: 100%;
height: 500px;
left: 0px;
}
<div class="perspective">
<img src="https://i.imgur.com/foDEYpB.png">
<div class="bottom"><img src="https://i.imgur.com/foDEYpB.png"></div>
<div class="left"><img src="https://i.imgur.com/foDEYpB.png"></div>
</div>
Here is a hacky idea using multiple background to simulate such effect. The trick is to add 2 semi-transparent gradients to create the shadow effect then 2 other gradient to cut a small part of the corner to obtain the 3D shape.
The result may not be perfect for all the images:
.wrapper {
display:inline-block;
perspective:1000px;
}
.box {
margin: 50px;
width:200px;
height:200px;
transform: rotate3d(360, 120, -90, 60deg) rotateZ(-30deg);
background:
linear-gradient(to bottom right,transparent 49%,#fff 52%) bottom right/14px 10px,
linear-gradient(to top left,transparent 49%,#fff 52%) top left /10px 14px,
linear-gradient(rgba(0,0,0,0.5),rgba(0,0,0,0.5)) 0 0px/10px 100%,
linear-gradient(rgba(0,0,0,0.5),rgba(0,0,0,0.5)) 100% 100%/calc(100% - 10px) 10px,
url(https://picsum.photos/id/1061/1000/800) center/cover;
background-repeat:no-repeat;
}
<div class="wrapper" >
<div class="box" >
</div>
</div>
With your image you can have a specific gradient like below:
body {
background:#ccc;
}
.wrapper {
display:inline-block;
perspective:1000px;
}
.box {
margin: 50px;
width:200px;
height:250px;
transform: rotate3d(360, 120, -90, 60deg) rotateZ(-30deg);
background:
linear-gradient(to bottom right,transparent 49%,#ccc 52%) bottom right/16px 10px,
linear-gradient(to top left,transparent 49%,#ccc 52%) top left /10px 12px,
linear-gradient(#efefef,#efefef) 100% 100%/calc(100% - 10px) 10px,
linear-gradient(-226deg,#222428 13px,#ff4946 13px,#ff4946 77px,#592D30 77px,#592D30 100px,#222428 100px,#222428 108px,#efefef 108px,#efefef 161px) 0 0px/10px 100%,
url(https://i.imgur.com/foDEYpB.png) center/cover;
background-repeat:no-repeat;
}
<div class="wrapper">
<div class="box">
</div>
</div>

How to cut box corner Using CSS with transparent background?

I want to cut left top corner of a box using CSS like this.
keep in mind that background is transparent.
Nearly the same solution as OriDrori's answer but more flexible (if you need fixed-width cutted corner).
This gradient will look the same regardless of .card width and height.
body {
background: purple;
}
.card {
width: 200px;
height: 200px;
background: linear-gradient(135deg, transparent 20px, white 20px);
}
<div class="card"></div>
You can use a simple linear gradient for that:
body {
background: purple;
}
.card {
width: 200px;
height: 200px;
background: linear-gradient(to bottom right, transparent 5%, white 5%);
}
<div class="card"></div>
You can use clip-path
https://developer.mozilla.org/en/docs/Web/CSS/clip-path
and use something like this:
div#test{
background:red;
width:200px;
height: 200px;
-webkit-clip-path: polygon(22% 0, 100% 0, 100% 100%, 0 100%, 0 20%);
clip-path: polygon(22% 0, 100% 0, 100% 100%, 0 100%, 0 20%);
}
<div id="test"></div>
With a pseudo and transform you can do that, and it has good browser support (from IE9)
body {
background: url(https://picsum.photos/400/300) center / cover;
}
div {
position: relative;
width: 200px;
height: 200px;
overflow: hidden;
}
div::before {
content: '';
position: absolute;
left: calc(50% + 25px); /* 25px is height/width of the cut */
top: calc(50% + 25px);
width: 141.5%;
height: 141.5%;
transform: translate(-50%,-50%) rotate(45deg);
background: #eee;
opacity: 0.8;
}
<div></div>
As pointed out, if you need it to scale on different aspect ratio's, use this
body {
background: url(https://picsum.photos/400/300) center / cover;
}
div {
position: relative;
width: 80vw;
height: 80vh;
overflow: hidden;
}
div::before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 1000%;
height: 5000%;
transform: rotate(45deg) translate(25px,-50%); /* 25px for the cut height/width */
transform-origin: left top;
background: #eee;
opacity: 0.8;
}
<div></div>

Clipping Mask to SVG

I'm trying to create a menu that when you hover over one of the links, it shows a sliced image in the background. I was able to create something that works only in Chrome using CSS3 clipping masks.
The code to produce these shapes scale with the browser widths (+1 for percentages!) and work excellent except for two things: one being that the mask does not clip the shape I need (refer to the colorful image to see the shape) and it is not viable to use with Firefox and IE.
#music_hover {
z-index: 5;
width: 100%;
height: 100%;
background: red;
-webkit-clip-path: polygon(50% 50%, 100% 50%, 100% 100%, 70% 100%);
clip-path: polygon(50% 50%, 100% 50%, 100% 100%, 70% 100%);
float: right;
position: absolute;
background: url(../music.jpg) bottom right no-repeat;
display: none;
}
Now, to find something supported by more browsers, I have switched to SVG images. I've done this in [CodePen]. My issue with my current solution is that the slices do not "stay together" when the browser is not 1920x1080. The 3 slices in the first row stick to the top while the second row sticks to the bottom creating a white strip in the middle of the page. The slices also do not scale as they have precise points to draw the shape (as opposed to percentages of the clipping mask).
HTML:
<svg version="1.1" id="novel_Position" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 773.685 540.94">
<defs>
<pattern id="novel_BG" patternUnits="userSpaceOnUse" width="100%" height="100%">
<image xlink:href="http://loiseau-noir.com/seb/novel.jpg" x="0" y="0" width="100%" height="100%" />
</pattern>
</defs>
<path d="M420,1.058H0v539.569l696.512,0.313c0.031-72.714,29.516-138.541,77.173-186.197L420,1.058z" fill="red"/>
</svg>
CSS:
#novel_Position {
z-index: 5;
width: 40.5%;
top: 0;
left: 0;
position: fixed;
}
Now if all that isn't clear, the page should function like this:
You can do it without clipping masks, just using transforms and overflow: hidden. and some html structure
html, body {height: 100%;}
.base {
height: 100%;
width: 100%;
border: 1px solid black;
position: relative;
overflow: hidden;
}
.part {
position: absolute;
width: 50%;
height: 50%;
overflow: hidden;
}
.part:after {
content: '';
position: absolute;
width: 100%;
height: 100%;
background-size: cover;
transform-origin: inherit;
}
.NW {
left: 0px;
top: 0px;
transform: skewX(30deg);
transform-origin: bottom right;
}
.NW:after {
transform: skewX(-30deg);
background-image: url("http://placekitten.com/g/200/300");
}
.N {
top: 0px;
right: 0px;
transform: rotate(-60deg) skewX(-30deg);
transform-origin: bottom left;
overflow: hidden;
}
.N:after {
transform: skewX(30deg) rotate(60deg) translateX(-50%) ;
background-image: url("http://placekitten.com/g/600/400");
}
.NE {
right: 0px;
top: 0px;
transform: skewX(-30deg);
transform-origin: bottom left;
}
.NE:after {
transform: skewX(30deg);
background-image: url("http://placekitten.com/g/200/300");
}
.SW {
left: 0px;
bottom: 0px;
transform: skewX(-30deg);
transform-origin: top right;
}
.SW:after {
transform: skewX(30deg);
background-image: url("http://placekitten.com/g/200/300");
}
.S {
bottom: 0px;
right: 0px;
transform: rotate(60deg) skewX(30deg);
transform-origin: top left;
}
.S:after {
transform: skewX(-30deg) rotate(-60deg) translateX(-50%) ;
background-image: url("http://placekitten.com/g/200/300");
}
.SE {
right: 0px;
bottom: 0px;
transform: skewX(30deg);
transform-origin: top left;
}
.SE:after {
transform: skewX(-30deg);
background-image: url("http://placekitten.com/g/200/300");
}
.center {
position: absolute;
width: 20%;
height: 0%;
left: 40%;
top: 50%;
z-index: 10;
}
.roundcenter {
width: 100%;
padding: 50% 0;
border-radius: 50%;
background-color: lightgreen;
margin-top: -50%;
}
<div class="base">
<div class="part NW"></div>
<div class="part N"></div>
<div class="part NE"></div>
<div class="part SW"></div>
<div class="part S"></div>
<div class="part SE"></div>
<div class="center">
<div class="roundcenter">
</div>
</div>
</div>

Centering image and also offsetting it

I'm trying to overlay this logo so it sits at the bottom of the page, and also so it is offset by its full width to the left (so that the right edge of the logo sits against the center line).
If I use position:absolute on #logo I have access to the top and left properties, which is good, but now centering won't work...
Here's the fiddle.
Also: making it a fixed distance from the left edge of the page won't work because the page is responsive. The right edge of the logo always has to sit perfectly on the center line.
In case the fiddle isn't working here's the code:
HTML:
<div id ="layer1">
<p>Hello</p>
</div>
<div id="layer2">
<div id="wrapper">
<img id="logo" src="http://i.stack.imgur.com/icxpG.png"/>
</div>
</div>
CSS:
body {
background: linear-gradient(to left, #1a1a1a 50%, #f15922 50%);
}
#layer1 {
position: absolute;
z-index: 100;
height: 100%;
width: 100%;
}
#layer2 {
position: absolute;
z-index: 5000;
height: 100%;
width: 100%;
}
#wrapper {
position: relative;
background-color: rgba(255, 255, 255, 0.3);
height: 100%;
}
#logo {
background-color: rgba(255, 0, 0, 0.3);
bottom: 0;
display: block;
margin-left: auto;
margin-right: auto
}
You could add position: absolute; and transform to center your #logo like this:
JSFiddle - DEMO
#logo {
background-color: rgba(255, 0, 0, 0.3);
display:block;
position: absolute;
bottom: 0;
left: 50%;
-webkit-transform: translateX(-100%);
-moz-transform: translateX(-100%);
-ms-transform: translateX(-100%);
-o-transform: translateX(-100%);
transform: translateX(-100%);
}
To get the image positioned offset perfectly at all widths, we need to get rid of the gradient and apply the second background to a pseudo element of the body.
In these 2 examples, body provides the orange background and body:before provides the dark background.
Example 1 - logo is a background image
calc(50% - 167px) offsets the logo.
html, body {
height: 100%;
width: 100%;
margin: 0;
}
body {
background: #f15922 url(http://i.stack.imgur.com/icxpG.png) calc(50% - 167px) bottom no-repeat;
}
body:before {
width: 50%;
height: 100%;
background: #1a1a1a;
content: '';
display: block;
position: absolute;
right: 0;
}
Example 2 - logo is <img>
right: 50% and bottom: 0 keep it at the bottom and offset by the natural width of the image.
html, body {
height: 100%;
width: 100%;
margin: 0;
}
body {
background: #f15922;
}
body:before {
width: 50%;
height: 100%;
background: #1a1a1a;
content: '';
display: block;
position: absolute;
right: 0;
}
#logo {
position: absolute;
bottom: 0;
right: 50%;
}
<img id="logo" src="http://i.stack.imgur.com/icxpG.png" />
Old Archived Examples (with gradient)
Limitation: There is a gap at certain viewport widths that is caused by the gradients 50% calculation. I'm not certain that this can be avoided.
Archived 1 - Keep it all in a background image / gradient
calc(50% - 167px) offsets the image from the center
html, body {
height: 100%;
width: 100%;
margin: 0;
}
body {
background: url(http://i.stack.imgur.com/icxpG.png) calc(50% - 167px) bottom no-repeat, linear-gradient(to left, #1a1a1a 50%, #f15922 50%);
}
Archived 2 - Using <img>
right: 50% and bottom: 0 keep it at the bottom and offset by the natural width of the image.
body {
background: linear-gradient(to left, #1a1a1a 50%, #f15922 50%);
}
#logo {
background-color: rgba(255, 0, 0, 0.3);
bottom: 0;
right: 50%;
position: absolute;
}
<img id="logo" src="http://i.stack.imgur.com/icxpG.png" />

Resources