docs(docs-infra): fix app-scroller offset. (#64144)

Guide heading need different scroll offsets depending on the width of the screen. (The menu position varies).

PR Close #64144
This commit is contained in:
Matthieu Riegler 2025-09-30 03:59:07 +02:00 committed by kirjs
parent ced186fafb
commit 3db8ef004f
3 changed files with 53 additions and 13 deletions

View file

@ -5,6 +5,18 @@ $screen-lg: 1200px;
$screen-xl: 1430px;
$screen-xxl: 1800px;
@mixin breakpoints-vars {
// The app-scroller also relies on these values to determine the scroll offset.
:root {
--screen-xs: #{$screen-xs};
--screen-sm: #{$screen-sm};
--screen-md: #{$screen-md};
--screen-lg: #{$screen-lg};
--screen-xl: #{$screen-xl};
--screen-xxl: #{$screen-xxl};
}
}
@mixin for-phone-only {
@media (max-width: $screen-xs) {
@content;
@ -12,43 +24,43 @@ $screen-xxl: 1800px;
}
@mixin for-tablet-portrait-up {
@media (min-width: calc($screen-xs + .01px)) {
@media (min-width: calc($screen-xs + 0.01px)) {
@content;
}
}
@mixin for-tablet {
@media (min-width: calc($screen-xs + .01px)) and (max-width: $screen-md) {
@media (min-width: calc($screen-xs + 0.01px)) and (max-width: $screen-md) {
@content;
}
}
@mixin for-tablet-up {
@media (min-width: calc($screen-sm + .01px)) {
@media (min-width: calc($screen-sm + 0.01px)) {
@content;
}
}
@mixin for-tablet-landscape-up {
@media (min-width: calc($screen-md + .01px)) {
@media (min-width: calc($screen-md + 0.01px)) {
@content;
}
}
@mixin for-desktop-up {
@media (min-width: calc($screen-lg + .01px)) {
@media (min-width: calc($screen-lg + 0.01px)) {
@content;
}
}
@mixin for-large-desktop-up {
@media (min-width: calc($screen-xl + .01px)) {
@media (min-width: calc($screen-xl + 0.01px)) {
@content;
}
}
@mixin for-extra-large-desktop-up {
@media (min-width: calc($screen-xxl + .01px)) {
@media (min-width: calc($screen-xxl + 0.01px)) {
@content;
}
}
@ -75,4 +87,4 @@ $screen-xxl: 1800px;
@media (max-width: $screen-sm) {
@content;
}
}
}

View file

@ -41,6 +41,7 @@
@include api-item-label.api-item-label();
@include faceted-list.faceted-list();
@include mq.breakpoints-vars();
@include mq.for-phone-only();
@include mq.for-tablet-portrait-up();
@include mq.for-tablet-landscape-up();

View file

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {ViewportScroller} from '@angular/common';
import {isPlatformBrowser, ViewportScroller} from '@angular/common';
import {
Injectable,
inject,
@ -13,6 +13,8 @@ import {
afterNextRender,
EnvironmentInjector,
Injector,
DestroyRef,
PLATFORM_ID,
} from '@angular/core';
import {Scroll, Router} from '@angular/router';
import {filter, firstValueFrom, map, switchMap, tap} from 'rxjs';
@ -23,6 +25,7 @@ export class AppScroller {
private readonly viewportScroller = inject(ViewportScroller);
private readonly appRef = inject(ApplicationRef);
private readonly injector = inject(EnvironmentInjector);
private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
private _lastScrollEvent?: Scroll;
private canScroll = false;
@ -33,6 +36,26 @@ export class AppScroller {
}
constructor() {
if (this.isBrowser) {
this.setupScrollRestoration();
}
}
private setupScrollRestoration(): void {
let windowWidth = window.innerWidth;
// Setting up a ResizeObserver to update the width on resize. (without triggering a reflow)
const windowSizeObserver = new ResizeObserver((entries) => {
windowWidth = entries[0].contentRect.width;
});
windowSizeObserver.observe(document.documentElement);
inject(DestroyRef).onDestroy(() => windowSizeObserver.disconnect());
const root = document.documentElement; // or any element with the variable
const styles = getComputedStyle(root);
// slice to drop the 'px'
const xsBreakpoint = +styles.getPropertyValue('--screen-xs').slice(0, -2);
const mdBreakpoint = +styles.getPropertyValue('--screen-md').slice(0, -2);
this.viewportScroller.setHistoryScrollRestoration('manual');
this.router.events
.pipe(
@ -62,12 +85,16 @@ export class AppScroller {
this.scroll();
});
// This value is primarily intended to offset the scroll position on mobile when the menu is on the top.
// But on desktop, it doesn't hurt to have a small offset either.
this.viewportScroller.setOffset([0, 64]);
if (windowWidth < xsBreakpoint) {
this.viewportScroller.setOffset([0, 64]);
} else if (windowWidth <= mdBreakpoint) {
this.viewportScroller.setOffset([0, 140]);
} else {
this.viewportScroller.setOffset([0, 24]);
}
}
scroll(injector?: Injector) {
private scroll(injector?: Injector) {
if (!this._lastScrollEvent || !this.canScroll) {
return;
}