improve hover performance
All checks were successful
publish.yml / publish (push) Successful in 1m6s

This commit is contained in:
2026-04-23 23:50:27 +02:00
parent 1a00b77511
commit f7eceda442
3 changed files with 26 additions and 32 deletions

View File

@@ -30,7 +30,6 @@
border: 1px solid #30363d; border: 1px solid #30363d;
border-radius: 18px; border-radius: 18px;
background: rgba(22, 27, 34, 0.75); background: rgba(22, 27, 34, 0.75);
backdrop-filter: blur(9px);
z-index: 3; z-index: 3;
transition: transition:
top 260ms ease, top 260ms ease,

View File

@@ -37,35 +37,9 @@ h2 {
.stack-carousel-column { .stack-carousel-column {
position: relative; position: relative;
--left-fade-size: 0px;
--right-fade-size: 0px;
width: calc(100% - (var(--carousel-nav-space) * 2)); width: calc(100% - (var(--carousel-nav-space) * 2));
margin-inline: auto; margin-inline: auto;
overflow: hidden; overflow: hidden;
-webkit-mask-image: linear-gradient(
to right,
transparent 0,
#000 var(--left-fade-size),
#000 calc(100% - var(--right-fade-size)),
transparent 100%
);
mask-image: linear-gradient(
to right,
transparent 0,
#000 var(--left-fade-size),
#000 calc(100% - var(--right-fade-size)),
transparent 100%
);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
}
.stack-carousel-column.has-left-fade {
--left-fade-size: var(--carousel-edge-fade-size);
}
.stack-carousel-column.has-right-fade {
--right-fade-size: var(--carousel-edge-fade-size);
} }
.stack-carousel { .stack-carousel {
@@ -118,8 +92,7 @@ h2 {
height: 1.2rem; height: 1.2rem;
object-fit: contain; object-fit: contain;
opacity: 0.92; opacity: 0.92;
filter: grayscale(1) brightness(1.25) contrast(0.92); transition: transform 140ms ease, opacity 140ms ease;
transition: transform 140ms ease, opacity 140ms ease, filter 140ms ease;
} }
.skill-fallback { .skill-fallback {
@@ -159,7 +132,6 @@ h2 {
.stack-slide:focus-within .skill-logo { .stack-slide:focus-within .skill-logo {
opacity: 1; opacity: 1;
transform: scale(1.04); transform: scale(1.04);
filter: grayscale(1) brightness(1.4) contrast(1);
} }
.carousel-btn { .carousel-btn {

View File

@@ -30,11 +30,13 @@ export class TechStackCarousel implements AfterViewInit, OnDestroy {
private isPausePendingStop = false; private isPausePendingStop = false;
private isTouchInteracting = false; private isTouchInteracting = false;
private isProgrammaticScrollUpdate = false; private isProgrammaticScrollUpdate = false;
private readonly autoScrollSpeedPxPerSecond = 72; private lastFadeStateUpdateTime = 0;
private readonly autoScrollSpeedPxPerSecond = 48;
private readonly speedRampDurationMs = 420; private readonly speedRampDurationMs = 420;
private readonly speedStopThresholdPxPerSecond = 0.5; private readonly speedStopThresholdPxPerSecond = 0.5;
private readonly touchScrollResumeDelayMs = 1200; private readonly touchScrollResumeDelayMs = 1200;
private readonly hoverPauseDelayMs = 300; private readonly hoverPauseDelayMs = 300;
private readonly fadeUpdateIntervalMs = 96;
isAutoScrolling = false; isAutoScrolling = false;
showLeftFade = false; showLeftFade = false;
showRightFade = false; showRightFade = false;
@@ -71,6 +73,8 @@ export class TechStackCarousel implements AfterViewInit, OnDestroy {
this.updateFadeState(); this.updateFadeState();
this.resumeAutoScroll(); this.resumeAutoScroll();
}, 0); }, 0);
document.addEventListener('visibilitychange', this.onVisibilityChange);
} }
ngOnDestroy(): void { ngOnDestroy(): void {
@@ -82,6 +86,7 @@ export class TechStackCarousel implements AfterViewInit, OnDestroy {
this.clearScheduledResume(); this.clearScheduledResume();
this.clearScheduledHoverPause(); this.clearScheduledHoverPause();
this.pauseAutoScroll(); this.pauseAutoScroll();
document.removeEventListener('visibilitychange', this.onVisibilityChange);
this.isAutoScrolling = false; this.isAutoScrolling = false;
} }
@@ -168,6 +173,10 @@ export class TechStackCarousel implements AfterViewInit, OnDestroy {
} }
resumeAutoScroll(): void { resumeAutoScroll(): void {
if (document.hidden) {
return;
}
if (this.isTouchInteracting) { if (this.isTouchInteracting) {
this.scheduleResume(this.touchScrollResumeDelayMs); this.scheduleResume(this.touchScrollResumeDelayMs);
return; return;
@@ -208,7 +217,11 @@ export class TechStackCarousel implements AfterViewInit, OnDestroy {
this.autoAdvanceStack(carousel, deltaMs, this.currentAutoScrollSpeedPxPerSecond); this.autoAdvanceStack(carousel, deltaMs, this.currentAutoScrollSpeedPxPerSecond);
} }
if (timestamp - this.lastFadeStateUpdateTime >= this.fadeUpdateIntervalMs) {
this.updateFadeState(carousel); this.updateFadeState(carousel);
this.lastFadeStateUpdateTime = timestamp;
}
this.syncAutoScrollState(); this.syncAutoScrollState();
if (this.isPausePendingStop && this.currentAutoScrollSpeedPxPerSecond <= this.speedStopThresholdPxPerSecond) { if (this.isPausePendingStop && this.currentAutoScrollSpeedPxPerSecond <= this.speedStopThresholdPxPerSecond) {
@@ -353,7 +366,17 @@ export class TechStackCarousel implements AfterViewInit, OnDestroy {
this.currentAutoScrollSpeedPxPerSecond = 0; this.currentAutoScrollSpeedPxPerSecond = 0;
this.targetAutoScrollSpeedPxPerSecond = 0; this.targetAutoScrollSpeedPxPerSecond = 0;
this.lastAutoScrollTime = 0; this.lastAutoScrollTime = 0;
this.lastFadeStateUpdateTime = 0;
this.syncAutoScrollState(); this.syncAutoScrollState();
} }
private readonly onVisibilityChange = (): void => {
if (document.hidden) {
this.pauseAutoScrollImmediately();
return;
}
this.scheduleResume(320);
};
} }