为啥 iframe 的 CSS 边框会闪烁以及如何修复它?

Posted

技术标签:

【中文标题】为啥 iframe 的 CSS 边框会闪烁以及如何修复它?【英文标题】:Why does the CSS border of an iframe flicker and how to fix it?为什么 iframe 的 CSS 边框会闪烁以及如何修复它? 【发布时间】:2018-02-23 07:29:00 【问题描述】:

我有一个使用 CSS 的 iframe 边框。当页面调整大小时,边框有时会在 Chrome 中消失并在 Safari 中改变大小(在 Firefox 中很好)

有已知的解决方法吗?

const html = `
<style>
body  
  background: #DDD;

</style>
<body>
  <div>hello iframe</div>
</body>
`;

const blob = new Blob([html], type: 'text/html');
document.querySelector("iframe").src = URL.createObjectURL(blob);
div 
  max-width: 90%;
  margin: 0 auto;

iframe 
  display: block;
  border: 1px solid black;
  width: 100%;
  background: red;
<p>Size the window and watch the right border</p>
<!-- src set from javascript because offsite iframes are often banned -->
<div>
  <iframe></iframe>
</div>

使用其他元素没有同样的问题

div 
  max-width: 90%;
  margin: 1em auto;

span, canvas 
  display: block;
  border: 1px solid black;
  width: 100%;
  height: 60px;
  background: #eee;
<p>no issue with other elements</p>
<div>
  <span></span>
</div>
<div>
  <canvas></canvas>
</div>

请注意,它似乎与 iframe 中的背景颜色有关。如果我删除背景颜色,Chrome 中的问题就会消失(虽然不是 Safari)

const html = `
<body>
  <div>hello iframe</div>
</body>
`;

const blob = new Blob([html], type: 'text/html');
document.querySelector("iframe").src = URL.createObjectURL(blob);
div 
  max-width: 90%;
  margin: 0 auto;

iframe 
  display: block;
  border: 1px solid black;
  width: 100%;
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
  <iframe></iframe>
</div>

【问题讨论】:

提交了bug。仍在寻找解决方法 【参考方案1】:

使用overflow: hidden;box-sizing: border-box; 添加包装器 div 对我有用。

const html = `
<style>
body  
  background: #eee;

</style>
<body>
  <div>hello iframe</div>
</body>
`;

const blob = new Blob([html], type: 'text/html');
document.querySelector("iframe").src = URL.createObjectURL(blob);
div 
  max-width: 90%;
  margin: 0 auto;

.iframe-wrapper 
  border: 1px solid black;
  box-sizing: border-box;
  width: 100%;
  overflow: hidden;

iframe 
  display: block;
  width: 100%;
  border: none;
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
  <div class="iframe-wrapper">
     <iframe></iframe>
  </div>
</div>

【讨论】:

如果我将 iframe 的背景设置为红色,并将 iframe 的内容主体设置为灰色,您会发现这不太有效。 imgur.com/a/sM9uvdc【参考方案2】:

我仍然在 Chrome 上看到这个问题(不是在 Safari 上)。这似乎是边界可视化中的一个错误(仍然)。

一种选择可能是将border 更改为宽度为0,并改为设置outline。然后这个效果就消失了。我不知道这是否是最好的解决方案(轮廓经常用于突出重点/活跃元素),但它会接近你所拥有的。

这是一个演示,只是进行了更改:

const html = `
<style>
body  
  background: #eee;

</style>
<body>
  <div>hello iframe</div>
</body>
`;

const blob = new Blob([html], type: 'text/html');
document.querySelector("iframe").src = URL.createObjectURL(blob);
div 
  max-width: 90%;
  margin: 0 auto;

iframe 
  display: block;
  border: 0;
  outline: 1px solid black;
  width: 100%;
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
  <iframe></iframe>
</div>

【讨论】:

谢谢,但这对我不起作用。 outline 有同样的问题。 imgur.com/a/sM9uvdc 虽然我看到它适用于我上面发布的代码。我想知道与我的实际位置有什么不同。 另外,如果我将 iframe 的背景设置为红色并将 iframe 的内容主体设置为灰色,您会发现这不太有效。 imgur.com/a/sM9uvdc【参考方案3】:

