johandigital
An image

Creating a Smart Header Visibility Toggle with Svelte

How a website's header behaves during scrolling can significantly affect user experience. Here's a simple yet effective way to hide the header when scrolling down and reveal it when scrolling up, implemented in Svelte.

Johan

2024 | 12 | 23

Creating a seamless and responsive web experience often comes down to the finer details. One subtle yet effective touch is dynamically hiding and showing the header based on user scroll behavior. This blog post explores how you can achieve this smart functionality using Svelte.

The idea

The goal is to dynamically hide the header when the user scrolls down and reveal it when scrolling up. This makes the interface less intrusive while still keeping the header easily accessible.

The code

Here’s the complete Svelte component that handles the header visibility toggle:

<script>
	let scrollArray = [];
	let style = 'transform: translateY(0);';
	let ticking = false;
	let debounce = false;
	let debounceTimer;
	let scrollTimer;

		const handleScroll = (scrollOffset) => {
		clearTimeout(scrollTimer);
		scrollTimer = setTimeout(() => (scrollArray = []), 1000);

		scrollArray.push(scrollOffset);
		console.log(scrollArray);
		if (scrollArray.length === 5) {
			const stopValue = scrollArray[scrollArray.length - 1];
			const startValue = scrollArray[0];

			if (Math.abs(stopValue - startValue) > 100) {
				style =
					stopValue > startValue ? 'transform: translateY(-100%);' : 'transform: translateY(0);';
			}
			scrollArray = [];
		}
	};

	const hideOrShowHeader = (event) => {
		const scrollOffset = event.target.defaultView.pageYOffset;

		if (scrollOffset < 200) {
			style = 'transform: translateY(0);';
			scrollArray = [];
			ticking = false;
			return;
		}
		if (debounce) return;

		debounce = true;

		if (!ticking) {
			requestAnimationFrame(() => {
				handleScroll(scrollOffset);
				ticking = false;
			});
			ticking = true;
		}
		clearTimeout(debounceTimer);
		debounceTimer = setTimeout(() => {
			debounce = false;
		}, 200);
	};
</script>

<svelte:window on:scroll={(event) => hideOrShowHeader(event)} />

Benefits of this approach

  1. Efficient Handling with Debouncing and Throttling:

    • The debounce mechanism ensures that rapid scrolling doesn't overwhelm the logic.

    • requestAnimationFrame is used to batch DOM updates efficiently.

  2. Adaptive Behavior:

    • The scrollArray collects scroll positions over time, allowing the header's visibility to adapt based on the user's scrolling behavior. For example, it checks if the scroll offset changes significantly over five recorded events.

  3. Reset Logic:

    • A scrollTimer clears the scrollArray after 1 second of inactivity, ensuring no stale data affects future decisions.

  4. Minimal CSS Changes:

    • By toggling only the transform property, we avoid expensive layout recalculations, making the animation smooth.

How It Works

  • The on:scroll event on the <svelte:window> component captures the scroll offset.

  • The handleScroll function calculates whether the user is scrolling up or down.

  • The header’s position is updated dynamically with inline styles.

With this setup, you’ll have a responsive and intuitive header experience that enhances your website's usability. Let me know how you’d use or improve this solution!