旋转后计算 box-shadow 的位置

3

在使用CSS为旋转元素添加阴影时,阴影的位置会根据元素的旋转而改变。这里有一个例子:

.box {
  width: 200px;
  height: 100px;
  position: absolute;
  left: 20px;
  background-color: #BBF;
  -moz-box-shadow: 10px 10px 5px #888;
  -webkit-box-shadow: 10px 10px 5px #888;
  box-shadow: 10px 10px 5px #888;
}
#box1 {
  top: 20px;
}
#box2 {
  top: 170px;
  -webkit-transform: rotate(20deg);
  -moz-transform: rotate(20deg);
  -o-transform: rotate(20deg);
  -ms-transform: rotate(20deg);
}
#box3 {
  top: 80px;
  left: 250px;
  -webkit-transform: rotate(120deg);
  -moz-transform: rotate(120deg);
  -o-transform: rotate(120deg);
  -ms-transform: rotate(120deg);
}
<div id="box1" class="box"></div>
<div id="box2" class="box"></div>
<div id="box3" class="box"></div>

在旋转后是否有可能计算出阴影应该落在哪里,以便阴影看起来来自所有元素的同一光源?我假设我需要使用JavaScript或服务器端来完成这个任务,这是可以的。


我喜欢它 - 听起来像是一个有趣的挑战。我没有时间写一个完整的答案,但想象一下光源的位置,具有x、y和z值。然后还要考虑所有盒子的z值(z值为文档上方的高度)。从那里开始,这是非常简单的数学问题... - jcuenod
3个回答

4
为了在所有元素上大致相同地复制阴影,不管是否旋转,我最终使用了以下代码:
var shadowOffset = 13;
var shadowX = Math.round(Math.sin(angle * (Math.PI / 180)) * shadowOffset, 2);
var shadowY = Math.round(Math.cos(angle * (Math.PI / 180)) * shadowOffset, 2);

这适用于像这样的盒子阴影参数:

$("#box2").css({ "box-shadow": shadowX + "px " + shadowY + "px 5px #888" });

这里有一个例子:http://jsfiddle.net/3Ybr7/1/

它不是完美的,特别是在小元素上,阴影会被放置在两个像素之间,但它基本上能够工作。


13有什么特别的含义吗? - Olson.dev
@Olson.dev 这只是阴影偏移。与此链接的JSFiddle进行比较http://jsfiddle.net/3Ybr7/2/,您会注意到我已经用45替换了13,并且阴影离对象更远。我将编辑我的答案以更好地展示这一点。 - Joakim Johansson

3

基于这里的答案:Keep box-shadow direction consistent while rotating,可以在CSS中仅使用转换和伪元素来实现。

关键点是随着链接转换,变换的起点会跟随着元素移动。下面是您可以在所有元素上使用相同阴影方向的示例:

.box {
  width: 200px; height: 100px;
  position: absolute;
  left: 20px;
}
.box:before {
  content: '';
  position: absolute;
  top: 5px; left: 5px;
  width: 190px; height: 90px;
  background-color: #888;
  box-shadow: 0px 0px 5px 5px #888;
}
.box:after {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  background-color: #BBF;
}

#box1 { top: 20px; }
#box1:before { transform: translate(10px, 10px); }

#box2 { top: 170px; transform: rotate(20deg); }
#box2:before { transform: rotate(-20deg) translate(10px, 10px) rotate(20deg); }

#box3 { top: 80px; left: 250px; transform: rotate(120deg); }
#box3:before { transform: rotate(-120deg) translate(10px, 10px) rotate(120deg); }
<div id="box1" class="box"></div>
<div id="box2" class="box"></div>
<div id="box3" class="box"></div>


2
我写了一个名为 convertOffset 的函数,它接受阴影的 x 和 y 坐标以及角度,并返回新的 x/y 坐标以匹配旋转。不仅适用于任何阴影位置,而且还支持内嵌阴影。尝试编辑下面的代码片段,并尝试使用不同的值进行实验。

var xOffset = -4;
var yOffset = 5;
var blurSpreadColor = '4px 0 #222';
var inset = false;

for (var i = 1; i < 6; i++) {
  var el = document.getElementById('div' + i);
  var degrees = (i - 1) * 26;
  var offset = convertOffset(xOffset, yOffset, degrees);

  el.style.transform = 'rotate(' + degrees + 'deg)';
  el.style.boxShadow = (inset ? 'inset ' : '') + offset[0] + 'px ' + offset[1] + 'px ' + blurSpreadColor;
}

function convertOffset(x, y, deg) {
  var radians = deg * Math.PI / 180;
  var sin = Math.sin(radians);
  var cos = Math.cos(radians);

  return [
    Math.round((x * cos + y * sin) * 100) / 100,
    Math.round((-x * sin + y * cos) * 100) / 100
  ];
}
.box {
  width: 100px;
  height: 50px;
  background: lightblue;
  margin: 35px 8px;
  display: inline-block;
}
<div class="box" id="div1"></div>
<div class="box" id="div2"></div>
<div class="box" id="div3"></div>
<div class="box" id="div4"></div>
<div class="box" id="div5"></div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接