CSS 如何强制 WebKit 重绘/重绘以传播样式更改?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3485365/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 22:35:50  来源:igfitidea点击:

How can I force WebKit to redraw/repaint to propagate style changes?

cssgoogle-chromesafariwebkit

提问by danorton

I have some trivial JavaScript to effect a style change:

我有一些简单的 JavaScript 来影响样式更改:

sel = document.getElementById('my_id');
sel.className = sel.className.replace(/item-[1-9]-selected/,'item-1-selected');
return false;

This works fine with the latest versions of FF, Opera and IE, but fails on the latest versions of Chrome and Safari.

这适用于最新版本的 FF、Opera 和 IE,但无法在最新版本的 Chrome 和 Safari 上运行。

It affects two descendants, which happen to be siblings. The first sibling updates, but the second doesn't. A child of the second element also has focus and contains the <a>tag that contains the above code in an onclickattribute.

它影响两个后代,它们恰好是兄弟姐妹。第一个兄弟更新,但第二个没有。第二个元素的子元素也有焦点并包含<a>标记,该标记在onclick属性中包含上述代码。

In the Chrome “Developer Tools” window if I nudge (e.g. uncheck & check) anyattribute of anyelement, the second sibling updates to the correct style.

在 Chrome 的“开发人员工具”窗口中,如果我轻推(例如取消选中和选中)任何元素的任何属性,第二个兄弟元素将更新为正确的样式。

Is there a workaround to easily and programmatically “nudge” WebKit into doing the right thing?

是否有一种解决方法可以轻松地以编程方式“推动”WebKit 做正确的事情?

回答by danorton

I found some complicated suggestions and many simple ones that didn't work, but a comment to one of them by Vasil Dinkovprovided a simple solution to force a redraw/repaint that works just fine:

我发现了一些复杂的建议和许多不起作用的简单建议,但是Vasil Dinkov对其中一个的评论提供了一个简单的解决方案来强制重绘/重绘,效果很好:

sel.style.display='none';
sel.offsetHeight; // no need to store this anywhere, the reference is enough
sel.style.display='';

I'll let someone else comment if it works for styles other than “block”.

如果它适用于“块”以外的样式,我会让其他人发表评论。

Thanks, Vasil!

谢谢,瓦西尔!

回答by morewry

We recently encountered this and discovered that promoting the affected element to a composite layerwith translateZin CSS fixed the issue without needing extra JavaScript.

我们最近遇到了这个问题,并发现在 CSS 中使用translateZ将受影响的元素提升到复合层可以解决这个问题,而无需额外的 JavaScript。

.willnotrender { 
   transform: translateZ(0); 
}

As these painting issues show up mostly in Webkit/Blink, and this fix mostly targets Webkit/Blink, it's preferable in some cases. Especially since the accepted answer almost certainly causes a reflowand repaint, notjust a repaint.

由于这些绘制问题主要出现在 Webkit/Blink 中,并且此修复主要针对 Webkit/Blink,因此在某些情况下更可取。特别是因为接受的答案几乎肯定会导致回流和重绘不仅仅是重绘。

Webkit and Blink have been working hard on rendering performance, and these kinds of glitches are the unfortunate side effect of optimizations that aim to reduce unnecessary flows and paints. CSS will-changeor another succeeding specification will be the future solution, most likely.

Webkit 和 Blink 一直在努力提高渲染性能,而这些类型的故障是旨在减少不必要的流程和绘制的优化的不幸副作用。 CSS will-change或其他后续规范很可能是未来的解决方案。

There are other ways to achieve a composite layer, but this is the most common.

还有其他方法可以实现复合层,但这是最常见的。

回答by Gerben

danorton solution didn't work for me. I had some really weird problems where webkit wouldn't draw some elements at all; where text in inputs wasn't updated until onblur; and changing className would not result in a redraw.

danorton 解决方案对我不起作用。我遇到了一些非常奇怪的问题,其中 webkit 根本不会绘制某些元素;输入中的文本直到 onblur 才更新;并且更改 className 不会导致重绘。

My solution, I accidentally discovered, was to add a empty style element to the body, after the script.

我偶然发现,我的解决方案是在脚本之后向正文添加一个空的样式元素。

<body>
...
<script>doSomethingThatWebkitWillMessUp();</script>
<style></style>
...

That fixed it. How weird is that? Hope this is helpful for someone.

那修复了它。这有多奇怪?希望这对某人有帮助。

回答by EricG

Since the display + offset trigger didn't work for me, I found a solution here:

由于显示 + 偏移触发器对我不起作用,我在这里找到了解决方案:

