Wpadki i wypadki #12

Zapraszam na kolejne Wpadki i wypadki!

Dzisiaj na tapet wzięty zostanie wzorzec, który swego czasu już omawiałem: nawigacja na stronie typu one-page, płynnie przewijająca do odpowiednich sekcji na stronie. Zacznijmy od prostego przykładu:

<nav class="navigation">
	<ul class="navigation__menu menu">
		<li class="menu__item">
			<a href="#" id="about-me-link" class="menu__link">About me</a>
		</li>
		<li class="menu__item">
			<a href="#" id="offer-link" class="menu__link">Offer</a>
		</li>
		<li class="menu__item">
			<a href="#" id="contact-link" class="menu__link">Contact</a>
		</li>
	</ul>
</nav>
[…]
<script src="http://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script>
	$( '.menu__link' ).on( 'click', ( evt ) => {
		const targetId = evt.target.id.replace( /-link$/, '' );
		const target = $( '#' + targetId );

		$( 'html, body' ).animate({
			scrollTop: target.offset().top
		} );
	} );
</script>

Tego typu rozwiązanie spotykam na sporej liczbie stron, które wrzucane są do oceny na grupach na FB czy forach. Choć działa, jest z nim szereg problemów:

  • URL-e są częścią UI. Psując kotwice do poszczególnych sekcji strony, psujemy tak podstawowe rzeczy, jak m.in. możliwość podzielenia się linkiem do konkretnej sekcji naszej strony, np. kontaktu.

  • Brak poprawnego URL-a obniża znacząco także i użyteczność strony, nie pozwalając choćby otworzyć danej sekcji w nowej karcie. Bardzo często klikam linki w nawigacji kółkiem myszy i bardzo nie lubię, gdy okazuje się, że link w nawigacji przeniósł mnie nigdzie.

  • Co więcej, uzależniamy działanie naszej nawigacji od działania JS-a – a ten lubi się wysypać. Ba, nawigacja zacznie działać dopiero, gdy JS się wczyta, więc skonsternowany użytkownik może przez kilka sekund klikać w niedziałające odnośniki. A jeśli jest bardziej paranoiczny i ma włączonego choćby NoScripta, to linki nigdy nie zaczną działać.

  • Bez zmiany URL-a nie zmienia się także focus na stronie. A to oznacza, że zostaje w menu. Można to łatwo przetestować na przykładzie, po prostu naciskając Tab po przejściu do dowolnej sekcji. Zamiast przenieść focus na przycisk wewnątrz danej sekcji, zostaniemy przerzuceni z powrotem na górę strony, do nawigacji. Istnieją co prawda obejścia tego problemu, ale nie rozwiązują one z kolei pozostałych wymienionych problemów, zwłaszcza braku zmiany URL-a.

Jak zatem zrobić taką nawigację poprawnie? Oto przykład:

<style>
	html, body {
		scroll-behavior: smooth;
	}
</style>
[…]
<nav class="navigation">
	<ul class="navigation__menu menu">
		<li class="menu__item">
			<a href="#about-me" class="menu__link">About me</a>
		</li>
		<li class="menu__item">
			<a href="#offer" class="menu__link">Offer</a>
		</li>
		<li class="menu__item">
			<a href="#contact" class="menu__link">Contact</a>
		</li>
	</ul>
</nav>
[…]
<script>
	if ( !( 'scrollBehavior' in document.documentElement.style ) ) {
		import( 'https://unpkg.com/smoothscroll-polyfill@0.4.4/dist/smoothscroll.js' ).then( () => {
			document.querySelector( '.navigation' ).addEventListener( 'click', ( evt ) => {
				const link = evt.target.closest( '.menu__link' );

				if ( !link ) {
					return;
				}

				evt.preventDefault();

				const scrollToElement = link.getAttribute( 'href' );

				document.querySelector( scrollToElement ).scrollIntoView( {
					behavior: 'smooth' }
				);

				location.href = scrollToElement;
			} );
		} );
	}
</script>
  • Wszystkie linki w nawigacji mają poprawne URL-e, dzięki czemu można je udostępnić czy otworzyć w nowej karcie.

  • Dzięki poprawnym URL-om odpada także problem uzależnienia działania nawigacji od JS-a. Jeśli JS z jakiegoś powodu się nie doczyta, linki w nawigacji będą dalej działać. I to działać od samego początku, bez konieczności czekania na doczytanie jakiegokolwiek skryptu.

  • Skoro kliknięcie na link w nawigacji zmienia hash w adresie, focus jest poprawnie przenoszony. Teraz, gdy naciśnie się Tab, przycisk w danej sekcji dostanie focus. Nie jesteśmy już dłużej przenoszeni z powrotem do nawigacji.

Co więcej, poprawnie zrobiony link tego typu nie potrzebuje ani linijki JS-a. Wszystko dzięki (nie tak już znowu) nowej własności CSS: scroll-behavior: smooth;. Wsparcie dla niej jest bardzo dobre. A jeśli już koniecznie musimy też zapewnić wsparcie dla Safari, można dołączyć dla niego (i tylko niego) polyfilla – co robi skrypt z przykładu. W przypadku IE myślę, że można sobie darować płynne przewijanie.

I to by było na tyle!

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.