对于奇数像素宽度,变换比例工作不正确

时间:2017-12-31 16:18:01

标签: html css css3 css-transforms scaletransform

我正在尝试缩放div,但将内部元素保持在相同位置相同大小。为此,我在包装器上使用transform: scale(value),在内部div上使用transform: scale(1/value)

问题是,当我改变比例时,内部div会发生变化。只有当包装纸的宽度/高度为奇数或不是整数时才会发生这种情况。对于包装器的均匀宽度/高度,它不会发生。

我的目标是让许多包装器的子元素与包装器一起缩放,但只有一个不包装。

看看这个例子,看看行动中的问题(悬停到比例)。

示例无问题,内部元素保持固定(容器的高度和宽度均匀):

https://jsfiddle.net/o16rau6u/5/

.wrapper {
  width: 200px;
  height: 200px;
  background-color: blue;
  position: relative;
}

.bg {
  width: 20px;
  height: 20px;
  display: inline-block;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -10px;
  margin-left: -10px;
  background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Wiktionary_small.svg/350px-Wiktionary_small.svg.png");
  background-size: 100% 100%;
  background-repeat: no-repeat;
}

.wrapper:hover {
  transform: scale(2);
}

.wrapper:hover .bg {
  transform: scale(0.5);
}
<div id="wrapper" class="wrapper">
  <div id="bg" class="bg"></div>
</div>

问题示例,内部元素在比例上移动一点(容器的高度和宽度是奇数):

https://jsfiddle.net/o16rau6u/6/

.wrapper {
  width: 201px;
  height: 201px;
  background-color: blue;
  position: relative;
}

.bg {
  width: 20px;
  height: 20px;
  display: inline-block;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -10px;
  margin-left: -10px;
  background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Wiktionary_small.svg/350px-Wiktionary_small.svg.png");
  background-size: 100% 100%;
  background-repeat: no-repeat;
}

.wrapper:hover {
  transform: scale(2);
}

.wrapper:hover .bg {
  transform: scale(0.5);
}
<div id="wrapper" class="wrapper">
  <div id="bg" class="bg"></div>
</div>

如何解决这个问题并避免我的元素在容器大小上按比例移动?

PS: 上面使用的示例是一个非常简单的示例,用于显示问题,而不是所需的输出或使用的代码。因此,我们不是在寻找另一种方法来实现上述相同的行为,因为它很容易完成

3 个答案:

答案 0 :(得分:7)

一开始我认为这与浏览器的计算和一些舍入有关,但它似乎是错误的。我已经做了很多测试,并且我使用它的标度值总是在奇数值上失败。

以下是仅scaleX

的简单示例

&#13;
&#13;
body:after {
  content: "";
  position: absolute;
  z-index: 999;
  top: 0;
  bottom: -200%;
  width: 2px;
  right: 50%;
  margin-right: -1px;
  background: rgba(0, 0, 0, 0.5);
}

.box {
  width: 200px;
  height: 100px;
  margin: 50px auto;
  background: blue;
  position: relative;
}

.inner {
  height: 20px;
  width: 20px;
  background: red;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-left: -10px;
  text-align: center;
  color: #fff;
  margin-top: -10px;
}
&#13;
<div class="box">
  <div class="inner">A</div>
</div>

<div class="box" style="transform:scaleX(2)">
  <div class="inner" style="transform:scaleX(0.5)">A</div>
</div>

<div class="box" style="width:201px;transform:scaleX(2)">
  <div class="inner" style="transform:scaleX(0.5)">A</div>
</div>
&#13;
&#13;
&#13;

正如您在下面看到的,浏览器似乎在内部div中添加了一个额外的像素,但如果您仔细观察,内部div的大小正确,但正在翻译 1px到右边。所以Dev Tools的悬停块定位正确但不是元素本身!因此,似乎浏览器正确计算了位置,但做了错误的绘画。

enter image description here

如果我们只是在容器上应用scale,就会出现同样的问题。所以这不是因为内部元素的规模:

&#13;
&#13;
body:after {
  content: "";
  position: absolute;
  z-index: 999;
  top: 0;
  bottom: -200%;
  width: 2px;
  right: 50%;
  margin-right: -1px;
  background: rgba(0, 0, 0, 0.5);
}

.box {
  width: 200px;
  height: 100px;
  margin: 50px auto;
  background: blue;
  position: relative;
}

.inner {
  height: 20px;
  width: 20px;
  background: red;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-left: -10px;
  text-align: center;
  color: #fff;
  margin-top: -10px;
}
&#13;
<div class="box" style="transform:scaleX(2)">
  <div class="inner">A</div>
</div>

<div class="box" style="width:201px;transform:scaleX(2)">
  <div class="inner">A</div>
</div>
&#13;
&#13;
&#13;

enter image description here

即使我们使用带有比例的浮动值,我们可以说有一些路由和复杂的计算,我们有正确的输出,偶数值和奇数值的问题:

