When giving e.g. a <div>
a box-shadow as well as rotating it will cause a rotation of the box-shadow direction - which is problematic when the box-shadow should create an illusion of lighting.
Example: https://jsfiddle.net/5h7z4swk/
div {
width: 50px;
height: 50px;
margin: 20px;
box-shadow: 10px 10px 10px #000;
display: inline-block;
}
#box1 {
background-color: #b00;
}
#box2 {
background-color: #0b0;
transform: rotate(30deg);
}
#box3 {
background-color: #00b;
transform: rotate(60deg);
}
#box4 {
background-color: #b0b;
transform: rotate(90deg);
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#box6 {
background-color: #0bb;
animation-name: spin;
animation-duration: 2s;
animation-iteration-count: infinite;
}
<div id="box1"></div>
<div id="box2"></div>
<div id="box3"></div>
<div id="box4"></div>
<div id="box6"></div>
The answer to this problem should look similar to this mock up:
How can I rotate a <div>
and still keep the box-shadow going the same direction?
The solution should be pure CSS...
Note: The animation in the CSS is for demonstration purposes. The use case will use JavaScript to set the rotation. But the JavaScript will know nothing about the box-shadow as it is in the responsibility of the design to define a (or many...) shadows. That's why it should be a pure CSS solution.
Keeping direction of an offset box-shadow consistent during rotation is simple with CSS transforms.
This approach relies on the fact that the transform origin is moved with the transforms. This means that when several transforms are set on the same element, the coordinate system of each transform changes according to the previous ones.
In the following example, the blue element is a pseudo element and the shadow is the div element:
div {
width: 40px; height: 40px;
margin: 40px;
box-shadow: 0px 0px 10px 5px #000;
animation: spinShadow 2s infinite;
background-color: #000;
}
@keyframes spinShadow {
to { transform: rotate(360deg); }
}
div:before {
content: '';
position: absolute;
left:-5px; top:-5px;
width: 50px; height: 50px;
transform: rotate(0deg) translate(-10px, -10px) rotate(0deg);
animation:inherit;
animation-name: spinElt;
background-color: #0bb;
}
@keyframes spinElt {
to { transform: rotate(-360deg) translate(-10px, -10px) rotate(360deg); }
}
<div></div>
Explanation of the transition property on the pseudo element (See the following code snippet for an illustration of the steps):
transform: rotate(-360deg) translate(-10px, -10px) rotate(360deg)
rotate(-360deg)
counters the rotation of the parent to make the pseudo element static.
translate(-10px, -10px)
the pseudo element is translated to make the shadow offset
rotate(360deg)
the pseudo element is rotated in the same direction as parent
div {
width: 40px; height: 40px;
margin: 40px;
box-shadow: 0px 0px 10px 5px #000;
animation: spinShadow 2s infinite;
background-color: #000;
}
@keyframes spinShadow {
to { transform: rotate(360deg); }
}
div:before {
content: '';
position: absolute;
left:-5px; top:-5px;
width: 50px; height: 50px;
animation:inherit;
background-color: #0bb;
}
#first:before{
transform: rotate(0deg);
animation-name: first;
}
@keyframes first {
to { transform: rotate(-360deg); }
}
#second:before{
transform: rotate(0deg) translate(-10px, -10px);
animation-name: second;
}
@keyframes second {
to { transform: rotate(-360deg) translate(-10px, -10px); }
}
#complete:before{
transform: rotate(0deg) translate(-10px, -10px) rotate(0deg);
animation-name: complete;
}
@keyframes complete {
to { transform: rotate(-360deg) translate(-10px, -10px) rotate(360deg); }
}
<ol>
<li>Counter rotate:<div id="first"></div></li>
<li>Translate :<div id="second"></div></li>
<li>Rotate:<div id="complete"></div></li>
<ol>
You could as well integrate box-shadow direction inside animation frames:
div {
display: inline-block;
margin: 1em ;
height: 50px;
width: 50px;
box-shadow: 15px 15px 15px 5px gray;
animation: rte 5s infinite linear;
}
.red {
background: red
}
.green {
background: green;
animation-delay:2s;
}
.blue {
background: blue;
animation-delay:4s;
}
.bob {
background: #b0b;
animation-delay:6s;
}
.cyan {
background: cyan;
animation-delay:8s;
}
@keyframes rte {
25% {
box-shadow: 15px -15px 15px 5px gray;
}
50% {
box-shadow: -15px -15px 15px 5px gray;
}
75% {
box-shadow: -15px 15px 15px 5px gray;
}
100% {
transform: rotate(360deg);
}
}
<div class="red"></div>
<div class="green"></div>
<div class="blue"></div>
<div class="bob"></div>
<div class="cyan"></div>
Inspired by the other answers I created my own answer as well:
https://jsfiddle.net/zoxgbcrg/1/
.shadow {
background-color: black !important;
width: 40px;
height: 40px;
box-shadow: 0px 0px 10px 5px #000;
margin-top: 35px;
margin-left: 35px;
position: absolute;
z-index: -1;
}
<div class="box1 shadow"></div><div class="box1"></div>
The trick is also to create an additional <div>
to handle the shadow. In my case it's not a :before
but a real DOM element that is moved by margin
.
Note: it seems that of today (31.01.2016) Firefox and Chrome have a subtile rendering difference. So for Firefox https://jsfiddle.net/zoxgbcrg/ is creating the desired result, for Chrome I suggest https://jsfiddle.net/zoxgbcrg/1/