【问题标题】:Child position differs from assigned if container has non-integer (%) position如果容器具有非整数 (%) 位置,则子位置与分配的位置不同
【发布时间】:2012-11-10 09:11:54
【问题描述】:

我已将(position: absolute; left: 50%; margin: -50px;) 100px 宽度的 div(容器)居中。

它有绝对定位子 div 与 overflow: hidden,其大小为 100x2000 px(此高度用于测试目的,如下所述)。

子 div 中有一张图片,它是绝对定位的。 图片是3100x100 px,,它包含动画帧。

我通过将其style.left 从 0 更改为 -1100 像素来设置此图像的动画,步长为 100 像素。 一切都很好,但是当身体宽度不均匀时我遇到了奇怪的问题。

如果有滚动条并且滚动条宽度奇数,就会发生这种情况(例如,在 Chrome/Win32 上发生这种情况)。 在这种情况下,只要动画图像通过屏幕边缘,图像就会在视觉上水平移动 1 个像素(对于 1920x1080,它大约发生在动画的 9-10 帧处)。 我找不到此行为的解决方法。

可以找到重现问题的工作示例here

子 div 高度设置为 2000px 以确保滚动条可见。 如果滚动条的宽度是偶数,您可以通过将浏览器窗口调整为奇数宽度来重现该问题。

【问题讨论】:

  • 您应该更好地记录您的问题,例如,您可以将某些内容粘贴到 jsfiddle.net 吗?
  • 我可以看看css和jquery代码吗
  • Fiddled: jsfiddle.net/PjHFc 问题似乎仅限于 Chrome/Webkit。
  • 为什么不用gif动画?
  • 哇,不知道 jsfiddle。对不起。从现在开始使用它;) gif 动画绝对不是我项目中需要的东西。 gif 有很多缺点,例如 8 位调色板和只有二进制透明度...

标签: javascript html css animation


【解决方案1】:

这是因为浏览器的四舍五入引擎。 Webkit 显然在偶数和奇数宽度上的 50% 存在一些问题。

解决此问题的一种方法 - 根据窗口宽度重新定位 .outer 元素

document.getElementById( 'outer' ).style.left = Math.floor( window.innerWidth / 2 ) + 'px';

DEMO

【讨论】:

  • 您可以将该行移出循环,因此它只会运行一次 - jsfiddle.net/PjHFc/4
  • 这样,当用户调整浏览器窗口大小时,它不会自动重新计算。在 JS 代码中进行定位通常在性能方面是个坏主意。
  • 如果您尝试调整窗口大小,您会发现它可以工作。我同意循环执行它不是最好的主意,但单个 JS 重新定位不会有 任何对性能的影响:)
  • 如果是 single JS 重新定位怎么办?除非你把它放在调整大小处理程序中。
【解决方案2】:

您需要将.inner img position 更改为relative 并更新您的javascript。我为你做了更改,所以这是你解决的代码:

<!DOCTYPE html>
<html>
    <head>
        <title>test</title>
        <style>
            body {
                background-color: #000000;
            }
            .outer {
                position: absolute;
                left: 50%;
                margin-left: -50px;
            }
            .inner {
                position: absolute;
                width: 100px;
                height: 2000px;
                overflow: hidden;
            }
            .inner img {
                position: relative;
                top: 0;
                left: 0;
            }
        </style>
    </head>
    <body>
        <div class="outer">
            <div class="inner">
                <img src="http://lorgame.ru/test.png" id="img">
            </div>
        </div>
        <script language="JavaScript">
            var framesCount = 30;
            var framesCurrent = 0;
            var framesMoveLeft = true;
            var img = document.getElementById('img');
            var interval = setInterval(function() {
                if(framesMoveLeft == true){
                  framesCurrent++;
                  img.style.left = (img.offsetLeft - 100) + 'px';
                  if(framesCurrent == framesCount) framesMoveLeft = false;
                } else { // Move right
                  framesCurrent--;
                  img.style.left = (img.offsetLeft + 100) + 'px';
                  if(framesCurrent == 0) framesMoveLeft = true;
                }
            }, 100);
        </script>
    </body>
</html>

【讨论】:

  • 感谢您的想法。我的代码被简化了,动画可能更复杂,“帧”数组的存在是有原因的。但是,我当然可以更改您的代码以使其播放具有指定帧顺序的任何动画。所以我想我会在进一步的项目中使用这种方法。但是,我将不得不坚持以下针对该项目建议的“肮脏黑客”解决方案,因为我负担不起重新编写所有动画代码 atm。无论如何,谢谢你的好主意!
  • 我会在你的答案和 Kaivosukeltaja 的答案之间分享赏金,但似乎我不能。对不起:(
【解决方案3】:

在我看来,这似乎是 Chrome 中的一个错误。当百分比以整数定义时,它们的行为相当出乎意料。尝试将位置定义为小数:

.outer {
    position: absolute;
    left: 49.99999%;
    margin-left: -50px;
}

我在fiddle 上对此进行了测试,似乎可以解决问题。

【讨论】:

  • 谢谢,这看起来像一个肮脏的黑客,但它可以完成工作,并且不需要在每次按照其他答案中的建议调整窗口大小时重写整个动画代码或重新定位 .outer 。我会将其标记为已接受的答案。它很脏,但我必须使用它。非常感谢!
猜你喜欢
  • 2018-12-19
  • 2021-08-12
  • 2018-04-23
  • 1970-01-01
  • 2020-06-26
  • 1970-01-01
  • 2022-01-13
  • 2022-11-28
  • 2017-06-06
相关资源
最近更新 更多