规模(1.25)&amp;规模(1 / 1.25):

&#13;
&#13;
body:after {
  content: "";
  position: absolute;
  z-index: 999;
  top: 0;
  bottom: -200%;
  width: 2px;
  right: 50%;
  margin-right: -1px;
  background: rgba(0, 0, 0, 0.5);
}

.box {
  width: 200px;
  height: 100px;
  margin: 50px auto;
  background: blue;
  position: relative;
}

.inner {
  height: 20px;
  width: 20px;
  background: red;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-left: -10px;
  text-align: center;
  color: #fff;
  margin-top: -10px;
}
&#13;
<div class="box">
  <div class="inner">A</div>
</div>

<div class="box" style="transform:scaleX(1.25)">
  <div class="inner" style="transform:scaleX(0.8)">A</div>
</div>

<div class="box" style="width:201px;transform:scaleX(1.25)">
  <div class="inner" style="transform:scaleX(0.8)">A</div>
</div>
&#13;
&#13;
&#13;

规模(1.33)&amp;规模(1 / 1.33):

&#13;
&#13;
body:after {
  content: "";
  position: absolute;
  z-index: 999;
  top: 0;
  bottom: -200%;
  width: 2px;
  right: 50%;
  margin-right: -1px;
  background: rgba(0, 0, 0, 0.5);
}

.box {
  width: 200px;
  height: 100px;
  margin: 50px auto;
  background: blue;
  position: relative;
}

.inner {
  height: 20px;
  width: 20px;
  background: red;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-left: -10px;
  text-align: center;
  color: #fff;
  margin-top: -10px;
}
&#13;
<div class="box">
  <div class="inner">A</div>
</div>

<div class="box" style="transform:scaleX(1.33)">
  <div class="inner" style="transform:scaleX(calc(1 / 1.33))">A</div>
</div>

<div class="box" style="width:201px;transform:scaleX(1.33)">
  <div class="inner" style="transform:scaleX(calc(1 / 1.33))">A</div>
</div>
&#13;
&#13;
&#13;

答案 1 :(得分:3)

请不要将其中一个div放入另一个div中,而是将它们放入第三个div中,如下所示:

.wrapper {
  width: 201px;
  height: 201px;
  position: relative;
}

.div-1 {
  width: 100%;
  height: 100%;
  background-color: blue;
}

.div-1:hover {
  transform: scale(2);
}

.div-2 {
  width: 20px;
  height: 20px;
  display: inline-block;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -10px;
  margin-left: -10px;
  background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Wiktionary_small.svg/350px-Wiktionary_small.svg.png");
  background-size: 100% 100%;
  background-repeat: no-repeat;
}
<div class="wrapper">
  <div class="div-1"></div>
  <div class="div-2"></div>
</div>

这样你就不需要将内部div缩放回原来的高度和宽度。

答案 2 :(得分:0)

浏览器在计算内容时notoriously bad。曾经有一段时间,网络开发人员数学表明(在某些浏览器中)33.33%3次大于100%(但那是14年前)。从那时起事情变得更好,但不要依赖它。像这样做调整大小的技巧不是要走的路。

在我看来,你想要调整包装器的大小,同时保持背景大小相同。为此,您正在使用复杂的转换技巧,所有互联网用户(未加固定)excludes 17%。这是不正确的浏览器支持以及不这样做的另一个原因。

这种效果可以通过99.99%的浏览器支持轻松实现,适用于所有尺寸。

&#13;
&#13;
.wrapper {
  width: 402px;
  height: 402px;
  background-color: blue;
  position: relative;
}

.bg {
  width: 20px;
  height: 20px;
  display: block;
  position: absolute;
  top: 201px;
  left: 201px;
  margin-top: -10px;
  margin-left: -10px;
  background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Wiktionary_small.svg/350px-Wiktionary_small.svg.png");
  background-size: 100% 100%;
  background-repeat: no-repeat;
}

.wrapper:hover {
  width: 4020px;
  height: 4020px;
}
&#13;
<div id="wrapper" class="wrapper">
  <div id="bg" class="bg"></div>
</div>
&#13;
&#13;
&#13;

如果你想让它响应(你这样做!),这应该可以解决问题:

&#13;
&#13;
* {padding: 0; margin: 0;}
html, body {height: 100%;}

.wrapper {
  width: 50vw;
  background-color: blue;
  position: relative;
  padding-bottom: 50%;
}

.bg {
  width: 20px;
  height: 20px;
  display: block;
  position: absolute;
  top: 25vw;
  left: 25vw;
  margin-top: -10px;
  margin-left: -10px;
  background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Wiktionary_small.svg/350px-Wiktionary_small.svg.png");
  background-size: 100% 100%;
  background-repeat: no-repeat;
}

.wrapper:hover {
  width: 500vw;
  padding-bottom: 500%;
}
&#13;
<div id="wrapper" class="wrapper">
  <div id="bg" class="bg"></div>
</div>
&#13;
&#13;
&#13;