Simplify TOC spacing styles/logic by reusing the visible sticky header class

- Remove the 'vector-scrolled-below-table-of-contents' class, reducing the number of classes added with JS and simplifying the scrollObserver logic
- Move the 'vector-sticky-header-visible' class from the sticky header element to the body element. Hopefully, this is where other feature specific classes can go in the future
- This approach means the TOC will not need JS to update it's spacing when the sticky header is not enabled

Bug: T307345
Change-Id: I1084defc7025f5c946e22a36d373224fae6f8bd6
This commit is contained in:
bwang 2022-05-05 15:54:20 -05:00
parent 5f341fbb36
commit 91e2e55a10
8 changed files with 35 additions and 43 deletions

View File

@ -8,7 +8,7 @@
for more context.
}}
<header id="vector-sticky-header" aria-hidden="true"
class="vector-sticky-header{{#is-visible}} vector-sticky-header-visible{{/is-visible}}">
class="vector-sticky-header">
<div class="vector-sticky-header-start">
<div class="vector-sticky-header-icon-start">
{{#data-button-start}}

View File

@ -18,8 +18,7 @@ const
TOC_SCROLL_HOOK = 'table_of_contents',
PAGE_TITLE_SCROLL_HOOK = 'page_title',
TOC_QUERY_PARAM = 'tableofcontents',
TOC_EXPERIMENT_NAME = 'skin-vector-toc-experiment',
SCROLL_TOC_BELOW_CLASS = 'vector-scrolled-below-table-of-contents';
TOC_EXPERIMENT_NAME = 'skin-vector-toc-experiment';
/**
* @callback OnIntersection
@ -101,15 +100,13 @@ const main = () => {
const observer = scrollObserver.initScrollObserver(
() => {
if ( isStickyHeaderAllowed && isStickyHeaderEnabled ) {
stickyHeader.show( header );
document.body.classList.add( SCROLL_TOC_BELOW_CLASS );
stickyHeader.show();
}
scrollObserver.fireScrollHook( 'down', PAGE_TITLE_SCROLL_HOOK );
},
() => {
if ( isStickyHeaderAllowed && isStickyHeaderEnabled ) {
stickyHeader.hide( header );
document.body.classList.remove( SCROLL_TOC_BELOW_CLASS );
stickyHeader.hide();
}
scrollObserver.fireScrollHook( 'up', PAGE_TITLE_SCROLL_HOOK );
}

View File

@ -31,21 +31,17 @@ function copyAttribute( from, to, attribute ) {
/**
* Show the sticky header.
*
* @param {Element} header
*/
function show( header ) {
header.classList.add( STICKY_HEADER_VISIBLE_CLASS );
function show() {
document.body.classList.add( STICKY_HEADER_VISIBLE_CLASS );
document.body.classList.remove( ULS_HIDE_CLASS );
}
/**
* Hide the sticky header.
*
* @param {Element} header
*/
function hide( header ) {
header.classList.remove( STICKY_HEADER_VISIBLE_CLASS );
function hide() {
document.body.classList.remove( STICKY_HEADER_VISIBLE_CLASS );
document.body.classList.add( ULS_HIDE_CLASS );
}
@ -284,14 +280,13 @@ function isInViewport( element ) {
/**
* Add hooks for sticky header when Visual Editor is used.
*
* @param {Element} header
* @param {Element} stickyIntersection intersection element
* @param {IntersectionObserver} observer
*/
function addVisualEditorHooks( header, stickyIntersection, observer ) {
function addVisualEditorHooks( stickyIntersection, observer ) {
// When Visual Editor is activated, hide the sticky header.
mw.hook( 've.activationStart' ).add( () => {
hide( header );
hide();
observer.unobserve( stickyIntersection );
} );
@ -308,7 +303,7 @@ function addVisualEditorHooks( header, stickyIntersection, observer ) {
// After saving edits, re-apply the sticky header if the target is not in the viewport.
mw.hook( 'postEdit.afterRemoval' ).add( () => {
if ( !isInViewport( stickyIntersection ) ) {
show( header );
show();
observer.observe( stickyIntersection );
}
} );
@ -378,7 +373,7 @@ function makeStickyHeaderFunctional(
const primaryEdit = protectedEdit || ( veEdit || ceEdit );
const secondaryEdit = veEdit ? ceEdit : null;
const disableStickyHeader = () => {
header.classList.remove( STICKY_HEADER_VISIBLE_CLASS );
document.body.classList.remove( STICKY_HEADER_VISIBLE_CLASS );
stickyObserver.unobserve( stickyIntersection );
};
@ -458,7 +453,7 @@ function initStickyHeader( props ) {
);
setupSearchIfNeeded( props.header );
addVisualEditorHooks( props.header, props.stickyIntersection, props.observer );
addVisualEditorHooks( props.stickyIntersection, props.observer );
// Make sure ULS outside sticky header disables the sticky header behaviour.
// @ts-ignore

View File

@ -74,9 +74,9 @@
}
}
// T305069 When scrolling down, override the top padding of the sticky TOC that is applied during menu toggling
// so that the top of sticky TOC remains at the top of the viewport with normal padding. See scrollObserver.js.
&.vector-scrolled-below-table-of-contents .sidebar-toc {
// T305069 When scrolling down, override the top margin of the sticky TOC
// so that the top of sticky TOC remains at the top of the viewport with normal padding.
&.vector-sticky-header-visible .sidebar-toc {
margin-top: @top-margin-sidebar-toc;
}
}

View File

@ -9,7 +9,6 @@
left: 0;
right: 0;
z-index: @z-index-header;
transform: translateY( -100% );
transition: @transition-sticky-header;
display: flex;
align-items: center;
@ -32,20 +31,25 @@
max-width: @max-width-page-container + ( @padding-horizontal-page-container-wide * 2 );
}
// Hide sticky header and it's children until visible class is applied to the body
.client-js.vector-sticky-header-enabled :not( .vector-sticky-header-visible ) & {
transform: translateY( -100% );
> div {
display: none;
}
}
// Hide sticky header for no-js users
.client-nojs & {
display: none;
}
// T298836 Hide the sticky header at lower resolutions.
@media ( max-width: @width-breakpoint-desktop ) {
display: none;
}
// Hide any open menus/search results unless sticky header is visible
&:not( .vector-sticky-header-visible ) > div {
display: none;
}
&-visible {
transform: translateY( 0% );
}
//
// Layout
//
@ -120,10 +124,6 @@
}
}
.client-nojs .vector-sticky-header {
display: none;
}
@media ( min-width: @width-breakpoint-tablet ) {
.client-js.vector-sticky-header-enabled {
// T290518: When the sticky header is enabled (feature flag is on, js is

View File

@ -183,9 +183,10 @@ body {
position: sticky;
float: left;
clear: both;
// Defaults to the top of the viewport unless .mw-sticky-header-element
// overrides it.
top: 0;
// Defaults to -2em to account for the TOC's top margin
// ensuring the TOC is 1.5em (24px) from the top of the viewport
// unless .mw-sticky-header-element overrides it.
top: calc( 1.5em - @top-margin-sidebar-toc_title_inline );
}
.parsoid-body {

View File

@ -31,6 +31,6 @@
* and the notification bar is also open, the notification
* should be moved so that it doesn't obstruct the sticky header
*/
.vector-sticky-header-visible ~ .mw-notification-area-overlay > .mw-notification-area-floating {
.vector-sticky-header-visible .mw-notification-area-overlay > .mw-notification-area-floating {
transform: translateY( @height-sticky-header );
}

View File

@ -23,7 +23,6 @@ const HISTORY_ICON = {
const data = {
title: 'Audre Lorde',
heading: 'Introduction',
'is-visible': true,
'data-primary-action': {
id: 'p-lang-btn-sticky-header',
class: 'mw-interlanguage-selector',