http://mir.aculo.us/2009/09/25/force-redraw-dom-technique-for-webkit-based-browsers/

http://mir.aculo.us/2009/09/25/force-redraw-dom-technique-for-webkit-based-browsers/

i.e.

IE

element.style.webkitTransform = 'scale(1)';

回答by Rob Murphy

I was suffering the same issue. danorton's 'toggling display' fix did work for me when added to the step function of my animation but I was concerned about performance and I looked for other options.

我遇到了同样的问题。danorton 的“切换显示”修复在添加到我的动画的步进功能时确实对我有用,但我担心性能并寻找其他选项。

In my circumstance the element which wasn't repainting was within an absolutely position element which did not, at the time, have a z-index. Adding a z-index to this element changed the behaviour of Chrome and repaints happened as expected -> animations became smooth.

在我的情况下,未重绘的元素位于绝对位置元素内,当时该元素没有 z-index。向该元素添加 z-index 改变了 Chrome 的行为,并且重绘按预期发生 -> 动画变得平滑。

I doubt that this is a panacea, I imagine it depends whyChrome has chosen not to redraw the element but I'm posting this specific solution here in the help it hopes someone.

我怀疑这是一个万能的,我想这取决于为什么Chrome的选择不重绘元素,但我在它希望有人帮助下在这里张贴此特定的解决方案。

Cheers, Rob

干杯,罗布

tl;dr >> Try adding a z-index to the element or a parent thereof.

tl;dr >> 尝试向元素或其父元素添加 z-index。

回答by sweeds

The following works. It only has to be set once in pure CSS. And it works more reliably than a JS function. Performance seems unaffected.

以下作品。它只需要在纯 CSS 中设置一次。它比 JS 函数更可靠。性能似乎不受影响。

@-webkit-keyframes androidBugfix {from { padding: 0; } to { padding: 0; }}
body { -webkit-animation: androidBugfix infinite 1s; }

回答by sowasred2012

For some reason I couldn't get danorton's answer to work, I could see what it was supposed to do so I tweaked it a little bit to this:

出于某种原因,我无法得到 danorton 的答案,我可以看到它应该做什么,所以我对它进行了一些调整:

$('#foo').css('display', 'none').height();
$('#foo').css('display', 'block');

and it worked for me.

它对我有用。

回答by António Almeida

I came up here because I needed to redraw scrollbars in Chrome after changing its css.

我来到这里是因为我需要在更改 css 后在 Chrome 中重新绘制滚动条。

If someone's having the same problem, I solved it by calling this function:

如果有人遇到同样的问题,我通过调用这个函数来解决它:

//Hack to force scroll redraw
function scrollReDraw() {
    $('body').css('overflow', 'hidden').height();
    $('body').css('overflow', 'auto');
}

This method is not the best solution, but it may work with everything, hiding and showing the element that needs to be redraw may solve every problem.

这种方法不是最好的解决方案,但它可能适用于所有情况,隐藏和显示需要重绘的元素可能会解决所有问题。

Here is the fiddle where I used it: http://jsfiddle.net/promatik/wZwJz/18/

这是我使用它的小提琴:http: //jsfiddle.net/promatik/wZwJz/18/

回答by Adam Eberlin

I stumbled upon this today: Element.redraw() for prototype.js

我今天偶然发现了这个:prototype.js 的 Element.redraw()

Using:

使用:

Element.addMethods({
  redraw: function(element){
    element = $(element);
    var n = document.createTextNode(' ');
    element.appendChild(n);
    (function(){n.parentNode.removeChild(n)}).defer();
    return element;
  }
});

However, I've noticed sometimes that you must call redraw() on the problematic element directly. Sometimes redrawing the parent element won't solve the problem the child is experiencing.

但是,我注意到有时您必须直接在有问题的元素上调用 redraw()。有时重绘父元素并不能解决子元素遇到的问题。

Good article about the way browsers render elements: Rendering: repaint, reflow/relayout, restyle

关于浏览器渲染元素方式的好文章:渲染:重绘、回流/重新布局、重新设计

回答by JustGoscha

I had this problem with a a number of divs that were inserted in another div with position: absolute, the inserted divs had no position attribute. When I changed this to position:relativeit worked fine. (was really hard to pinpoint the problem)

我在插入另一个 div 的多个 div 时遇到了这个问题position: absolute,插入的 div 没有位置属性。当我将position:relative其更改为它时,它工作正常。(真的很难找出问题所在)

In my case the elements where inserted by Angular with ng-repeat.

在我的情况下,元素是由 Angular 插入的ng-repeat