Loading core/modules/toolbar/js/toolbar.anti-flicker.js 0 → 100644 +72 −0 Original line number Diff line number Diff line /** * @file * Prevents flicker of the toolbar on page load. */ (() => { const toolbarState = sessionStorage.getItem('Drupal.toolbar.toolbarState') ? JSON.parse(sessionStorage.getItem('Drupal.toolbar.toolbarState')) : false; // These are classes that toolbar typically adds to <body>, but this code // executes before the first paint, when <body> is not yet present. The // classes are added to <html> so styling immediately reflects the current // toolbar state. The classes are removed after the toolbar completes // initialization. const classesToAdd = ['toolbar-loading', 'toolbar-anti-flicker']; if (toolbarState) { const { orientation, hasActiveTab, isFixed, activeTray, activeTabId, isOriented, userButtonMinWidth, } = toolbarState; classesToAdd.push( orientation ? `toolbar-${orientation}` : 'toolbar-horizontal', ); if (hasActiveTab !== false) { classesToAdd.push('toolbar-tray-open'); } if (isFixed) { classesToAdd.push('toolbar-fixed'); } if (isOriented) { classesToAdd.push('toolbar-oriented'); } if (activeTray) { // These styles are added so the active tab/tray styles are present // immediately instead of "flickering" on as the toolbar initializes. In // instances where a tray is lazy loaded, these styles facilitate the // lazy loaded tray appearing gracefully and without reflow. const styleContent = ` .toolbar-loading #${activeTabId} { background-image: linear-gradient(rgba(255, 255, 255, 0.25) 20%, transparent 200%); } .toolbar-loading #${activeTabId}-tray { display: block; box-shadow: -1px 0 5px 2px rgb(0 0 0 / 33%); border-right: 1px solid #aaa; background-color: #f5f5f5; z-index: 0; } .toolbar-loading.toolbar-vertical.toolbar-tray-open #${activeTabId}-tray { width: 15rem; height: 100vh; } .toolbar-loading.toolbar-horizontal :not(#${activeTray}) > .toolbar-lining {opacity: 0}`; const style = document.createElement('style'); style.textContent = styleContent; style.setAttribute('data-toolbar-anti-flicker-loading', true); document.querySelector('head').appendChild(style); if (userButtonMinWidth) { const userButtonStyle = document.createElement('style'); userButtonStyle.textContent = ` #toolbar-item-user {min-width: ${userButtonMinWidth}.px;}`; document.querySelector('head').appendChild(userButtonStyle); } } } document.querySelector('html').classList.add(...classesToAdd); })(); core/modules/toolbar/toolbar.libraries.yml +7 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ toolbar: - core/once - core/drupal.displace - toolbar/toolbar.menu - toolbar/toolbar.anti-flicker toolbar.menu: version: VERSION Loading @@ -50,3 +51,9 @@ toolbar.escapeAdmin: - core/drupal - core/drupalSettings - core/once toolbar.anti-flicker: # Block the page from being loaded until anti-flicker is initialized. version: VERSION header: true js: js/toolbar.anti-flicker.js: {} core/modules/toolbar/toolbar.module +0 −96 Original line number Diff line number Diff line Loading @@ -7,7 +7,6 @@ use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Render\Element; use Drupal\Core\Render\Markup; use Drupal\Core\Render\RenderContext; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Template\Attribute; Loading Loading @@ -49,101 +48,6 @@ function toolbar_theme($existing, $type, $theme, $path) { return $items; } /** * Implements hook_page_attachments(). */ function toolbar_page_attachments(array &$page) { // This JavaScript code provides temporary styles while the toolbar loads, so // it better visually resembles the appearance it will have once fully loaded. // @todo investigate potential alternatives to this approach in // https://www.drupal.org/i/3355381 $anti_flicker_js = <<<JS (function() { const toolbarState = sessionStorage.getItem('Drupal.toolbar.toolbarState') ? JSON.parse(sessionStorage.getItem('Drupal.toolbar.toolbarState')) : false; // These are classes that toolbar typically adds to <body>, but this code // executes before the first paint, when <body> is not yet present. The // classes are added to <html> so styling immediately reflects the current // toolbar state. The classes are removed after the toolbar completes // initialization. const classesToAdd = ['toolbar-loading', 'toolbar-anti-flicker']; if (toolbarState) { const { orientation, hasActiveTab, isFixed, activeTray, activeTabId, isOriented, userButtonMinWidth } = toolbarState; classesToAdd.push( orientation ? `toolbar-` + orientation + `` : 'toolbar-horizontal', ); if (hasActiveTab !== false) { classesToAdd.push('toolbar-tray-open'); } if (isFixed) { classesToAdd.push('toolbar-fixed'); } if (isOriented) { classesToAdd.push('toolbar-oriented'); } if (activeTray) { // These styles are added so the active tab/tray styles are present // immediately instead of "flickering" on as the toolbar initializes. In // instances where a tray is lazy loaded, these styles facilitate the // lazy loaded tray appearing gracefully and without reflow. const styleContent = ` .toolbar-loading #` + activeTabId + ` { background-image: linear-gradient(rgba(255, 255, 255, 0.25) 20%, transparent 200%); } .toolbar-loading #` + activeTabId + `-tray { display: block; box-shadow: -1px 0 5px 2px rgb(0 0 0 / 33%); border-right: 1px solid #aaa; background-color: #f5f5f5; z-index: 0; } .toolbar-loading.toolbar-vertical.toolbar-tray-open #` + activeTabId + `-tray { width: 15rem; height: 100vh; } .toolbar-loading.toolbar-horizontal :not(#` + activeTray + `) > .toolbar-lining {opacity: 0}`; const style = document.createElement('style'); style.textContent = styleContent; style.setAttribute('data-toolbar-anti-flicker-loading', true); document.querySelector('head').appendChild(style); if (userButtonMinWidth) { const userButtonStyle = document.createElement('style'); userButtonStyle.textContent = `#toolbar-item-user {min-width: ` + userButtonMinWidth +`px;}` document.querySelector('head').appendChild(userButtonStyle); } } } document.querySelector('html').classList.add(...classesToAdd); })(); JS; // The anti flicker javascript is added as an inline tag so it is executed // as early as possible. This enables it to add classes that prevent // flickering before the first paint. $page['#attached']['html_head'][] = [ [ '#tag' => 'script', '#attributes' => [ 'type' => 'text/javascript', 'data-toolbar-anti-flicker-loading' => TRUE, ], // Process through Markup to prevent character escaping. '#value' => Markup::create($anti_flicker_js), ], 'anti_flicker_js', ]; } /** * Implements hook_page_top(). * Loading core/profiles/demo_umami/tests/src/FunctionalJavascript/PerformanceTest.php +1 −1 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ public function testFrontPagePerformance(): void { $this->drupalGet('<front>'); $this->assertSession()->pageTextContains('Umami'); $this->assertSame(2, $this->stylesheetCount); $this->assertSame(1, $this->scriptCount); $this->assertSame(2, $this->scriptCount); } } Loading
core/modules/toolbar/js/toolbar.anti-flicker.js 0 → 100644 +72 −0 Original line number Diff line number Diff line /** * @file * Prevents flicker of the toolbar on page load. */ (() => { const toolbarState = sessionStorage.getItem('Drupal.toolbar.toolbarState') ? JSON.parse(sessionStorage.getItem('Drupal.toolbar.toolbarState')) : false; // These are classes that toolbar typically adds to <body>, but this code // executes before the first paint, when <body> is not yet present. The // classes are added to <html> so styling immediately reflects the current // toolbar state. The classes are removed after the toolbar completes // initialization. const classesToAdd = ['toolbar-loading', 'toolbar-anti-flicker']; if (toolbarState) { const { orientation, hasActiveTab, isFixed, activeTray, activeTabId, isOriented, userButtonMinWidth, } = toolbarState; classesToAdd.push( orientation ? `toolbar-${orientation}` : 'toolbar-horizontal', ); if (hasActiveTab !== false) { classesToAdd.push('toolbar-tray-open'); } if (isFixed) { classesToAdd.push('toolbar-fixed'); } if (isOriented) { classesToAdd.push('toolbar-oriented'); } if (activeTray) { // These styles are added so the active tab/tray styles are present // immediately instead of "flickering" on as the toolbar initializes. In // instances where a tray is lazy loaded, these styles facilitate the // lazy loaded tray appearing gracefully and without reflow. const styleContent = ` .toolbar-loading #${activeTabId} { background-image: linear-gradient(rgba(255, 255, 255, 0.25) 20%, transparent 200%); } .toolbar-loading #${activeTabId}-tray { display: block; box-shadow: -1px 0 5px 2px rgb(0 0 0 / 33%); border-right: 1px solid #aaa; background-color: #f5f5f5; z-index: 0; } .toolbar-loading.toolbar-vertical.toolbar-tray-open #${activeTabId}-tray { width: 15rem; height: 100vh; } .toolbar-loading.toolbar-horizontal :not(#${activeTray}) > .toolbar-lining {opacity: 0}`; const style = document.createElement('style'); style.textContent = styleContent; style.setAttribute('data-toolbar-anti-flicker-loading', true); document.querySelector('head').appendChild(style); if (userButtonMinWidth) { const userButtonStyle = document.createElement('style'); userButtonStyle.textContent = ` #toolbar-item-user {min-width: ${userButtonMinWidth}.px;}`; document.querySelector('head').appendChild(userButtonStyle); } } } document.querySelector('html').classList.add(...classesToAdd); })();
core/modules/toolbar/toolbar.libraries.yml +7 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ toolbar: - core/once - core/drupal.displace - toolbar/toolbar.menu - toolbar/toolbar.anti-flicker toolbar.menu: version: VERSION Loading @@ -50,3 +51,9 @@ toolbar.escapeAdmin: - core/drupal - core/drupalSettings - core/once toolbar.anti-flicker: # Block the page from being loaded until anti-flicker is initialized. version: VERSION header: true js: js/toolbar.anti-flicker.js: {}
core/modules/toolbar/toolbar.module +0 −96 Original line number Diff line number Diff line Loading @@ -7,7 +7,6 @@ use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Render\Element; use Drupal\Core\Render\Markup; use Drupal\Core\Render\RenderContext; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Template\Attribute; Loading Loading @@ -49,101 +48,6 @@ function toolbar_theme($existing, $type, $theme, $path) { return $items; } /** * Implements hook_page_attachments(). */ function toolbar_page_attachments(array &$page) { // This JavaScript code provides temporary styles while the toolbar loads, so // it better visually resembles the appearance it will have once fully loaded. // @todo investigate potential alternatives to this approach in // https://www.drupal.org/i/3355381 $anti_flicker_js = <<<JS (function() { const toolbarState = sessionStorage.getItem('Drupal.toolbar.toolbarState') ? JSON.parse(sessionStorage.getItem('Drupal.toolbar.toolbarState')) : false; // These are classes that toolbar typically adds to <body>, but this code // executes before the first paint, when <body> is not yet present. The // classes are added to <html> so styling immediately reflects the current // toolbar state. The classes are removed after the toolbar completes // initialization. const classesToAdd = ['toolbar-loading', 'toolbar-anti-flicker']; if (toolbarState) { const { orientation, hasActiveTab, isFixed, activeTray, activeTabId, isOriented, userButtonMinWidth } = toolbarState; classesToAdd.push( orientation ? `toolbar-` + orientation + `` : 'toolbar-horizontal', ); if (hasActiveTab !== false) { classesToAdd.push('toolbar-tray-open'); } if (isFixed) { classesToAdd.push('toolbar-fixed'); } if (isOriented) { classesToAdd.push('toolbar-oriented'); } if (activeTray) { // These styles are added so the active tab/tray styles are present // immediately instead of "flickering" on as the toolbar initializes. In // instances where a tray is lazy loaded, these styles facilitate the // lazy loaded tray appearing gracefully and without reflow. const styleContent = ` .toolbar-loading #` + activeTabId + ` { background-image: linear-gradient(rgba(255, 255, 255, 0.25) 20%, transparent 200%); } .toolbar-loading #` + activeTabId + `-tray { display: block; box-shadow: -1px 0 5px 2px rgb(0 0 0 / 33%); border-right: 1px solid #aaa; background-color: #f5f5f5; z-index: 0; } .toolbar-loading.toolbar-vertical.toolbar-tray-open #` + activeTabId + `-tray { width: 15rem; height: 100vh; } .toolbar-loading.toolbar-horizontal :not(#` + activeTray + `) > .toolbar-lining {opacity: 0}`; const style = document.createElement('style'); style.textContent = styleContent; style.setAttribute('data-toolbar-anti-flicker-loading', true); document.querySelector('head').appendChild(style); if (userButtonMinWidth) { const userButtonStyle = document.createElement('style'); userButtonStyle.textContent = `#toolbar-item-user {min-width: ` + userButtonMinWidth +`px;}` document.querySelector('head').appendChild(userButtonStyle); } } } document.querySelector('html').classList.add(...classesToAdd); })(); JS; // The anti flicker javascript is added as an inline tag so it is executed // as early as possible. This enables it to add classes that prevent // flickering before the first paint. $page['#attached']['html_head'][] = [ [ '#tag' => 'script', '#attributes' => [ 'type' => 'text/javascript', 'data-toolbar-anti-flicker-loading' => TRUE, ], // Process through Markup to prevent character escaping. '#value' => Markup::create($anti_flicker_js), ], 'anti_flicker_js', ]; } /** * Implements hook_page_top(). * Loading
core/profiles/demo_umami/tests/src/FunctionalJavascript/PerformanceTest.php +1 −1 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ public function testFrontPagePerformance(): void { $this->drupalGet('<front>'); $this->assertSession()->pageTextContains('Umami'); $this->assertSame(2, $this->stylesheetCount); $this->assertSame(1, $this->scriptCount); $this->assertSame(2, $this->scriptCount); } }