Depois que o Edge se juntou às valentes fileiras dos navegadores Chromium, a personalização das barras de rolagem via CSS está ausente apenas no Firefox. Isso é ótimo, mas, além do Firefox, a solução CSS tem muitas limitações. Veja que magia negra você precisa usar para desaparecer. Para obter controle total sobre a aparência, você ainda precisa recorrer ao JavaScript. Vamos ver como fazê-lo através do componente Angular em um bom caminho.

Magia CSS
, , . -, . . scrollbar-width
, Firefox. Edge IE -ms-overflow-style
. IE , position: sticky
. Chrome Safari ::-webkit-scrollbar
.
-, , . , - position: fixed
. : .
position: sticky
display: flex
. :
<div class="bars">...</div>
<div class="content"><ng-content></ng-content></div>
. , - z-index: 1000, 1001, 9999
. , position: relative, z-index: 0
. - .
z-index: 1
, , 100%. :

, . . margin-right: -100%
, «» .
, , float
, 100%, (max-height, flex: 1
).
Angular
Angular, , . . . , . :
<div class="bars">
<div *ngIf="hasVerticalBar" class="bar">
<div
class="thumb"
[class.thumb_active]="verticalThumbActive"
[style.height.%]="verticalView"
[style.top.%]="verticalThumb"
></div>
</div>
</div>
:
//
get verticalScrolled(): number {
const {
scrollTop,
scrollHeight,
clientHeight
} = this.elementRef.nativeElement;
return scrollTop / (scrollHeight - clientHeight);
}
//
get verticalSize(): number {
const { clientHeight, scrollHeight } = this.elementRef.nativeElement;
return Math.ceil(clientHeight / scrollHeight * 100);
}
//
get verticalPosition(): number {
return this.verticalScrolled * (100 - this.verticalSize);
}
// ,
get hasVerticalBar(): boolean {
return this.verticalSize < 100;
}
, , — . . , .
mousedown
, mousemove
mouseup
.
:
<div
#vertical
class="thumb"
[class.thumb_active]="verticalThumbActive"
[style.height.%]="verticalSize"
[style.top.%]="verticalPosition"
(mousedown)="onVerticalStart($event)"
(document:mousemove)="onVerticalMove($event, vertical)"
></div>
mouseup
:
@HostListener('document:mouseup)
onDragEnd() {
this.verticalThumbActive = false;
}
onVerticalStart(event: MouseEvent) {
event.preventDefault();
const { target, clientY } = event;
const { top, height } = target.getBoundingClientRect();
this.verticalThumbDragOffset = (clientY - top) / height;
this.verticalThumbActive = true;
}
onVerticalMove(
{ clientY }: MouseEvent,
{ offsetHeight }: HTMLElement
) {
if (!this.verticalThumbActive) {
return;
}
const { nativeElement } = this.elementRef;
const { top, height } = nativeElement.getBoundingClientRect();
const maxScrollTop = nativeElement.scrollHeight - height;
const scrolled =
(clientY - top - offsetHeight * this.verticalThumbDragOffset) /
(height - offsetHeight);
nativeElement.scrollTop = maxScrollTop * scrolled;
}
.
Angular
, . mousemove
. . , Angular , . @tinkoff/ng-event-plugins, . .silent
@shouldCall
:
(document:mousemove.silent)="onVerticalMove($event, vertical)"
@shouldCall(isActive)
@HostListener('init.end', ['$event'])
@HostListener('document:mouseup.silent')
onDragEnd() {
this.verticalThumbActive = false;
}
@shouldCall(isActive)
@HostListener('init.move', ['$event'])
onVerticalMove(
{ clientY }: MouseEvent,
{ offsetHeight }: HTMLElement
) {
const { nativeElement } = this.elementRef;
const { top, height } = nativeElement.getBoundingClientRect();
const maxScrollTop = nativeElement.scrollHeight - height;
const scrolled =
(clientY - top - offsetHeight * this.verticalThumbDragOffset) /
(height - offsetHeight);
nativeElement.scrollTop = maxScrollTop * scrolled;
}
: Angular 10 markDirty(this)
@shouldCall
@HostListener(‘init.xxx’, [‘$event’])
, , — .
, . . , . ResizeObserver
@ng-web-apis/resize-observer, . Stackblitz.
Edit:
, , . . Output fromEvent, :
@Output()
dragged = fromEvent(
this.elementRef.nativeElement,
'mousedown'
).pipe(
switchMap(event => {
event.preventDefault();
const clientRect = event.target.getBoundingClientRect();
const offsetVertical = getOffsetVertical(event, clientRect);
const offsetHorizontal = getOffsetHorizontal(event, clientRect);
return fromEvent(this.documentRef, 'mousemove').pipe(
map(event => this.getScrolled(event, offsetVertical, offsetHorizontal)),
takeUntil(fromEvent(this.documentRef, 'mouseup'))
);
})
);
. , .