| <!DOCTYPE html> |
| <head> |
| <style> |
| #testInner { |
| position: absolute; |
| width: 600px; |
| top: 400px; |
| left: 200px;; |
| padding: 1em; |
| background: yellow; |
| box-shadow: 0 0 0.5em gray; |
| } |
| |
| .marker { |
| position: fixed; |
| background: black; |
| color: white; |
| top: 200px; |
| padding: 1em; |
| } |
| |
| .spacer { |
| height: 200px; |
| } |
| |
| button { |
| position: fixed; |
| top: 100px; |
| left: 200px; |
| padding: 2em; |
| font-size: 16px; |
| font-weight: bold; |
| } |
| |
| .trigger #testInner { |
| -webkit-transform: translateY(-200px); |
| } |
| </style> |
| </head> |
| <body> |
| <button onclick="toggleRunning()"> |
| CLICK ME to start / stop test |
| </button> |
| <div class="marker">Correct top position</div> |
| <div id="parent" class="trigger"> |
| <div id="testInner">test element</div> |
| </div> |
| <p class="spacer">.</p> |
| <p class="spacer">.</p> |
| <p class="spacer">.</p> |
| <p class="spacer">.</p> |
| <p class="spacer">.</p> |
| <p class="spacer">.</p> |
| <p class="spacer" id="last">.</p> |
| |
| <script> |
| var INTERVAL_MS = 17; |
| var testElement = document.getElementById('testInner'); |
| var testContainerElement = document.getElementById('parent'); |
| |
| var state = {}; |
| state.triggerTranslationOnOrOff = false; |
| state.running = false; |
| state.intervalId = 0; |
| |
| function updateState() |
| { |
| var translated = testContainerElement.classList.contains('trigger'); |
| state.scrolled = !translated; |
| } |
| |
| function toggleRunning() |
| { |
| state.running = !state.running; |
| if (state.running) { |
| updateState(); |
| state.intervalId = setInterval(runSequence, INTERVAL_MS); |
| } else { |
| clearInterval(state.intervalId); |
| } |
| } |
| |
| function doExpensiveContentUpdate() |
| { |
| var content = 'I should be stable at the correct position and not flicker above/below'; |
| if (state.scrolled) |
| content += '.'; |
| |
| testElement.innerHTML = content; |
| |
| var lastElement = document.getElementById('last'); |
| var startTime = Date.now(); |
| for (var i = 0; i < 1000; i++) { |
| lastElement.innerHTML = (lastElement.innerHTML + '.'); |
| } |
| var domWriteTimeMs = Date.now() - startTime; |
| if (domWriteTimeMs > 2 * INTERVAL_MS) |
| lastElement.innerHTML = ''; |
| } |
| |
| function runSequence() |
| { |
| doExpensiveContentUpdate(); |
| |
| var newScrollTop; |
| if (state.scrolled) { |
| testContainerElement.classList.add('trigger'); |
| newScrollTop = 0; |
| } else { |
| testContainerElement.classList.remove('trigger'); |
| newScrollTop = 200; |
| } |
| |
| document.body.scrollTop = newScrollTop; |
| state.scrolled = !state.scrolled; |
| } |
| |
| </script> |
| </body> |
| |