I'm trying to create a partial shadow on a skewed div, as close as I can get to this creative.
Right now I've been trying to do this with pseudo elements (before specifically) but I found that those elements behave strangely whenever I skew the element they are applied to. The pseudo element keeps appearing on top of my div, even though the z-index is set to -1. No matter what I do with z-index, it will stay on top of it. I want it to be behind the div it's applied to, and in front of the div below, like in the creative.
Here's my ::before code and a link to the codepen
CSS
/*! Shadows */
#test-title {
position: relative;
}
#test-title:before {
z-index: -1;
position: absolute;
content: "";
bottom: 15px;
left: 10px;
width: 50%;
top: 80%;
max-width:300px;
box-shadow: 0 15px 10px #777;
-webkit-transform: rotate(-3deg);
-moz-transform: rotate(-3deg);
-o-transform: rotate(-3deg);
-ms-transform: rotate(-3deg);
transform: rotate(-3deg);
}
http://codepen.io/kathryncrawford/pen/WwWEma
Skew the parent then unskew the child at the same degree.
* {
box-sizing: border-box
}
body {
padding: 40px 0
}
section {
width: 60vw;
clear: both;
overflow: hidden;
min-height: 100px;
margin: 0 auto;
position: relative;
background: #035076
}
section article {
width: 60%;
padding: 20px;
color: white;
margin: 0 auto
}
section:nth-child(even) {
transform: skew(-45deg) translate(5vw);
box-shadow: inset 0 0 2px 0 black;
}
section:nth-child(odd) {
transform: skew(45deg);
}
section:nth-child(even) article {
transform: skew(45deg) translate(5vw);
}
section:nth-child(odd) article {
transform: skew(-45deg);
}
section:before,
section:after {
content: '';
position: absolute;
}
section:nth-child(even):before {
width: 100%;
height: 0;
bottom: 100%;
left: 0;
z-index: 6;
opacity: 1;
transform: rotate(-10deg) translateY(-30px);
box-shadow: 0px 0px 64px 30px rgba(0, 0, 0, 0.8);
}
section:nth-child(odd):not(:first-child):before {
width: 100%;
height: 0;
bottom: 100%;
right: 0;
z-index: 6;
opacity: 1;
transform: rotate(10deg) translateY(-30px);
box-shadow: 0px 0px 64px 30px rgba(0, 0, 0, 0.8);
}
<section>
<article>What our clients say About Us</article>
</section>
<section>
<article>Read More!</article>
</section>
<section>
<article>Read More!</article>
</section>
<section>
<article>Read More!</article>
</section>
The easier approach would be to put the drop shadow at the top of each box after the first. This will solve all sorts of z-index issues, since each box sits 1 level higher than the box above it.. and it allows the shadow to sit inside the container instead of outside of it.
I've also changed your shadow styling to use a radial gradient* instead of a box shadow, as it is a bit easier to control in this situation, and is also closer to your design. I also did a bit of positioning to make it look a bit better too, and get the separate sides for skew1 and skew2
I've changed your last ruleset to this:
.test-info:before {
position: absolute;
content: "";
width: 100%;
left: 0;
top: 0;
height: 30px;
}
.test-info.skew1:before {
background: radial-gradient(ellipse farthest-side at 30% top, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0) 100%);
}
.test-info.skew2:before {
background: radial-gradient(ellipse farthest-side at 70% top, rgba(0,0,0,0.5) 0%, rgba(0,0,0,0) 100%);
}
See Demo
* note: You may want to check/add additional browser support on the gradient that I put in before using it.
I have tried, it's not perfect, but, it is closer to desired look, imho:
<div id="test-title">
<h3>What our clients say about us</h3>
</div>
<div id="shadow1"></div>
So, i've added new html element(shadow), rather than using pseudo-elements... Now, i've set z-indexes and positions properly, to hide rotated shadow div behind first div, and added this css:
#shadow1 {
position:absolute;
width:50%;
height:150px;
background:black;
top:50px;
left:11%;
z-index:6;
opacity:1;
transform: rotate(-5deg);
box-shadow: 15px 56px 50px -12px rgba(0,0,0,0.80);
}
Demo: http://codepen.io/anon/pen/vGwNqY
You can play with rotation, box-shadow, position, height... but, this could be a good start (maybe). P.S. Similar logic could be applied to second div.
try to make box shadow for the second element using :before pseudo https://jsfiddle.net/0andpzsp/
.cont {
width: 1000px;
height: 500px;
}
div[class^="d"] {
width: 70%;
height: 50%;
position: relative;
margin-left: 40px;
margin-top: 50px;
}
.d0 {
background: linear-gradient(to right, #005f8a 0%,#00486c 50%,#003a59 100%);;
transform: skew(20deg)
}
.d1 {
background: linear-gradient(to right, #005f8a 0%,#00486c 50%,#003a59 100%);;
overflow: hidden;
top: -50px;
left: 20%;
transform: skewX(-20deg);
z-index: -1
}
.d1:before {
content: '';
border-radius: 30%;
position: absolute;
display: block;
width: 600px;
height: 70px;
z-index: 9999;
top: -100px;
left: -70px;
box-shadow: -50px 60px 90px 0px #000;
transform: rotate(-5deg)
}
<div class="cont">
<div class="d0"></div>
<div class="d1">
</div>
</div>
Related
I have a simple div element that I wanna apply a background shape to it when the user hovers over it by using the ::before and ::after pseudo elements. I rotated these elements with rotateX(). How can I style it that the elements shouldn't overlap each other (or at least not ruin the background color) but it should look like a single shape?
Tried using % but didn't work.
Please help.
Thanks so much 🙏
div{
width:200px;
padding: 18px;
margin: 10px auto;
/* border: 1px solid black; */
text-align:center;
position: relative;
perspective: 100px;
z-index: 1;
}
div:hover{
color:#fff;
}
div:hover::before, div:hover::after{
content: "";
display: block;
background-color: #00000050;
width: 100%;
height: 50px;
position: absolute;
left: 0%;
z-index: -1;
}
div::before{
top:0;
transform: rotateX(-75deg);
}
div::after{
bottom:0;
transform: rotateX(75deg);
}
<div>Hello World</div>
If you make half of each pseudo element only have the color then when you rotate them the colors don't overlap.
A minor adjustment to the padding of the div was needed to get the two rotated 'halves' to meet correctly so this would have to be looked at if you ever went for a responsive rather than a fixed px unit solution.
This snippet removes the background-color from the pseudo elements, instead using a linear-gradient background-image going just half way up (or down) the pseudo element.
div {
width: 200px;
padding: 18px;
padding: 16px;
margin: 10px auto;
/* border: 1px solid black; */
text-align: center;
position: relative;
perspective: 100px;
z-index: 1;
}
div:hover {
color: #fff;
}
div:hover::before,
div:hover::after {
content: "";
display: block;
margin: 0;
padding: 0;
width: 100%;
height: 50px;
position: absolute;
left: 0%;
z-index: -1;
}
div::before {
top: 0;
transform: rotateX(-75deg);
background-image: linear-gradient(#00000050 0 50%, transparent 50% 100%);
}
div:hover::after {
bottom: 0;
transform: rotateX(75deg);
background-color: transparent;
background-image: linear-gradient(to top, #00000050 0 50%, transparent 50% 100%);
}
<div>Hello World</div>
A Haworth's answer covers using linear gradient stops to hide the color of half of each pseudo element.
Another approach you could take is to use only one of the pseudo elements with a polygon clip path to make your shape.
.container { display: flex; }
.hoverable { position: relative; margin: auto; padding: 10px 100px; }
.hoverable:hover::before {
content: "";
position: absolute;
inset: 0;
/* top: 0; left: 0; right: 0; bottom: 0; */
background-color: rgba(0, 0, 0, 0.25);
clip-path: polygon(0 0, 100% 0, 80% 50%, 100% 100%, 0 100%, 20% 50%);
}
<div class="container">
<div class="hoverable">Hello, World!</div>
</div>
When you line up two elements with a backdrop-filter: blur() you (naturally) get an ugly line down the middle. None the less two such elements next to each other might be desirable when you need more complex shapes than a simple square. How can two elements line up without creating such an ugly line?
Warning: This only works in Chrome with experimental web platform features enabled, and possibly in Safari and Edge 17.
div {
position: relative;
width: 400px;
}
.cover {
background: rgba(0,0,0,.1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
position: absolute;
top: 0px;
bottom: 0px;
width: 50%;
z-index: 1;
}
#left {
left: 0px;
top: 10px;
}
#right {
right: 0px;
bottom: 10px;
}
<div>
<div id="left" class="cover"></div>
<div id="right" class="cover"></div>
<img src="https://www.google.com/google.jpg">
<div>
Since you are already limited to webkit, may be you can take advantage of clip-path. Use a single cover element, and give it the shape that you want.
div {
position: relative;
width: 800px;
}
.cover {
background: rgba(0, 0, 0, .1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
position: absolute;
top: 0px;
bottom: 0px;
width: 50%;
z-index: 1;
-webkit-clip-path: polygon(50% 10%, 50% 0%, 100% 0, 100% 90%, 50% 90%, 50% 100%, 0 100%, 0% 10%);
}
<div>
<div class="cover"></div>
<img src="https://www.google.com/google.jpg">
</div>
Instead of the clip-path solution provided by #Vals you can use multiple gradient like this:
.container {
position: relative;
display:inline-block;
padding:20px;
}
.container:before {
content:"";
background:
linear-gradient(rgba(0,0,0,.1),rgba(0,0,0,.1))0 20px/50% 100% no-repeat,
linear-gradient(rgba(0,0,0,.1),rgba(0,0,0,.1))100% -20px/50% 100% no-repeat;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
position: absolute;
top: 0px;
bottom: 0px;
left:0;
right:0;
z-index: 1;
}
<div class="container">
<img src="https://www.google.com/google.jpg">
<div>
My target is to implement a pure-CSS flag-shape container like this:
Requirements include:
background-color of parent container is unknown
works for different line-height and font-size settings
Option 1
Use clip-path, but check browser support for this property:
div {
clip-path: polygon(0% 0%, 100% 0%, 85% 50%, 100% 100%, 0% 100%);
background-color: #ff69b4;
/* styles for demo */
padding: 20px;
color: #fff;
}
<div>5 items</div>
Option 2
Use SVG:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<polygon points="0 0, 100 0, 85 50, 100 100, 0 100" fill="#ff69b4" />
</svg>
Option 3
Use absolutely positioned pseudoelements with gradients (to simulate triangles)
div {
background-color: #ff69b4;
margin-right: 50px;
position: relative;
/* styles for demo */
padding: 20px;
color: #fff;
}
/* pseudoelement to simulate triangles */
div:before,
div:after {
content: "";
position: absolute;
top: 0;
left: 100%;
width: 50px;
height: 50%;
background-image: linear-gradient(to left top, transparent 50%, #ff69b4 50%);
}
/* Flip triangle */
div:after {
top: 50%;
transform: scaleY(-1);
}
<div>5 items</div>
Another possible variant would be to use transformed pseudo elements.
Create 2 layers using ::before ad ::after pseudo elements.
Add background-color and place them with position: absolute having 50% height of the parent.
Apply CSS3 skew() transformations to get the flag shape.
Output Image:
Working Demo:
* {box-sizing: border-box;}
body {
background: linear-gradient(green, yellow) no-repeat;
min-height: 100vh;
padding: 10px;
margin: 0;
}
.flag {
padding: 5px 40px 5px 10px;
display: inline-block;
vertical-align: top;
position: relative;
line-height: 40px;
overflow: hidden;
}
.flag:before,
.flag:after {
transform-origin: top right;
transform: skewX(-45deg);
position: absolute;
background: pink;
content: '';
left: -45px;
height: 50%;
z-index: -1;
right: 0;
top: 0;
}
.flag:after {
transform-origin: bottom right;
transform: skewX(45deg);
top: auto;
bottom: 0;
}
<div class="flag">5 Items</div>
I want to create an html element, e.g. a div, which is styled as follows:
semi-transparent background-color
rounded borders on all edges
left side of the div draws a straight line
right side of the div draws a skewed line
I'd like to create this in CSS only and wonder if this is possible. So far I came up with two different approaches which have their own drawbacks and are not fully sufficient. You can have a look at those in this fiddle:
https://jsfiddle.net/n4tecna3/
.one-side-skew-1,
.one-side-skew-2 {
font-size: 20px;
padding: 2%;
background-color: rgba(220, 50, 255, 0.6);
position: relative;
display: block;
border-radius: 4px;
z-index: 2;
color: #ffffff;
margin-top: 30px;
}
.one-side-skew-2 {
border-top-right-radius: 0px;
}
.one-side-skew-1:after {
height: 100%;
width: 20%;
position: absolute;
top: 0;
left: 85%;
display: inline-block;
content: "";
background-color: rgba(220, 50, 255, 0.6);
-moz-transform: skewX(-10deg);
-webkit-transform: skewX(-10deg);
-ms-transform: skewX(-10deg);
-o-transform: skewX(-10deg);
transform: skewX(-10deg);
z-index: -1;
border-radius: 4px;
}
.one-side-skew-2:after {
border-top: 1em solid rgba(220, 50, 255, 0.6);
border-left: 0.25em solid rgba(220, 50, 255, 0.6);
border-right: 0.25em solid transparent;
border-bottom: 1em solid transparent;
border-top-right-radius: 4px;
left: 100%;
display: inline-block;
position: absolute;
content: "";
top: 0;
}
.container {
width: 500px;
}
<div class="container">
<div class="one-side-skew-1">
<span class="inner-text">One Side Skew With Pseudo Element Skewed</span>
</div>
<div class="one-side-skew-2">
<span class="inner-text">One Side Skew With Pseudo Element Border</span>
</div>
</div>
Approach 1 .one-side-skew-1 uses a div element with round borders and a skewed, round-bordered pseudo element to create a one-side skewed element in sum. This works great as long as the background-color is solid. For semi-transparent backgrounds you will see an ugly color overlap where the element and its pseudo-element meet.
Approach 2 .one-side-skew2 uses a div element with a pseudo behind it that consists of borders only. It's somewhat hacky but gets close to my desired result. Still, the right does not look nearly as smooth as in the first approach.
Does someone else have a good solution for this problem in CSS only? Or will I have to use a fallback solution with a semi-transparent background-image to solve this?
You can use a pseudo element for all the background and hide the overflowing parts with the overflow property on the element.
This will prevent element and pseudo element background overlapping and allow semi transparent backgrounds:
div {
position: relative;
width: 250px;
font-size: 20px;
border-radius: 4px;
overflow: hidden;
color: #fff;
padding: 1% 2%;
}
div:before {
content: '';
position: absolute;
top: 0; right: 0;
width: 100%; height: 100%;
background: rgba(220, 50, 255, 0.6);
-webkit-transform-origin:100% 0;
-ms-transform-origin:100% 0;
transform-origin: 100% 0;
-webkit-transform: skewX(-10deg);
-ms-transform: skewX(-10deg);
transform: skewX(-10deg);
border-radius: 4px 4px 6px;
z-index: -1;
}
/** FOR THE DEMO **/body {background: url('http://lorempixel.com/output/people-q-g-640-480-3.jpg');background-size: cover;}
<div>content</div>
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" />