relacje.

Ten wzorzec pokazuje, jak utworzyć komponent Relacje na stronie internetowej, który jest elastyczny, obsługuje nawigację za pomocą klawiatury i działa w różnych przeglądarkach.

Pełny artykuł · Film w YouTube · Źródło: GitHub

HTML

<div class="stories">    <section class="user">     <article class="story" style="--bg: url(https://picsum.photos/480/840);"></article>      <article class="story" style="--bg: url(https://picsum.photos/480/841);"></article>   </section>   <section class="user">     <article class="story" style="--bg: url(https://picsum.photos/481/840);"></article>   </section>   <section class="user">     <article class="story" style="--bg: url(https://picsum.photos/481/841);"></article>   </section>   <section class="user">     <article class="story" style="--bg: url(https://picsum.photos/482/840);"></article>     <article class="story" style="--bg: url(https://picsum.photos/482/843);"></article>     <article class="story" style="--bg: url(https://picsum.photos/482/844);"></article>   </section> </div>

CSS

         .stories {   display: grid;   grid: 1fr / auto-flow 100%;   grid-gap: 1ch;   gap: 1ch;   overflow-x: auto;   scroll-snap-type: x mandatory;   overscroll-behavior: contain;   touch-action: pan-x; }  .user {   scroll-snap-align: start;   scroll-snap-stop: always;   display: grid;   grid: [story] 1fr / [story] 1fr; }  .story {   grid-area: story;    background-size: cover;   background-image:      var(--bg),      linear-gradient(to top, rgb(249, 249, 249), rgb(226, 226, 226));    user-select: none;   touch-action: manipulation;    transition: opacity .3s cubic-bezier(0.4, 0.0, 1, 1) }  .story.seen {   opacity: 0;   pointer-events: none; }         

JS

         const stories = document.querySelector('.stories') const median = stories.offsetLeft + (stories.clientWidth / 2)  const state = {   current_story: stories.firstElementChild.lastElementChild }  const navigateStories = direction => {   const story = state.current_story   const lastItemInUserStory = story.parentNode.firstElementChild   const firstItemInUserStory = story.parentNode.lastElementChild   const hasNextUserStory = story.parentElement.nextElementSibling   const hasPrevUserStory = story.parentElement.previousElementSibling      if (direction === 'next') {     if (lastItemInUserStory === story && !hasNextUserStory)       return     else if (lastItemInUserStory === story && hasNextUserStory) {       state.current_story = story.parentElement.nextElementSibling.lastElementChild       story.parentElement.nextElementSibling.scrollIntoView({         behavior: 'smooth'       })     }     else {       story.classList.add('seen')       state.current_story = story.previousElementSibling     }   }   else if(direction === 'prev') {     if (firstItemInUserStory === story && !hasPrevUserStory)       return     else if (firstItemInUserStory === story && hasPrevUserStory) {       state.current_story = story.parentElement.previousElementSibling.firstElementChild       story.parentElement.previousElementSibling.scrollIntoView({         behavior: 'smooth'       })     }     else {       story.nextElementSibling.classList.remove('seen')       state.current_story = story.nextElementSibling     }   } }  stories.addEventListener('click', e => {   if (e.target.nodeName !== 'ARTICLE')      return      navigateStories(     e.clientX > median        ? 'next'        : 'prev') })  // left & right are free with snap points 👍 document.addEventListener('keydown', ({key}) => {   if (key !== 'ArrowDown' || key !== 'ArrowUp')     navigateStories(       key === 'ArrowDown'         ? 'next'         : 'prev') })