How to make a picture shadow with CSS3 - css

I want to implement a picture shadow as below
I tried to use the following code, but that can't work as I want
Code snippet:
.oval {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
width: 30px;
height: 5px;
border: none;
-webkit-border-radius: 50%;
border-radius: 50%;
color: rgba(0, 0, 0, 1);
-o-text-overflow: clip;
text-overflow: clip;
background: #1abc9c;
-webkit-box-shadow: 0 100px 4px -2px rgba(15, 13, 13, 0.53);
box-shadow: 0 100px 4px -2px rgba(15, 13, 13, 0.53);
-webkit-transform: scaleX(5);
transform: scaleX(5);
-webkit-transform-origin: 0 50% 0;
transform-origin: 0 50% 0;
}
<div class="oval"></div>
I want to put the HTML code below the picture if the CSS code works well.

Another method to achieve this would be to make use of a pseudo-element with CSS transform. In the below snippet, the :after pseudo-element is rotated in X-axis by close to 90deg (but not by equal to 90deg) to give it an oval like appearance. Then by adding a radial-gradient background and box-shadow, we can get an appearance close to the image in the picture.
One advantage of this approach is that the shadow that is produced is responsive and so it can adapt to change in container/image sizes.
.oval{
position: relative;
height: 200px;
width: 200px;
border: 8px solid red;
border-radius: 50%;
}
.oval img{
border-radius: 50%;
}
.oval:after{
position: absolute;
content: '';
height: 100%;
width: calc(100% - 40px); /* to offset for the shadow */
top: 25%;
left: 20px; /* to offset for the shadow spread */
border-radius: 50%;
backface-visibility: hidden;
transform-origin: 50% bottom;
transform: rotateX(85deg);
background: radial-gradient(ellipse at center, rgba(216,216,216, 0.5), rgba(248,248,248,0.1));
box-shadow: 0px 0px 20px 20px rgba(248,248,248,0.5);
}
/* Just for demo */
.oval#oval2{ height: 300px; width: 300px; }
div{ float: left; }
<div class="oval">
<img src='http://lorempixel.com/200/200/nature/1' />
</div>
<div class="oval" id="oval2">
<img src='http://lorempixel.com/300/300/nature/1' />
</div>

You could achieve this quite easily if you're able to wrap the <img /> element in a container tag such as a <div>. By using the :after pseudo-selector on the parent div, you can achieve a similar approach using box-shadow.
For example, assuming you have the following markup:
You may add the following CSS definitions:
.image-round {
border: 4px solid red;
border-radius: 50%;
}
.image-shadow {
display: inline-block;
position: relative;
}
.image-shadow:after {
display: block;
content: '';
position: absolute;
bottom: -30px;
height: 10px;
right: 5px;
left: 5px;
border-radius: 50%;
background: #ccc;
box-shadow: 0 0 10px 10px #ccc;
}
Of course, you can modify the left and right properties of the :after pseudo-element to achieve a better look.
jsFiddle Demo

Related

CSS rendering bug on rotated :after pseudo elements

