Increase scroll-padding-top for page sections

This introduces a general scroll-padding-top value of 50px
for Vector 2022's HTML element.

This changes makes it so that when navigating sections via the
TOC, the section headings are 50px lower on the screen.

This change has been synced with the ToC active sections as well,
so that active sections become active at the same offset.

Bug: T314419
Change-Id: I99e5fe2047f5ad1e61ef51b6ba7e76a6cac36fc5
This commit is contained in:
Jan Drewniak 2023-02-28 14:48:31 -05:00
parent bb4e46ec27
commit cfc454f615
5 changed files with 26 additions and 9 deletions

View file

@ -220,6 +220,10 @@
@padding-horizontal-page-container: unit( 24px / @font-size-browser, em );
@padding-horizontal-page-container-desktop: unit( 44px / @font-size-browser, em );
@padding-horizontal-page-container-desktop-wide: unit( 52px / @font-size-browser, em );
// T314419 - Scroll padding is modified primarily to bring section headings into a position that is
// easier to read, which is slightly lower than the very top of the page. The primary use-case is when
// navigating sections via the table of contents.
@scroll-padding-top: 50px;
// Grid
@grid-row-gap: 24px;

View file

@ -140,13 +140,24 @@ const updateTocLocation = () => {
};
/**
* @param {HTMLElement|null} header
* Return the computed value of the
* `scroll-margin-top` CSS property, of the document element, as a number.
*
* @return {number} Value of scroll-margin-top OR zero if falsy.
*/
function getDocumentScrollPaddingTop() {
const documentStyles = getComputedStyle( document.documentElement ),
scrollPaddingTopString = documentStyles.getPropertyValue( 'scroll-padding-top' );
return parseInt( scrollPaddingTopString, 10 ) || 0;
}
/**
* @param {HTMLElement|null} tocElement
* @param {HTMLElement|null} bodyContent
* @param {initSectionObserver} initSectionObserverFn
* @return {tableOfContents|null}
*/
const setupTableOfContents = ( header, tocElement, bodyContent, initSectionObserverFn ) => {
const setupTableOfContents = ( tocElement, bodyContent, initSectionObserverFn ) => {
if ( !(
tocElement &&
bodyContent
@ -202,7 +213,7 @@ const setupTableOfContents = ( header, tocElement, bodyContent, initSectionObser
const sectionObserver = initSectionObserverFn( {
elements: elements(),
topMargin: header ? header.getBoundingClientRect().height : 0,
topMargin: getDocumentScrollPaddingTop(),
onIntersection: getHeadingIntersectionHandler( tableOfContents.changeActiveSection )
} );
const updateElements = () => {
@ -252,7 +263,7 @@ const main = () => {
const isToCUpdatingAllowed = isIntersectionObserverSupported &&
window.requestAnimationFrame;
const tableOfContents = isToCUpdatingAllowed ?
setupTableOfContents( header, tocElement, bodyContent, initSectionObserver ) : null;
setupTableOfContents( tocElement, bodyContent, initSectionObserver ) : null;
//
// Sticky header

View file

@ -142,7 +142,7 @@
// .vector-sticky-header-visible class to correctly handle situations where the
// sticky header isn't visible yet but we still need scroll padding applied
// (e.g. when the user navigates to a page with a hash fragment in the URI).
scroll-padding-top: @height-sticky-header;
scroll-padding-top: ~'calc( @{height-sticky-header} + @{scroll-padding-top} )';
.vector-sticky-header {
// Sticky header is only enabled for js users and when feature flag is enabled

View file

@ -22,6 +22,10 @@
// smaller and will start horizontal scrolling instead.
@min-width-supported: unit( 500px / @font-size-browser, em );
html {
scroll-padding-top: @scroll-padding-top;
}
body {
background-color: @background-color-secondary--modern;
color: @color-base;

View file

@ -191,10 +191,9 @@ describe( 'Table of contents re-rendering', () => {
it( 'listens to wikipage.tableOfContents hook when mounted', () => {
mockMwHook();
const spy = jest.spyOn( mw, 'hook' );
const header = document.createElement( 'header' );
const tocElement = document.createElement( 'div' );
const bodyContent = document.createElement( 'article' );
const toc = test.setupTableOfContents( header, tocElement, bodyContent, sectionObserverFn );
const toc = test.setupTableOfContents( tocElement, bodyContent, sectionObserverFn );
expect( toc ).not.toBe( null );
expect( spy ).toHaveBeenCalledWith( 'wikipage.tableOfContents' );
expect( spy ).not.toHaveBeenCalledWith( 'wikipage.tableOfContents.vector' );
@ -202,10 +201,9 @@ describe( 'Table of contents re-rendering', () => {
it( 'Firing wikipage.tableOfContents triggers reloadTableOfContents', async () => {
mockMwHook();
const header = document.createElement( 'header' );
const tocElement = document.createElement( 'div' );
const bodyContent = document.createElement( 'article' );
const toc = test.setupTableOfContents( header, tocElement, bodyContent, sectionObserverFn );
const toc = test.setupTableOfContents( tocElement, bodyContent, sectionObserverFn );
if ( !toc ) {
// something went wrong
expect( true ).toBe( false );