这是一个抗锯齿问题。 Chrome 通常会避免在浮动像素上渲染,以避免抗锯齿。它将尝试移动并调整到下一个圆形像素。 在这种情况下,它将切断您的边框,而不是使其泄漏到 iframe 之外。

您可以通过浮动像素移动或调整 iframe 的大小来强制它:

const html = `
<style>
body  
  background: #DDD;

</style>
<body>
  <div>hello iframe</div>
</body>
`;
const iframe = document.querySelector("iframe");
iframe.srcdoc = html;

document.querySelector("input").oninput = function(e) 
  iframe.style.marginLeft = this.value + 'px';
;
div 
  max-width: 90%;
  margin: 0 auto;

iframe 
  display: block;
  border: 1px solid black;
  width: 250.5px; /* force a floating pixel width */
  background: red;
<p>Edit the range and watch the right border</p>
<input type="range" min="0" max="1" value="0" step="0.01">
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
  <iframe></iframe>
</div>

我认为您在打开这个问题时做得很好,因为这绝对不是预期的行为。

由于您要求解决方法,这里有一个,远非完美,它会在每次调整大小事件时导致双重回流,但应该可以修复错误...

const html = `
<style>
body  
  background: #DDD;

</style>
<body>
  <div>hello iframe</div>
</body>
`;
const iframe = document.querySelector("iframe");
iframe.srcdoc = html;

addEventListener('resize', resizeFrame, passive: true);
resizeFrame();

function resizeFrame(_)
  iframe.style.width = null; // reset to 100%
  // force reflow by calling offsetWidth which is already rounded
  iframe.style.width = iframe.offsetWidth + 'px'; 
div 
  max-width: 90%;
  margin: 0 auto;

iframe 
  display: block;
  border: 1px solid black;
  width: 100%;
  background: red;
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
  <iframe></iframe>
</div>

但请注意,此代码仅处理调整大小事件,如果您的 iframe 可以根据其他事件(例如 DOM 操作、CSS 等)调整大小,那么您可能希望使用一个包装器元素,在其上应用 @987654328 @ 并从 ResizeObserver 的回调中更改 iframe 的宽度:

const html = `
<style>
body  
  background: #DDD;

</style>
<body>
  <div>hello iframe</div>
</body>
`;
const iframe = document.querySelector("iframe");
iframe.srcdoc = html;

if(window.ResizeObserver) 
  const observer = new ResizeObserver(entries => 
    iframe.style.width = iframe.parentNode.offsetWidth + 'px';
  );
  observer.observe(iframe.parentNode);

else 
  console.log('no support');
div 
  max-width: 90%;
  margin: 0 auto;

iframe 
  display: block;
  border: 1px solid black;
  width: 100%;
  background: red;

.iframe-wrapper 
  max-width: none;
  width: 100%;
<p>Size the window and watch the right border</p>
<!-- src set from JavaScript because offsite iframes are often banned -->
<div>
<div class="iframe-wrapper">
  <iframe></iframe>
</div>
</div>

即in Blink only for now...

【讨论】:

【参考方案4】:

.ifrmoutr
  border: 1px solid red;
  width:100%;
  overflow:hidden;

.ifrmoutr iframe
  width:100%;
<div class="row">
  <div class="col-lg-12">
    <div class="ifrmoutr">
      <iframe></iframe>
    </div>
  </div>
  </div>

【讨论】:

以上是关于为啥 iframe 的 CSS 边框会闪烁以及如何修复它?的主要内容,如果未能解决你的问题,请参考以下文章

jquery下拉菜单瞬间闪烁

如何在 iframe 周围创建边框?

带有pdf黑色闪烁的iframe(闪烁)

为啥 CSS 转换翻译会将表格行的边框留在原来的位置?

为啥当鼠标悬停后出现边框时 <div> 的大小会增加? CSS [重复]

带有闪烁边框的表格单元格