Skip to content

Commit 85b6213

Browse files
Fix layout shift - The REAL root cause (remove all scroll-blocking)
Based on AI debugging analysis, the issue was NOT JavaScript scroll: - NO scroll events were triggered - NO JavaScript scroll calls happened - NO autofocus was causing scroll THE REAL ISSUE: CSS Layout Shift What happens: 1. library.js:140 opens modal with view.open() 2. WordPress focuses modal container immediately 3. Modal iframe loads Types.php content 4. Content renders with "Create Chart from Image" at top 5. BUT viewport has already anchored to visible content 6. Result: Appears scrolled to "Select Library" section THE FIX: Removed: - 51 lines of useless scroll-blocking JavaScript - API overrides for window.scrollTo - Element.prototype.scrollTop overrides - All the "nuclear option" code that didn't work Added: - Simple CSS to prevent layout shift - scroll-behavior: auto (disable smooth scroll) - min-height: 100vh on #type-picker - Simple scroll-to-top on DOMContentLoaded and load events This addresses the ACTUAL problem: ensuring viewport stays at top when iframe content finishes rendering, not blocking non-existent scrolls. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 20ff363 commit 85b6213

1 file changed

Lines changed: 21 additions & 53 deletions

File tree

classes/Visualizer/Render/Page/Types.php

Lines changed: 21 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,25 @@ protected function _toHTML() {
5252
* @access protected
5353
*/
5454
protected function _renderContent() {
55+
// CSS to prevent layout shift - ensure page starts at top
56+
echo '<style>';
57+
echo 'html { scroll-behavior: auto !important; }';
58+
echo 'body { overflow-x: hidden; }';
59+
echo '#type-picker { min-height: 100vh; }';
60+
echo '</style>';
61+
62+
// Script to scroll to top AFTER content fully loads (fixes CSS layout shift)
63+
echo '<script>';
64+
echo 'document.addEventListener("DOMContentLoaded", function() {';
65+
echo ' window.scrollTo(0, 0);';
66+
echo ' document.documentElement.scrollTop = 0;';
67+
echo ' document.body.scrollTop = 0;';
68+
echo '});';
69+
echo 'window.addEventListener("load", function() {';
70+
echo ' window.scrollTo(0, 0);';
71+
echo '});';
72+
echo '</script>';
73+
5574
echo '<div id="type-picker">';
5675

5776
// AI Image Upload Section
@@ -169,57 +188,6 @@ protected function _renderContent() {
169188
echo '</div>';
170189
}
171190
echo '</div>';
172-
173-
// NUCLEAR OPTION: Block ALL scroll attempts at the API level
174-
echo '<script type="text/javascript">';
175-
echo '(function() {';
176-
echo ' var scrollBlocked = true;';
177-
echo ' var originalScrollTo = window.scrollTo;';
178-
echo ' var originalScroll = window.scroll;';
179-
echo ' var savedScrollTop = {};';
180-
echo ' ';
181-
echo ' console.log("[Visualizer] Scroll blocker activated");';
182-
echo ' ';
183-
echo ' // Block window.scrollTo and window.scroll completely';
184-
echo ' window.scrollTo = window.scroll = function() {';
185-
echo ' if (scrollBlocked) {';
186-
echo ' console.log("[Visualizer] Blocked scroll attempt via window.scrollTo/scroll");';
187-
echo ' return;';
188-
echo ' }';
189-
echo ' return originalScrollTo.apply(this, arguments);';
190-
echo ' };';
191-
echo ' ';
192-
echo ' // Save original scrollTop descriptors';
193-
echo ' var htmlDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, "scrollTop");';
194-
echo ' ';
195-
echo ' // Override scrollTop setter globally on Element.prototype';
196-
echo ' if (htmlDescriptor && htmlDescriptor.set) {';
197-
echo ' Object.defineProperty(Element.prototype, "scrollTop", {';
198-
echo ' get: function() {';
199-
echo ' return htmlDescriptor.get.call(this);';
200-
echo ' },';
201-
echo ' set: function(value) {';
202-
echo ' if (scrollBlocked && value > 0) {';
203-
echo ' console.log("[Visualizer] Blocked scrollTop set to", value);';
204-
echo ' return;';
205-
echo ' }';
206-
echo ' htmlDescriptor.set.call(this, value);';
207-
echo ' }';
208-
echo ' });';
209-
echo ' }';
210-
echo ' ';
211-
echo ' // Unblock after WordPress scripts finish loading';
212-
echo ' setTimeout(function() {';
213-
echo ' scrollBlocked = false;';
214-
echo ' window.scrollTo = originalScrollTo;';
215-
echo ' window.scroll = originalScroll;';
216-
echo ' if (htmlDescriptor) {';
217-
echo ' Object.defineProperty(Element.prototype, "scrollTop", htmlDescriptor);';
218-
echo ' }';
219-
echo ' console.log("[Visualizer] Scroll blocker deactivated");';
220-
echo ' }, 3000);';
221-
echo '})();';
222-
echo '</script>';
223191
}
224192

225193
/**
@@ -262,8 +230,8 @@ private function render_chart_selection() {
262230

263231
$select = '';
264232
if ( ! empty( $libraries ) ) {
265-
$select .= '<label>' . __( 'Select Library for charts', 'visualizer' ) . '</label>';
266-
$select .= '<select name="chart-library" class="viz-select-library" data-type-vs-library="' . esc_attr( json_encode( $type_vs_library ) ) . '" tabindex="-1">';
233+
$select .= '<label for="chart-library">' . __( 'Select Library for charts', 'visualizer' ) . '</label>';
234+
$select .= '<select name="chart-library" class="viz-select-library" data-type-vs-library="' . esc_attr( json_encode( $type_vs_library ) ) . '">';
267235
foreach ( $libraries as $library ) {
268236
$select .= '<option value="' . $this->_removeSpaceFromLibrary( $library ) . '">' . $library . '</option>';
269237
}

0 commit comments

Comments
 (0)