I sure hope I did not miss the according discussion on this:
I define an ":after"-pseudo element to create a triangle on top of a <p> (<div> looks the same) using the following CSS-code:
div {
padding-top: 20px;
}
p {
position: relative;
width: 200px;
height: 100px;
display: block;
background-color: #ccc;
margin: 75px auto 0 auto;
}
p:after {
content: "";
position: absolute;
top: -35px;
width: 50px;
height: 50px;
left: 15%;
background: #ccc;
border: 10px solid #fff;
border-color: #fff #fff #ccc #ccc;
transform: rotate(-45deg);
clip-path: polygon(0 0, 100% 0, 100% 100%);
}
.dark {
background-color: #333;
}
.dark p:after {
border: 10px solid #333;
border-color: #333 #333 #ccc #ccc;
}
<div>
<p></p>
</div>
<div class="dark">
<p></p>
</div>
I noticed a thin outer visible edge (seemingly in the given background-color) in Safari, chromium forked Browsers (Chromium, Vivaldi, Brave, Chrome, Edge) and even worse in Firefox (all on Mac OS X 10.14). I took screenshots in different colors (and magnified by 2) to illustrate the issue. All of this on a non-retina 1080p display.
Can anyone explain this to me?
(The clip-path prevents the edge (which surrounds the whole pseudo-element) from reaching down inside the parenting div.)
The issue seems to be related to angles, Specifically any angle that is not a straight angle.
Related issue
In gradients it happens when there's hard stops from one color to the next, the fix is to avoid hard stops and give the colors room to transition so we don't see the pixels.
div {
height: 300px;
width: 300px;
display: inline-block;
}
[problem] {
background: linear-gradient(30deg, black 50%, orange 50%) no-repeat;
}
[solution] {
background: linear-gradient(30deg, black 49%, orange 50%) no-repeat;
}
<div problem></div>
<div solution></div>
Your issue is similar when you rotate the element to an angle that is not straight the edges are jagged We can't use the same idea from gradients Unfortunately.
*,
*:after,
*:before {
padding: 0;
margin: 0;
box-sizing: border-box;
}
div {
background-color: #333;
height: 300px;
width: 300px;
position: relative;
}
div:after {
content: "";
position: absolute;
top: 25%;
left: 25%;
width: 50%;
height: 50%;
background: #ccc;
transform: rotate(1deg);/* any angle that is not right*/
border: 30px solid #333;
}
<div></div>
Though we can clip it, to prevent the hard stop between the :after's background and the background of the parent because they're different.
*,
*:after,
*:before {
padding: 0;
margin: 0;
box-sizing: border-box;
}
div {
background-color: #333;
height: 300px;
width: 300px;
position: relative;
}
div:after {
content: "";
position: absolute;
top: 25%;
left: 25%;
width: 50%;
height: 50%;
background: #ccc;
background-clip: content-box;
transform: rotate(-45deg);
clip-path: polygon(0 0, 100% 0, 100% 100%);
border: 30px solid #333;
}
<div></div>
Original code:
html, body {
margin: 0;
padding: 0;
}
div {
margin: 0;
padding: 20px;
}
p {
position: relative;
width: 200px;
height: 200px;
display: block;
background-color: #ccc;
margin: 75px auto;
padding: 0;
}
p:after {
content: "";
position: absolute;
top: -35px;
width: 50px;
height: 50px;
left: 15%;
background: #ccc;
background-clip: content-box; /* NEW */
border: 10px solid #fff;
border-color: #fff #fff #ccc #ccc;
transform: rotate(-45deg);
clip-path: polygon(0 0, 100% 0, 100% 100%);
}
.dark {
background-color: #333;
}
.dark p:after {
border: 10px solid #333;
/* border-color: #333 #333 #ccc #ccc; */
}
<div>
<p></p>
</div>
<div class="dark">
<p></p>
</div>
Tested in latest Chrome and FF on Win 8
The issue might pop back up with the background itself, You can see it in the demo below
A bit of jaggedness on the sides of the background, it's subtle but you can see it if you're looking for it
*,
*:after,
*:before {
padding: 0;
margin: 0;
box-sizing: border-box;
}
div {
background-color: #333;
height: 300px;
width: 300px;
position: relative;
}
div:after {
content: "";
position: absolute;
top: 25%;
left: 25%;
width: 50%;
height: 50%;
background: #ccc;
background-clip: content-box;
transform: rotate(1deg);
clip-path: polygon(0 0, 100% 0, 100% 100%);
border: 30px solid #333;
}
<div></div>
We can fix it by having 4 gradients on the edges which transition outward from the color of the current background to the color of whatever is behind which would be tricky to manage dynamically.

Add shadow to custom shape made with border in CSS

Ok, so in HTML I have one div tag with a before and after pseudo elements. This is my CSS:
.divClass{
background: #41423D;
height:30px;
}
.divClass:before{
content: '';
line-height: 0;
font-size: 0;
width: 0;
height: 0;
border-width :15px 7px 15px 7px;
border-color: transparent #41423D #41423D transparent;
border-style:solid;
position: absolute;
top: 0;
left: -14px;
}
.divClass:after{
content: '';
line-height: 0;
font-size: 0;
width: 0;
height: 0;
border-width :15px 7px 15px 7px;
border-color: transparent transparent #41423D #41423D;
border-style:solid;
position: absolute;
top: 0;
right: -14px;
}
So, in design it becomes like this:
___
/ \
Now all I need is a shadow on the before and after pseudo elements which are the 2 triangles on either side of the div. The pseudo elements have 0 width and height so using box-shadow is a little tricky.
I need the shadow along the triangle. So, what can I do?
You can use unicode character : ▲ to make the triangles.
Apply a text shadow on it.
If the shape of the triangle is not what you want you can adjust it with transform: rotate(); or transform: skewX(); or both.
It's a bit tricky and not perfect but it can works :
span {
display: inline-block;
font-size: 70px;
transform: skewX(29.5deg);
color: red;
text-shadow: 2px 2px 4px gray;
}
<span>▲</span>
There are some other possibilities, all describe on a CSS Tricks post, so check it if you want :
https://css-tricks.com/triangle-with-shadow/
If think you can check filter: drop-shadow() too. In case you do not need a support for all the browsers it may works for you...
edit:
According to the css tricks post, can't you do that ?
.triangle-with-shadow {
transform: rotate(-45deg);
width: 100px;
height: 100px;
position: relative;
overflow: hidden;
box-shadow: 0 20px 10px -17px rgba(0, 0, 0, 0.5);
}
.triangle-with-shadow:after {
content: "";
position: absolute;
width: 50px;
height: 50px;
background: #999;
transform: rotate(45deg); /* Prefixes... */
top: 75px;
left: 25px;
box-shadow: -1px -1px 10px -2px rgba(0, 0, 0, 0.5);
}
<div class="triangle-with-shadow"></div>
Another possibility if you just want the shape that you describe is to use the perspective :
.shape {
background: #41423D;
width: 150px;
height: 150px;
margin: 20px auto;
transform-origin:50% 100%;
transform:perspective(100px) rotateX(30deg);
box-shadow: 2px 2px 15px #41423D;
}
<div class="shape"></div>

