题 Webkit bug:在将子元素的大小调整为匹配大小后自动触发溢出


我有以下简单的设置:

document.getElementById('inner').addEventListener('click', ({ target }) => {
  target.classList.add('match');
});
#container {
  background: green;
  overflow: auto;
  width: 200px;
  height: 100px;
}

#inner {
  width: 210px;
  height: 110px;
}

#inner.match {
  width: 200px;
  height: 100px;
}
<div id="container">
  <div id="inner"></div>
</div>

单击内部元素后,我希望父项上的滚动条消失,因为这两个元素现在具有匹配的大小。这在Firefox中可以正常工作。
但是,容器元素不会丢失Chrome中的滚动条,如下面的屏幕截图所示:

Sample image

滚动条本身会创建一个足以产生溢出的偏移量。
这是特定于webkit的问题吗?对于这个(看似微不足道的)问题,是否存在跨浏览器,可靠的解决方案?

我正在寻找一种不会改变父母属性作为我的内容的解决方案(#inner)将被放置在DOM中我无法控制。

到目前为止,我已经尝试在不同的执行点隐藏/显示和/或分离/重新插入元素,但问题仍然存在,可能是因为操作被简单地优化掉了。

问题出现在Jsfiddle和Stack片段中。

该错误已经提交 Webkit Bugzilla


12
2017-12-14 22:35


起源


如何设置父元素溢出:点击隐藏?我在OS X上使用相同版本的Chrome,无法在您的jsfiddle中重现该问题。 - Aweary
@Aweary这是我想要避免的东西,因为我的内容将放在我无法控制的DOM中。虽然这可能是一种解决方法,但实际上并没有解决或解释这个问题。 - Nit
我无法在OS X 10.10的Chrome 39.0.2171.95中重现此问题。你可能有任何可能干扰的扩展吗? - Aweary
我能够在我的实验室Mac(OS X 10.10)上运行Chrome(相同版本)以及Safari 8重现它。不确定为什么我的便携式设备没有问题。 - Aweary
在Windows上的Firefox 34.0.1中测试过,不会出现问题。在Windows上的Opera 26.0.1656.32中测试并出现问题。在Windows上的Safari 5.1.7中测试,出现问题。从所有这些测试来看,它看起来像Webkit特有的。非Webkit浏览器没有问题。 - TylerH


答案:


不涉及解决父级问题的解决方法是 强制浏览器重绘 应用样式后。

document.getElementById('inner').addEventListener('click', ({ target }) => {
  target.classList.add('match');
  //Force redraw
  target.style.display='none';
  target.offsetHeight; //Won't work without this
  target.style.display='';
});
#container {
  background: green;
  overflow: auto;
  width: 200px;
  height: 100px;
}

#inner {
  width: 210px;
  height: 110px;
}

#inner.match {
  width: 200px;
  height: 100px;
}
<div id="container">
  <div id="inner"></div>
</div>

我不能保证这是一个一致工作的解决方案(请参阅关于强制重绘可能问题的链接线程),但至少在这个特定情况下,这似乎可以通过我的初始测试。
我已经向Webkit提交了一个描述上述所有行为的错误,但在此之前,这是一个可行的选择。


4
2017-12-15 06:30



这是对的。你需要 触发回流。您可以使用jQuery hide / offset / show函数。 - Salman A
@SalmanA感谢您的链接,它完全解释了 为什么 解决方法有效。 - Nit


以下是在Chrome中解决此问题的三种解决方案。

解决方案1

$('.i').on('click', function() {
    var t = $(this);
    t.css({
        width: '100%',
        height: '100%'
   });
});

解决方案2

$('.i').on('click', function() {
    var t = $(this);
    t.css({
        width : '200px',
        height : '100px',
        zoom : 0.5
   });
    setTimeout(function(){
    t.css({
        zoom : 1
    })}, 1);    
});

解决方案3

使用动画工作

$('.i').on('click', function() {
    var t = $(this);
    t.css({
        width: '100%',
        height: '100%',
        '-webkit-animation': 'animate 0.01s, linear'
   });
});

添加到CSS:

/* Chrome, Safari, Opera */
@-webkit-keyframes animate {
    from {width: 180px; height: 100px;}
    to {width: 200px; height: 100px;}
}

1
2017-12-21 00:21



很好找。虽然这肯定是有用的,但我认为使用百分比总是一个选项(因为这个错误可能在各种设置中发生)。 - Nit
我相信,正如其他人所做的那样,这确实是Webkit中的一个错误(在Safari中也应该可以重现吗?)。当您缩小尺寸20个像素(大约一个滚动条的大小)时,它突然适合,两个滚动条都消失了。当然,在一个维度上留出20px的差距。我已经添加 box-sizing: border-box div和问题仍然存在。看起来像一个bug,显示像一个bug,必须是一个bug。 - Mouser
这个问题在Safari中是可重现的,已经在问题中记录了。 - Nit
这并不能解决问题,因为它最终会导致子元素小于父元素。 - Nit
@Nit此代码有效。它使用了轻微的延迟和缩放。 - Mouser


要删除滚动条,您需要重绘父$('。c')元素。但是简单的hide(style =“display:none;”),然后show(style =“display:block;”)根本没有效果。 通过更新溢出属性,您需要每次检查更新的宽度和高度,并根据条件,您必须更改溢出属性的值。

尝试以下代码

$('.i').on('click', function() {
    var t = $(this);
    t.css({
        width: 200,
        height: 100
    })

    $('.c').slideUp(0).slideDown(0); // added
});

我尝试了值为0的jquery slideUp()和slideDown()方法。它在windows chrome和safari上工作正常。我希望它也适用于Mac的浏览器。 仅供参考:使用值为0的jquery hide()和show()方法也可以正常工作。


-1
2017-12-23 11:35



在回答之前,请完整阅读问题。我正在寻找一种不解决父母问题的解决方案。 - Nit


从所有浏览器测试来看,这个问题似乎可以重现并与基于webkit的浏览器隔离。

我建议查看是否有使用webkit的开放票证,或者提交错误报告: https://bugs.webkit.org/

这张旧票 似乎与您的问题有关。除了操纵父元素(你说的不实用)之外,我不确定是否有任何变通方法。


-3
2017-12-14 23:28