检测并修复固定的绝对错误

时间:2016-09-19 21:31:01

标签: javascript html css

对于一个小项目,我在Firefox中遇到一种行为(包括移动和桌面),我认为这是一个错误:使用chrome我没有错误,检查html触发器重新绘制并解决问题。

为了实现响应式设计,我有一个绝对定位的侧面板,可以滑入和滑出。在这个侧面板中,我愿意有一个固定的元素。固定位置仅指定底部,因此固定元件应与包含面板侧向平移。然而,在firefox中,位置没有正确更新,并且固定元素不会后期翻译。搜索,我提出了一个hacky解决方法,但这个修复并不完美,并引入了其他浏览器没有的小错误。因此,我还设计了一个测试,以检查浏览器是否遇到错误,以便我只在必要时使用hack。这是从我的代码派生的最小示例。

/* Fix to programatically force fixed element repositionning */
var trigger = document.getElementById('trigger');
var container = document.getElementById('container');
var child = document.getElementById('child');

function from_and_back(evt) {
  if (container.children.length) {
    container.removeChild(child);
    setTimeout(function() {
      container.appendChild(child);
    }, 300);
  }
}
trigger.addEventListener('mouseenter', from_and_back);
trigger.addEventListener('mouseleave', from_and_back);

/* Simulate the bug to check whether the browser experiences it */
var bug_status = document.getElementById('bug-status');
bug_status.innerText = (function() {
  //create an absolutely positionned element
  var abs = document.createElement('div');
  abs.style.position = 'relative';
  abs.style.left = '0px';

  //create a fixed element to put inside
  var fix = document.createElement('div');
  fix.style.position = 'fixed';

  //insert it into the document
  abs.appendChild(fix);
  document.body.appendChild(abs);

  //test
  fix.getBoundingClientRect(); /************ this line *************/
  abs.style.left = '20px';
  var fix_left = fix.getBoundingClientRect().left;
  var abs_left = abs.getBoundingClientRect().left;

  //remove test elements from the document
  document.body.removeChild(abs);

  //send the result
  return abs_left !== fix_left;
})();
/* Wrapper class to trigger the effect */

.trigger {
  width: 220px;
  border: 1px solid #000;
  display: inline-block;
}
.trigger:hover .container {
  left: 200px;
}
/* Absolutely positionned element */

.container {
  position: relative;
  width: 20px;
  height: 20px;
  left: 0px;
  background: #aaa;
  transition: all .25s ease-out;
}
/* Fixed element inside the absolute one */

.child {
  position: fixed;
  width: 20px;
  height: 20px;
  background: #aaa;
  top: 100px;
}
<!-- Display the bug test result -->
Your browser has the bug : <span id='bug-status'></span>
<br/>
<br/>
<div class="trigger">
  <!-- Demonstrate the error without any fix -->
  <span>Reference</span>
  <br/>
  <div class="container">
    <div class="child"></div>
  </div>
</div>
</div>
<!-- Apply the fix fix -->
<div class="trigger" id="trigger">
  <span>Fixed</span>
  <br/>
  <div class="container" id="container">
    <div class="child" id="child"></div>
  </div>
</div>

现在问题:

  1. 显然我的解决方法并不完全令人满意:平滑过渡失去了,在示例中,如果鼠标快速移入和移出触发器,固定元素将保持悬空在中间。您是否有更好的解决方法的想法,或没有错误的相同行为设计?

  2. 在javascript测试中,我标记了一行。删除该行会使测试通过Firefox。我不明白为什么,但也许这可以用来粗略地解决这个问题?

1 个答案:

答案 0 :(得分:1)

可能提供相同结果的解决方法是将.child移到移动容器之外,并在触发器上应用相同的转换:悬停,只使用margin-left甚至{{1}不要搞乱固定的定位。

(使用transform: translateX(200px)而不是在容器上定位实际上会解决渲染问题,但遗憾的是它也会使位置:相对于转换后的元素而不是视口固定。)

transform
/* Wrapper class to trigger the effect */

.trigger {
  width: 220px;
  border: 1px solid #000;
  display: inline-block;
}
.trigger:hover .container {
  left: 200px;
}
.trigger:hover .child {
  margin-left: 200px;
}

.container {
  position: relative;
  width: 20px;
  height: 20px;
  left: 0px;
  background: #aaa;
  transition: all .25s ease-out;
}

.child {
  position: fixed;
  width: 20px;
  height: 20px;
  background: #aaa;
  top: 100px;
  margin-left: 0;
  transition: all .25s ease-out;
}