box shadow to left and right side

I want to add box shadow to left and right side of a div , here I am attaching a image for that, I don't know how to do this, can somebody help me please? please notice that shadow should be to the point mark on left and right.
body {
background-color: red;
}
.boxWrapper {
height: 100%;
overflow: hidden;
margin: 30px auto;
width: 500px;
padding: 0 60px;
}
.box {
position: relative;
border-radius: 3px;
padding: 20px;
min-height: 300px;
background-color: #fff;
}
.box:before {
content: '';
position: absolute;
width: 100%;
height: 100%;
z-index: -1;
top: -20px;
transform: rotate(-8deg);
left: 20px;
background-color: transparent;
box-shadow: -40px 0 30px rgba(0, 0, 0, 0.3);
}
.box:after {
content: '';
position: absolute;
width: 100%;
height: 100%;
z-index: -1;
top: -20px;
transform: rotate(8deg);
right: 20px;
background-color: transparent;
box-shadow: 40px 0 20px rgba(0, 0, 0, 0.3);
}
<div class="boxWrapper">
<div class="box">
box
</div>
</div>
So this is definitely a neat question. I've played around and was able to at least come up with a stepping stone to the right solution. I've been doing it with the box-shadow method that has been mentioned, but have added it to both an :after and :before pseudo-selector.
Then, I've rotated both these selectors 8 degrees (just to mimic your provided image) and found that it was still showing some unwanted shadow both above the element and below the element.
To solve that, I wrapped the box with a box wrapper thats sole purpose was to define the size of the box as well as hide anything overflowing on the tops and bottoms.
It will definitely need to be adapted to how you need it, as it kinda feels hacky. But I think this provides some ideas on how to approach the problem.
I've created a Codepen so you can see it at work.
http://codepen.io/RyanAaronGreen/pen/Kagdad
Hopefully this gets you what you need. The documentation for the box-shadow property is located Here on MDN.
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.container {
background-color: pink;
height: 100%;
padding: 10px;
}
.content {
width: 85%;
margin: 0 auto;
box-sizing: border-box;
height: calc(100% - 10px);
box-shadow: -5px 5px 5px rgba(0, 0, 0, 0.3), 5px 5px 5px rgba(0, 0, 0, 0.3);
background-color: white;
}
<div class="container">
<div class="content">
Hello
</div>
</div>
Use this samples
CSS3 drop shadow

Semi-transparent slanted background

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>

CSS box shadow conflicting with pseudo-element

Is there a way to disable the box shadow for the part where the pseudo-element arrow resides?
Current:
or without the negative z-index on the pseudo-element:
Desired result:
#element {
position: relative;
width: 100px;
height: 100px;
background-color: blue;
box-shadow: 5px 5px 5px #222;
}
#element::after {
content: "";
width: 25px;
height: 25px;
background-color: blue;
top: 40px;
left: 88px;
transform: rotate(45deg);
position: absolute;
z-index: -1;
-webkit-filter: drop-shadow(5px 5px 5px #222);
filter: drop-shadow(5px 5px 5px #222);
}
<div id="element"></div>
You can't control which parts of a box shadow or a drop shadow filter are rendered, at least not directly.
Depending on your layout, you could cheat by patching another pseudo-element over the one that you have. I swap the ::after with a ::before to obviate the need for z-index because boxes with the same stack level stack from back to front (meaning ::after stacks in front of ::before).
However if you have any content in your element, you will need to position the content and give it z-index: 1 to ensure that it will paint on top of both of your pseudo-element boxes, since ::after comes after the main content and will therefore also stack in front of the content. See the #element > p rule in the following example.
#element {
position: relative;
width: 100px;
height: 100px;
background-color: blue;
box-shadow: 5px 5px 5px #222;
}
#element::before, #element::after {
content: "";
background-color: inherit;
position: absolute;
}
#element::before {
width: 25px;
height: 25px;
top: 40px;
left: 88px;
transform: rotate(45deg);
-webkit-filter: drop-shadow(5px 5px 5px #222);
filter: drop-shadow(5px 5px 5px #222);
}
#element::after {
top: 0;
right: 0;
bottom: 0;
left: 0;
}
#element > p {
position: relative;
z-index: 1;
}
<div id="element"><p>text</p></div>

Resources