From 6a383da7552a330ec85456ca2fb7ec77e3eaa92c Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:52:40 +1300 Subject: [PATCH 01/12] Leave the sidebar positioned absolute until the page is scrolled --- .../blocks/sidebar-container/postcss/style.pcss | 1 + mu-plugins/blocks/sidebar-container/src/view.js | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/mu-plugins/blocks/sidebar-container/postcss/style.pcss b/mu-plugins/blocks/sidebar-container/postcss/style.pcss index cb5ecf41e..29e746626 100644 --- a/mu-plugins/blocks/sidebar-container/postcss/style.pcss +++ b/mu-plugins/blocks/sidebar-container/postcss/style.pcss @@ -25,6 +25,7 @@ &.is-fixed-sidebar { position: fixed; + top: 0; } &.is-bottom-sidebar { diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index b5701ede0..6d10ea911 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -1,7 +1,8 @@ /** * This is the calculated value of the admin bar + header height + local nav bar. */ -const FIXED_HEADER_HEIGHT = 179; +const localNavHeight = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ); +const FIXED_HEADER_HEIGHT = 32 + 90 + localNavHeight; /** * Get the value of a CSS custom property. @@ -27,12 +28,11 @@ function getCustomPropValue( name, element = document.body ) { * @return {boolean} True if the sidebar is at the bottom of the page. */ function onScroll() { - // Only run the scroll code if the sidebar is fixed. + // Only run the scroll code if the sidebar is floating. const sidebarContainer = document.querySelector( '.wp-block-wporg-sidebar-container' ); - if ( ! sidebarContainer || ! sidebarContainer.classList.contains( 'is-fixed-sidebar' ) ) { + if ( ! sidebarContainer || ! window.matchMedia( '(min-width: 1200px)' ).matches ) { return; } - const mainEl = document.getElementById( 'wp--skip-link--target' ); const footerStart = mainEl.offsetTop + mainEl.offsetHeight; @@ -61,11 +61,15 @@ function onScroll() { ); return true; } - } else if ( footerStart - sidebarContainer.offsetHeight - FIXED_HEADER_HEIGHT - gap * 2 > scrollPosition ) { + } else if ( footerStart - sidebarContainer.offsetHeight - gap * 2 > scrollPosition ) { // If the scroll position is higher than the top of the sidebar, switch back to just a fixed sidebar. sidebarContainer.classList.remove( 'is-bottom-sidebar' ); sidebarContainer.style.removeProperty( 'top' ); } + + // Toggle the fixed position based on whether the scrollPosition is greater than the initial gap from the top. + sidebarContainer.classList.toggle( 'is-fixed-sidebar', scrollPosition > gap ); + return false; } @@ -133,7 +137,6 @@ function init() { if ( container ) { if ( isSidebarWithinViewport( container ) ) { - container.classList.add( 'is-fixed-sidebar' ); onScroll(); // Run once to avoid footer collisions on load (ex, when linked to #reply-title). window.addEventListener( 'scroll', onScroll ); From ca9e3bdca24a40379aceb6bc983c5846bb925bb0 Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:20:52 +1300 Subject: [PATCH 02/12] Add default local nav height This means themes don't need to set it unless different. Matches the css property fallback. --- mu-plugins/blocks/sidebar-container/src/view.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index 6d10ea911..68e373e15 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -1,8 +1,9 @@ /** * This is the calculated value of the admin bar + header height + local nav bar. + * LOCAL_NAV_HEIGHT fallback value matches that of the CSS variable. */ -const localNavHeight = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ); -const FIXED_HEADER_HEIGHT = 32 + 90 + localNavHeight; +const LOCAL_NAV_HEIGHT = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ) || 60; +const FIXED_HEADER_HEIGHT = 32 + 90 + LOCAL_NAV_HEIGHT; /** * Get the value of a CSS custom property. From 3178a18bd1ce567e774c3ff2c42afcbddd0f433b Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:23:20 +1300 Subject: [PATCH 03/12] Optimise scroll logic Remove dom selectors and other static vars --- .../blocks/sidebar-container/src/view.js | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index 68e373e15..a8c00735d 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -4,6 +4,10 @@ */ const LOCAL_NAV_HEIGHT = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ) || 60; const FIXED_HEADER_HEIGHT = 32 + 90 + LOCAL_NAV_HEIGHT; +const GAP = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ); + +let container; +let mainEl; /** * Get the value of a CSS custom property. @@ -30,14 +34,11 @@ function getCustomPropValue( name, element = document.body ) { */ function onScroll() { // Only run the scroll code if the sidebar is floating. - const sidebarContainer = document.querySelector( '.wp-block-wporg-sidebar-container' ); - if ( ! sidebarContainer || ! window.matchMedia( '(min-width: 1200px)' ).matches ) { + if ( ! container || ! window.matchMedia( '(min-width: 1200px)' ).matches ) { return; } - const mainEl = document.getElementById( 'wp--skip-link--target' ); - const footerStart = mainEl.offsetTop + mainEl.offsetHeight; - const gap = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ); + const footerStart = mainEl.offsetTop + mainEl.offsetHeight; const viewportYOffset = window .getComputedStyle( document.documentElement ) .getPropertyValue( 'margin-top' ) @@ -46,35 +47,35 @@ function onScroll() { // This value needs to take account the margin on `html`. const scrollPosition = window.scrollY - viewportYOffset; - if ( ! sidebarContainer.classList.contains( 'is-bottom-sidebar' ) ) { + if ( ! container.classList.contains( 'is-bottom-sidebar' ) ) { // The pixel location of the bottom of the sidebar, relative to the top of the page. - const sidebarBottom = scrollPosition + sidebarContainer.offsetHeight + sidebarContainer.offsetTop; + const sidebarBottom = scrollPosition + container.offsetHeight + container.offsetTop; // Is the sidebar bottom crashing into the footer? - if ( footerStart - gap < sidebarBottom ) { - sidebarContainer.classList.add( 'is-bottom-sidebar' ); + if ( footerStart - GAP < sidebarBottom ) { + container.classList.add( 'is-bottom-sidebar' ); // Bottom sidebar is absolutely positioned, so we need to set the top relative to the page origin. - sidebarContainer.style.setProperty( + container.style.setProperty( 'top', // Starting from the footer Y position, subtract the sidebar height and gap/margins, and add // the viewport offset. This ensures the sidebar doesn't jump when the class is switched. - `${ footerStart - sidebarContainer.clientHeight - gap * 2 + viewportYOffset * 1 }px` + `${ footerStart - container.clientHeight - GAP * 2 + viewportYOffset * 1 }px` ); return true; } - } else if ( footerStart - sidebarContainer.offsetHeight - gap * 2 > scrollPosition ) { + } else if ( footerStart - container.offsetHeight - GAP * 2 > scrollPosition ) { // If the scroll position is higher than the top of the sidebar, switch back to just a fixed sidebar. - sidebarContainer.classList.remove( 'is-bottom-sidebar' ); - sidebarContainer.style.removeProperty( 'top' ); + container.classList.remove( 'is-bottom-sidebar' ); + container.style.removeProperty( 'top' ); } // Toggle the fixed position based on whether the scrollPosition is greater than the initial gap from the top. - sidebarContainer.classList.toggle( 'is-fixed-sidebar', scrollPosition > gap ); + container.classList.toggle( 'is-fixed-sidebar', scrollPosition > GAP ); return false; } -function isSidebarWithinViewport( container ) { +function isSidebarWithinViewport() { // Margin offset from the top of the sidebar. const gap = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ); // Usable viewport height. @@ -89,7 +90,8 @@ function isSidebarWithinViewport( container ) { } function init() { - const container = document.querySelector( '.wp-block-wporg-sidebar-container' ); + container = document.querySelector( '.wp-block-wporg-sidebar-container' ); + mainEl = document.getElementById( 'wp--skip-link--target' ); const toggleButton = container?.querySelector( '.wporg-table-of-contents__toggle' ); const list = container?.querySelector( '.wporg-table-of-contents__list' ); @@ -160,7 +162,6 @@ function init() { } } ); - const mainEl = document.getElementById( 'wp--skip-link--target' ); observer.observe( mainEl ); } } From a37cce1f1ee8fde7d7393661eaa98ca7acfe2b48 Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:31:14 +1300 Subject: [PATCH 04/12] Remove scroll logic for toggling contents Toggle functionality has been removed on desktop, which is the only size we handle scroll --- .../blocks/sidebar-container/src/view.js | 33 +------------------ 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index a8c00735d..d9a2841d4 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -104,42 +104,11 @@ function init() { toggleButton.setAttribute( 'aria-expanded', true ); list.setAttribute( 'style', 'display:block;' ); } - - // Use the same media query that determines whether it's 2 columns, - // because we don't need to manage scroll when one column. - if ( ! window.matchMedia( '(min-width: 1200px)' ).matches ) { - return; - } - - // After toggle, see if we need to update the sidebar classes. - if ( isSidebarWithinViewport( container ) ) { - container.classList.add( 'is-fixed-sidebar' ); - } else { - container.classList.remove( 'is-fixed-sidebar' ); - window.scrollTo( { top: 0, left: 0, behavior: 'instant' } ); - } - // Remove the bottom sidebar class and re-run the check to re-add - // it if the newly-expanded sidebar crashes into the footer. - container.classList.remove( 'is-bottom-sidebar' ); - const isBottom = onScroll(); - // If the sidebar is at the bottom, opening it might push it - // upwards off the screen, so scroll to it (take into account - // the fixed headers, plus a little extra space). - if ( isBottom ) { - window.scrollTo( { - top: - container.offsetTop - - FIXED_HEADER_HEIGHT - - getCustomPropValue( '--wp--preset--spacing--20' ), - left: 0, - behavior: 'instant', - } ); - } } ); } if ( container ) { - if ( isSidebarWithinViewport( container ) ) { + if ( isSidebarWithinViewport() ) { onScroll(); // Run once to avoid footer collisions on load (ex, when linked to #reply-title). window.addEventListener( 'scroll', onScroll ); From 9049827f9678776f2778dae082eb2a79b1a00fce Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:32:51 +1300 Subject: [PATCH 05/12] Add an extra guard on the scroll logic --- mu-plugins/blocks/sidebar-container/src/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index d9a2841d4..e6a744859 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -34,7 +34,7 @@ function getCustomPropValue( name, element = document.body ) { */ function onScroll() { // Only run the scroll code if the sidebar is floating. - if ( ! container || ! window.matchMedia( '(min-width: 1200px)' ).matches ) { + if ( ! mainEl || ! container || ! window.matchMedia( '(min-width: 1200px)' ).matches ) { return; } From bda1760b057d74499076bb937308d8d1bf452dcd Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:36:53 +1300 Subject: [PATCH 06/12] Move isSidebarWithinViewport guard within function --- .../blocks/sidebar-container/src/view.js | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index e6a744859..683066fda 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -76,6 +76,9 @@ function onScroll() { } function isSidebarWithinViewport() { + if ( ! container ) { + return false; + } // Margin offset from the top of the sidebar. const gap = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ); // Usable viewport height. @@ -107,32 +110,30 @@ function init() { } ); } - if ( container ) { - if ( isSidebarWithinViewport() ) { - onScroll(); // Run once to avoid footer collisions on load (ex, when linked to #reply-title). - window.addEventListener( 'scroll', onScroll ); - - const observer = new window.ResizeObserver( () => { - // If the sidebar is positioned at the bottom and mainEl resizes, - // it will remain fixed at the previous bottom position, leading to a broken page layout. - // In this case manually trigger the scroll handler to reposition. - if ( container.classList.contains( 'is-bottom-sidebar' ) ) { - container.classList.remove( 'is-bottom-sidebar' ); - container.style.removeProperty( 'top' ); - const isBottom = onScroll(); - // After the sidebar is repositioned, also adjusts the scroll position - // to a point where the sidebar is visible. - if ( isBottom ) { - window.scrollTo( { - top: container.offsetTop - FIXED_HEADER_HEIGHT, - behavior: 'instant', - } ); - } + if ( isSidebarWithinViewport() ) { + onScroll(); // Run once to avoid footer collisions on load (ex, when linked to #reply-title). + window.addEventListener( 'scroll', onScroll ); + + const observer = new window.ResizeObserver( () => { + // If the sidebar is positioned at the bottom and mainEl resizes, + // it will remain fixed at the previous bottom position, leading to a broken page layout. + // In this case manually trigger the scroll handler to reposition. + if ( container.classList.contains( 'is-bottom-sidebar' ) ) { + container.classList.remove( 'is-bottom-sidebar' ); + container.style.removeProperty( 'top' ); + const isBottom = onScroll(); + // After the sidebar is repositioned, also adjusts the scroll position + // to a point where the sidebar is visible. + if ( isBottom ) { + window.scrollTo( { + top: container.offsetTop - FIXED_HEADER_HEIGHT, + behavior: 'instant', + } ); } - } ); + } + } ); - observer.observe( mainEl ); - } + observer.observe( mainEl ); } // If there is no table of contents, hide the heading. From fac3d152e75d462b463ead2433f15ae647217471 Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:37:27 +1300 Subject: [PATCH 07/12] Add fallback for top gap --- mu-plugins/blocks/sidebar-container/src/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index 683066fda..79cc3b31f 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -4,7 +4,7 @@ */ const LOCAL_NAV_HEIGHT = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ) || 60; const FIXED_HEADER_HEIGHT = 32 + 90 + LOCAL_NAV_HEIGHT; -const GAP = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ); +const GAP = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ) || 150; let container; let mainEl; From 554eda3c3dfc001feb85223d9fffa69cbcb62639 Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:38:15 +1300 Subject: [PATCH 08/12] Reduce the bottom space above the footer --- mu-plugins/blocks/sidebar-container/src/view.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index 79cc3b31f..c5b0fa42d 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -5,6 +5,7 @@ const LOCAL_NAV_HEIGHT = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ) || 60; const FIXED_HEADER_HEIGHT = 32 + 90 + LOCAL_NAV_HEIGHT; const GAP = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ) || 150; +const BOTTOM_GAP = getCustomPropValue( '--wp--preset--spacing--edge-space' ) || 80; let container; let mainEl; @@ -52,18 +53,18 @@ function onScroll() { const sidebarBottom = scrollPosition + container.offsetHeight + container.offsetTop; // Is the sidebar bottom crashing into the footer? - if ( footerStart - GAP < sidebarBottom ) { + if ( footerStart - BOTTOM_GAP < sidebarBottom ) { container.classList.add( 'is-bottom-sidebar' ); // Bottom sidebar is absolutely positioned, so we need to set the top relative to the page origin. container.style.setProperty( 'top', // Starting from the footer Y position, subtract the sidebar height and gap/margins, and add // the viewport offset. This ensures the sidebar doesn't jump when the class is switched. - `${ footerStart - container.clientHeight - GAP * 2 + viewportYOffset * 1 }px` + `${ footerStart - container.clientHeight - GAP - BOTTOM_GAP + viewportYOffset * 1 }px` ); return true; } - } else if ( footerStart - container.offsetHeight - GAP * 2 > scrollPosition ) { + } else if ( footerStart - container.offsetHeight - GAP - BOTTOM_GAP > scrollPosition ) { // If the scroll position is higher than the top of the sidebar, switch back to just a fixed sidebar. container.classList.remove( 'is-bottom-sidebar' ); container.style.removeProperty( 'top' ); From adc0164fd1446adac1687dcde76d049a91ee6534 Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:49:00 +1300 Subject: [PATCH 09/12] Improve comments --- mu-plugins/blocks/sidebar-container/src/view.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index c5b0fa42d..6044e4f52 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -1,10 +1,10 @@ /** - * This is the calculated value of the admin bar + header height + local nav bar. - * LOCAL_NAV_HEIGHT fallback value matches that of the CSS variable. + * FIXED_HEADER_HEIGHT is the calculated value of the admin bar + header height + local nav bar. + * Fallback values for custom properties match CSS defaults. */ const LOCAL_NAV_HEIGHT = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ) || 60; const FIXED_HEADER_HEIGHT = 32 + 90 + LOCAL_NAV_HEIGHT; -const GAP = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ) || 150; +const GAP = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ) || 80; const BOTTOM_GAP = getCustomPropValue( '--wp--preset--spacing--edge-space' ) || 80; let container; From 284845d6c1b1f1edad5816a7c824a7513daa4ac2 Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:31:25 +1300 Subject: [PATCH 10/12] Replace local nav bar height var with global setting --- mu-plugins/blocks/local-navigation-bar/postcss/style.pcss | 7 ++++++- mu-plugins/blocks/sidebar-container/postcss/style.pcss | 1 + mu-plugins/blocks/table-of-contents/postcss/style.pcss | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mu-plugins/blocks/local-navigation-bar/postcss/style.pcss b/mu-plugins/blocks/local-navigation-bar/postcss/style.pcss index 45d83368b..0a4b69567 100644 --- a/mu-plugins/blocks/local-navigation-bar/postcss/style.pcss +++ b/mu-plugins/blocks/local-navigation-bar/postcss/style.pcss @@ -14,7 +14,7 @@ } .wp-block-wporg-local-navigation-bar { - height: var(--wp--custom--local-navigation-bar--spacing--height, 60px); + height: var(--wp--custom--local-navigation-bar--spacing--height); @media (min-width: 890px) { & .global-header__wporg-logo-mark { @@ -122,3 +122,8 @@ } } } + +/* Set up the custom properties. These can be overridden by settings in theme.json. */ +:where(body) { + --wp--custom--local-navigation-bar--spacing--height: 60px; +} diff --git a/mu-plugins/blocks/sidebar-container/postcss/style.pcss b/mu-plugins/blocks/sidebar-container/postcss/style.pcss index 29e746626..90f2e3e27 100644 --- a/mu-plugins/blocks/sidebar-container/postcss/style.pcss +++ b/mu-plugins/blocks/sidebar-container/postcss/style.pcss @@ -17,6 +17,7 @@ position: absolute; top: calc(var(--wp-global-header-offset, 0px) + var(--wp-local-header-offset, 0px)); + top: calc(var(--wp-global-header-offset, 90px) + var(--wp--custom--local-navigation-bar--spacing--height, 60px)); /* Right offset should be "edge spacing" at minimum, otherwise calculate it to be centered. */ right: max(var(--wp--preset--spacing--edge-space), calc((100% - var(--wp--style--global--wide-size)) / 2)); diff --git a/mu-plugins/blocks/table-of-contents/postcss/style.pcss b/mu-plugins/blocks/table-of-contents/postcss/style.pcss index 50af14104..6f5b42bdb 100644 --- a/mu-plugins/blocks/table-of-contents/postcss/style.pcss +++ b/mu-plugins/blocks/table-of-contents/postcss/style.pcss @@ -139,6 +139,6 @@ @media (min-width: 890px) { .is-toc-heading { - scroll-margin-top: var(--wp-local-header-offset, 0); + scroll-margin-top: calc(var(--wp--custom--local-navigation-bar--spacing--height) + var(--wp--preset--spacing--20)); } } From 033a64b0ca69a07c65001b2fc2f8bc54e772f048 Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:32:03 +1300 Subject: [PATCH 11/12] Adjust settings to work with Documentation site --- .../sidebar-container/postcss/style.pcss | 9 ++-- .../blocks/sidebar-container/src/view.js | 54 +++++++++---------- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/mu-plugins/blocks/sidebar-container/postcss/style.pcss b/mu-plugins/blocks/sidebar-container/postcss/style.pcss index 90f2e3e27..20d7aedfb 100644 --- a/mu-plugins/blocks/sidebar-container/postcss/style.pcss +++ b/mu-plugins/blocks/sidebar-container/postcss/style.pcss @@ -16,17 +16,20 @@ --local--block-end-sidebar--width: 340px; position: absolute; - top: calc(var(--wp-global-header-offset, 0px) + var(--wp-local-header-offset, 0px)); top: calc(var(--wp-global-header-offset, 90px) + var(--wp--custom--local-navigation-bar--spacing--height, 60px)); /* Right offset should be "edge spacing" at minimum, otherwise calculate it to be centered. */ right: max(var(--wp--preset--spacing--edge-space), calc((100% - var(--wp--style--global--wide-size)) / 2)); width: var(--local--block-end-sidebar--width); - margin-top: var(--wp--custom--wporg-sidebar-container--spacing--margin--top) !important; + margin-top: var(--wp--custom--wporg-sidebar-container--spacing--margin--top); + margin-bottom: 0 !important; &.is-fixed-sidebar { position: fixed; top: 0; + + /* Make the space above the sidebar the same as the height of the local nav. */ + margin-top: calc(var(--wp-admin--admin-bar--height, 0px) + var(--wp--custom--local-navigation-bar--spacing--height, 60px) * 2); } &.is-bottom-sidebar { @@ -53,7 +56,7 @@ @media (min-width: 890px) { /* stylelint-disable selector-id-pattern */ #wp--skip-link--target { - scroll-margin-top: var(--wp-local-header-offset, 0); + scroll-margin-top: var(--wp--custom--local-navigation-bar--spacing--height, 0); } } diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index 6044e4f52..33bb4206e 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -1,11 +1,17 @@ /** - * FIXED_HEADER_HEIGHT is the calculated value of the admin bar + header height + local nav bar. * Fallback values for custom properties match CSS defaults. */ -const LOCAL_NAV_HEIGHT = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ) || 60; -const FIXED_HEADER_HEIGHT = 32 + 90 + LOCAL_NAV_HEIGHT; -const GAP = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ) || 80; -const BOTTOM_GAP = getCustomPropValue( '--wp--preset--spacing--edge-space' ) || 80; +const globalNavHeight = 90; +const localNavHeight = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ) || 60; + +const ADMIN_BAR_HEIGHT = parseInt( + window.getComputedStyle( document.documentElement ).getPropertyValue( 'margin-top' ), + 10 +); +const SPACE_FROM_BOTTOM = getCustomPropValue( '--wp--preset--spacing--edge-space' ) || 80; +const SPACE_TO_TOP = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ) || 80; +const FIXED_HEADER_HEIGHT = globalNavHeight + localNavHeight + ADMIN_BAR_HEIGHT; +const SCROLL_POSITION_TO_FIX = globalNavHeight + SPACE_TO_TOP - localNavHeight - ADMIN_BAR_HEIGHT; let container; let mainEl; @@ -34,44 +40,38 @@ function getCustomPropValue( name, element = document.body ) { * @return {boolean} True if the sidebar is at the bottom of the page. */ function onScroll() { - // Only run the scroll code if the sidebar is floating. + // Only run the scroll code if the sidebar is floating on a wide screen. if ( ! mainEl || ! container || ! window.matchMedia( '(min-width: 1200px)' ).matches ) { return; } - const footerStart = mainEl.offsetTop + mainEl.offsetHeight; - const viewportYOffset = window - .getComputedStyle( document.documentElement ) - .getPropertyValue( 'margin-top' ) - .replace( 'px', '' ); - - // This value needs to take account the margin on `html`. - const scrollPosition = window.scrollY - viewportYOffset; + const scrollPosition = window.scrollY - ADMIN_BAR_HEIGHT; if ( ! container.classList.contains( 'is-bottom-sidebar' ) ) { + const footerStart = mainEl.offsetTop + mainEl.offsetHeight; // The pixel location of the bottom of the sidebar, relative to the top of the page. - const sidebarBottom = scrollPosition + container.offsetHeight + container.offsetTop; + const sidebarBottom = scrollPosition + container.offsetHeight + container.offsetTop - ADMIN_BAR_HEIGHT; // Is the sidebar bottom crashing into the footer? - if ( footerStart - BOTTOM_GAP < sidebarBottom ) { + if ( footerStart - SPACE_FROM_BOTTOM < sidebarBottom ) { container.classList.add( 'is-bottom-sidebar' ); + // Bottom sidebar is absolutely positioned, so we need to set the top relative to the page origin. - container.style.setProperty( - 'top', - // Starting from the footer Y position, subtract the sidebar height and gap/margins, and add - // the viewport offset. This ensures the sidebar doesn't jump when the class is switched. - `${ footerStart - container.clientHeight - GAP - BOTTOM_GAP + viewportYOffset * 1 }px` - ); + // The pixel location of the top of the sidebar, relative to the footer. + const sidebarTop = + footerStart - container.offsetHeight - localNavHeight * 2 + ADMIN_BAR_HEIGHT - SPACE_FROM_BOTTOM; + container.style.setProperty( 'top', `${ sidebarTop }px` ); + return true; } - } else if ( footerStart - container.offsetHeight - GAP - BOTTOM_GAP > scrollPosition ) { - // If the scroll position is higher than the top of the sidebar, switch back to just a fixed sidebar. + } else if ( container.getBoundingClientRect().top > localNavHeight * 2 + ADMIN_BAR_HEIGHT ) { + // If the top of the sidebar is above the top fixing position, switch back to just a fixed sidebar. container.classList.remove( 'is-bottom-sidebar' ); container.style.removeProperty( 'top' ); } // Toggle the fixed position based on whether the scrollPosition is greater than the initial gap from the top. - container.classList.toggle( 'is-fixed-sidebar', scrollPosition > GAP ); + container.classList.toggle( 'is-fixed-sidebar', scrollPosition > SCROLL_POSITION_TO_FIX ); return false; } @@ -80,14 +80,12 @@ function isSidebarWithinViewport() { if ( ! container ) { return false; } - // Margin offset from the top of the sidebar. - const gap = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ); // Usable viewport height. const viewHeight = window.innerHeight - FIXED_HEADER_HEIGHT; // Get the height of the sidebar, plus the top margin and 50px for the // "Back to top" link, which isn't visible until `is-fixed-sidebar` is // added, therefore not included in the offsetHeight value. - const sidebarHeight = container.offsetHeight + gap + 50; + const sidebarHeight = container.offsetHeight + SPACE_TO_TOP + 50; // If the sidebar is shorter than the view area, apply the class so // that it's fixed and scrolls with the page content. return sidebarHeight < viewHeight; From 36220f9631efb8770f4c039d14702f58968dcacb Mon Sep 17 00:00:00 2001 From: Adam Wood <1017872+adamwoodnz@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:10:37 +1300 Subject: [PATCH 12/12] Adjust calculation for sidebar fitting in viewport --- mu-plugins/blocks/sidebar-container/src/view.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mu-plugins/blocks/sidebar-container/src/view.js b/mu-plugins/blocks/sidebar-container/src/view.js index 33bb4206e..52cb01841 100644 --- a/mu-plugins/blocks/sidebar-container/src/view.js +++ b/mu-plugins/blocks/sidebar-container/src/view.js @@ -2,16 +2,16 @@ * Fallback values for custom properties match CSS defaults. */ const globalNavHeight = 90; -const localNavHeight = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ) || 60; +const LOCAL_NAV_HEIGHT = getCustomPropValue( '--wp--custom--local-navigation-bar--spacing--height' ) || 60; const ADMIN_BAR_HEIGHT = parseInt( window.getComputedStyle( document.documentElement ).getPropertyValue( 'margin-top' ), 10 ); const SPACE_FROM_BOTTOM = getCustomPropValue( '--wp--preset--spacing--edge-space' ) || 80; const SPACE_TO_TOP = getCustomPropValue( '--wp--custom--wporg-sidebar-container--spacing--margin--top' ) || 80; -const FIXED_HEADER_HEIGHT = globalNavHeight + localNavHeight + ADMIN_BAR_HEIGHT; -const SCROLL_POSITION_TO_FIX = globalNavHeight + SPACE_TO_TOP - localNavHeight - ADMIN_BAR_HEIGHT; +const FIXED_HEADER_HEIGHT = globalNavHeight + LOCAL_NAV_HEIGHT + ADMIN_BAR_HEIGHT; +const SCROLL_POSITION_TO_FIX = globalNavHeight + SPACE_TO_TOP - LOCAL_NAV_HEIGHT - ADMIN_BAR_HEIGHT; let container; let mainEl; @@ -59,12 +59,12 @@ function onScroll() { // Bottom sidebar is absolutely positioned, so we need to set the top relative to the page origin. // The pixel location of the top of the sidebar, relative to the footer. const sidebarTop = - footerStart - container.offsetHeight - localNavHeight * 2 + ADMIN_BAR_HEIGHT - SPACE_FROM_BOTTOM; + footerStart - container.offsetHeight - LOCAL_NAV_HEIGHT * 2 + ADMIN_BAR_HEIGHT - SPACE_FROM_BOTTOM; container.style.setProperty( 'top', `${ sidebarTop }px` ); return true; } - } else if ( container.getBoundingClientRect().top > localNavHeight * 2 + ADMIN_BAR_HEIGHT ) { + } else if ( container.getBoundingClientRect().top > LOCAL_NAV_HEIGHT * 2 + ADMIN_BAR_HEIGHT ) { // If the top of the sidebar is above the top fixing position, switch back to just a fixed sidebar. container.classList.remove( 'is-bottom-sidebar' ); container.style.removeProperty( 'top' ); @@ -81,11 +81,11 @@ function isSidebarWithinViewport() { return false; } // Usable viewport height. - const viewHeight = window.innerHeight - FIXED_HEADER_HEIGHT; - // Get the height of the sidebar, plus the top margin and 50px for the + const viewHeight = window.innerHeight - LOCAL_NAV_HEIGHT + ADMIN_BAR_HEIGHT; + // Get the height of the sidebar, plus the top offset and 60px for the // "Back to top" link, which isn't visible until `is-fixed-sidebar` is // added, therefore not included in the offsetHeight value. - const sidebarHeight = container.offsetHeight + SPACE_TO_TOP + 50; + const sidebarHeight = container.offsetHeight + LOCAL_NAV_HEIGHT + 60; // If the sidebar is shorter than the view area, apply the class so // that it's fixed and scrolls with the page content. return sidebarHeight < viewHeight;