滚动条与转换对象的实际边界不匹配

Scrollbars don't match the real bounds of transformed object

我尝试使用 transform: rotate(45deg); 旋转 html 元素。这确实有效,但是滚动条与旋转元素的视觉边界不匹配。

上下文是我想创建一个 pdf 查看器应用程序,用户还可以在其中旋转文件以提高可读性。但是,他不可能滚动整个文件,因为滚动条不够长。

this fiddle为例。滚动条太短,无法滚动到每个角落。

我该如何解决这个问题,以便您可以滚动浏览整个元素?

一个jQuery解决方案就可以了。我在 Chrome v.60

中对此进行了测试

当发生 html 转换时,它独立于其他元素工作。这意味着转换后的元素不会移动邻居或调整其父元素的大小。

您可以为图像的父级使用预定的填充。或者您可以在转换期间更改它,但在这种情况下您需要注意 window 滚动位置。

90 度旋转元素所需的填充取决于要旋转的图像的较大尺寸,等于:

(biggerDimension - lesserDimension) / 2

因此,您的 jQuery 函数为父项获取正确的填充将类似于这个抽象函数:

var $img       = $('img'),
     imgWidth  = $img.width(),
     imgHeight = $img.height();

if (imgWidth > imgHeight) {
  var parentPadding = (imgWidth - imgHeight) / 2;
} else {
  var parentPadding = (imgHeight - imgWidth) / 2;
}

如果您的图像是方形的,而无需填充(90 度旋转)。

但是如果你想找到所需的最大填充(45 度、135 度等旋转),公式会稍微复杂一些。 例如,如果最大的尺寸是宽度,而你想设置 padding-top:

sqrt(imgWidth^2 + imgHeight^2) / 2 - imgHeight / 2

对角线的一半减去高度的一半。您可以针对高度较大和其他角的情况更改公式。

当然,如果 img 是响应式的,则需要在调整大小时调用该函数。

所以我认为我们需要克服的两个主要问题是:

  1. 图片比容器大
  2. 即使图像没有比容器大,一旦旋转,它也会变大,因为对角之间的长度将比图像任一侧的长度长

所以这里的基本方法是在 #wrapper 中添加一个额外的 div 并且:

  1. 使图片大小与#wrapper
  2. 相同
  3. 确保新的 div 足够大以适应图像,即使它被旋转

诀窍是弄清楚内包装应该有多大。这就是黄金老 Pythagorean Theorem 发挥作用的时候了。

使用一些数学知识,我们可以计算出对于 500x300 的图像,对角之间的长度为 583 像素并且有一些变化。因此,让我们将新的内部 div 设置为 584px 宽和高。

<div id="wrapper" style="width: 500px; height: 300px;">
  <div id="content" style="width: 584px; height: 584px"></div>
</div>

然后,让我们确保将图像置于内部 div 的中心,这样当它旋转时,它始终适合。

#content {
  position: relative;
}
#content img {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translateX(-50%) translateY(-50%);
}

从那里开始,鉴于 #content 中的图像与 #wrapper 的大小完全相同,理论上我们应该可以开始了。

不幸的是,就支持任意大小的图像或灵活的容器而言,此解决方案不够灵活。实际上没有任何 calc() 表达式可以用来得出我们的内部容器的大小(至少我可以得出),因为我们的操作仅限于加法、减法、乘法和 division,所以你需要自己计算这个数字并使用固定值。但是 它确实有效 ,并且希望您的用例是 PDF 查看器,您的图像将始终具有相同的尺寸,因此您可以使其有效。

这里唯一需要清除的障碍是,当图像根本不旋转时,图像在容器中并不完全可见,这有点奇怪。为此,我可能会尝试使用 JavaScript 将 #wrapper 的滚动位置设置为与图像的左上角匹配。我会把它留给你。

演示

$('#slider').on('input', function(){
  $('#content').css("transform", "rotate(" + $("#slider").val() + "deg)");
});
#wrapper {
  padding: 0;
  width: 500px;
  height: 300px;
  overflow: auto;
}
#content {
  width: 584px;
  height: 584px;
  position: relative;
}
#content img {
  width: 500px;
  height: 300px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translateX(-50%) translateY(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper">
  <div id="content">
    <img src="https://www.w3schools.com/css/img_lights.jpg">
  </div>
</div>
<input id="slider" type="range" min="0" max="360" step="1" value="0">