0

I'd like to change the color of my visual navigation, based on what "productcard" is visible in screen. It looks like this on my webpage (only on tablet and mobile):

enter image description here

Is there a way with javascript to make the 2nd, 3rd of 4th circle the darker grey based on what product is in viewport?

My markup right now is:

  .usp-radio {
   display: none!important;
  }
  .usp-container {
   display: flex;
   justify-content: normal;
   flex-wrap: nowrap;
   overflow-x: auto;
   scroll-snap-type: x mandatory;
  }
   .usp-container::-webkit-scrollbar {
  display: none;
 }  
  .usp-item {
   flex: 0 0 auto;
   max-width: none!important;
   width: 100%;
   scroll-snap-align: start;
  }
  .usp-text {
   max-width: 260px;
   display: block;
   margin: 0 auto;
   padding-bottom: 15px;
  }
  #usp-1-button:checked ~ .usp-container .usp-item {
   transform: translateX(0%);
   transition: transform 0.3s ease-in-out;
  }
  #usp-2-button:checked ~ .usp-container .usp-item {
   transform: translateX(-100%);
   transition: transform 0.3s ease-in-out;
  }
  #usp-3-button:checked ~ .usp-container .usp-item {
   transform: translateX(-200%);
   transition: transform 0.3s ease-in-out;
  }
  #usp-4-button:checked ~ .usp-container .usp-item {
   transform: translateX(-300%);
   transition: transform 0.3s ease-in-out;
  }
  .content-container.usp-flex {
   display: flex;
   flex-wrap: wrap;
   justify-content: center;
  }
  .usp-radio + label {
   background-color: #C5C5C5;
   width: 10px;
   height: 10px;
   border-radius: 50%;
   order: 2;
   margin: 0px 2.5px;
  }
   .usp-radio:checked + label {
   background-color: #707070;
  }
<div class="content-container usp-flex">
  <input type="radio" id="usp-1-button" class="usp-radio" name="usp-slide" checked/>
  <label for="usp-1-button"></label>
  <input type="radio" id="usp-2-button" class="usp-radio" name="usp-slide"/>
  <label for="usp-2-button"></label>
  <input type="radio" id="usp-3-button" class="usp-radio" name="usp-slide"/>
  <label id="usp-3-label" for="usp-3-button"></label>
  <input type="radio" id="usp-4-button" class="usp-radio" name="usp-slide"/>
  <label id="usp-4-label" for="usp-4-button"></label>
 <div class="usp-container" style="order: 1;">
  <div id="usp-1" class="usp-item">
   <div><img src="https://www.voordeeluitjes.nl/Images/freeValues/userpanel-door.jpg" width="52" height="52"/></div>
   <div style="margin: 20px 0px 10px 0px;"><span class="usp-title">Uniek kijkje achter de schermen</span></div>
   <div><span class="usp-text">Doe mee aan een panelsessie en krijg direct een kijkje achter de schermen.</span></div>
  </div>
   <div id="usp-2" class="usp-item">
   <div><img src="https://www.voordeeluitjes.nl/Images/freeValues/userpanel-feedback.jpg" width="52" height="52"/></div>
   <div style="margin: 20px 0px 10px 0px;"><span class="usp-title">Vertel ons over jouw ideale website</span></div>
   <div><span class="usp-text">Geef aan wat voor u belangrijk is en misschien ziet u uw ideeën later terug!</span></div>
  </div>
   <div id="usp-3" class="usp-item">
   <div><img src="https://www.voordeeluitjes.nl/Images/freeValues/userpanel-reiskosten.jpg" width="52" height="52"/></div>
   <div style="margin: 20px 0px 10px 0px;"><span class="usp-title">Reiskosten worden vergoed</span></div>
   <div><span class="usp-text">Komt u bij ons langs op kantoor? Dan vergoeden wij uw reiskosten.</span></div>
  </div>
   <div id="usp-4" class="usp-item">
   <div><img src="https://www.voordeeluitjes.nl/Images/freeValues/userpanel-hotel.jpg" width="52" height="52"/></div>
   <div style="margin: 20px 0px 10px 0px;"><span class="usp-title">Maak kans op een GRATIS verblijf</span></div>
   <div><span class="usp-text">Neemt u deel aan ons gebruikerspanel? Dan maakt u kans op een gratis uitje!</span></div>
  </div>
 </div>
</div>

So it updates when I use the navigation, but I also need it to update when the card is swiped to the left. I saw something that might work in this thread:

Changing color when specific div is visible

However that works for vertical offset/scrolling, not horizontal.

Sybrentjuh
  • 247
  • 3
  • 14
  • How does the swiping work? Please also share the JavaScript code. – Barthy Jun 09 '20 at 13:25
  • The swiping is already in there. It is done with overflow-x: auto and flex: 0 0 auto on the children. The problem is: i have no idea where to start with my JS code on this. My JS knowledge is kind of basic. – Sybrentjuh Jun 09 '20 at 13:46
  • Ah, I just saw the `scroll-snap-type` CSS property. – Barthy Jun 09 '20 at 13:55
  • was my answer able to help you? Do you have more specific questions? I will add comments to the JavaScript code. – Barthy Jun 12 '20 at 08:16
  • 1
    Thank you! To be honest, after searching for a while and reading your comment ( which does work) I concluded it was too much a hassle and removed swiping. Only using next + previous buttons now. Thanks for your answer though, it was what I asked! – Sybrentjuh Jun 12 '20 at 13:28
  • Good to hear! If your question has been answered, please consider also marking my answer as accepted :) – Barthy Jun 12 '20 at 14:38

1 Answers1

2

In my experience carousels usually rely solely on the transform property and don't really use the scroll offset [1] [2] [3]. They use "Touch Events" and sometimes the "Drag and Drop API" to work across all devices and platforms.

However, out of curiosity I adapted your snippet to use the scroll snapping and scroll offset. Note, that the Element.scrollTo() method is not compatible with every browser and might need a polyfill.

Next, the onScroll function relies on a modulus calculation using scrollLeft property. This might lead to some errors or inaccuracies on systems using display scaling.

Finally, this snippet uses a passive scroll event for performance reasons. You might want to test if this is supported.

Note: You can try out the snippet by scrolling horizontally pressing the shift key.

const container = document.querySelector('.usp-container')
const buttons = document.querySelectorAll('input[name="usp-slide"]')

/**
 * This listener calculates the modulo of the scroll position by the visible width.
 * Every time the result equals 0, the scroll position is exactly an integer multiple of the width.
 * This means that the carousel has reached another page.
 * The scroll-snap-type property makes sure that the container snaps perfectly to integer multiple.
 */
const onScroll = function () {

    if (container.scrollLeft % container.offsetWidth === 0) {
        const page = container.scrollLeft / container.offsetWidth                   // the multiples range between 0-3
        const radio = document.getElementById(`usp-${page + 1}-button`)    // radio buttons are numbered 1-4
        radio.click()
    }
}

/**
 * Determine the target page by an HTML data attribute on the radio button.
 * Scroll to the desired position.
 * 
 * @param {MouseEvent} event: Click event used to determine the target/clicked element
 */
const onClick = function (event) {

    const button = event.target
    const targetPage = button.dataset.target

    container.scrollTo({
        left:     targetPage * container.offsetWidth,
        behavior: 'smooth'
    })
}

container.addEventListener('scroll', onScroll, {
    passive: true
})

for (const button of buttons) {
    button.addEventListener('click', onClick)
}
.usp-radio {
  display: none!important;
}

.usp-container {
  display: flex;
  justify-content: normal;
  flex-wrap: nowrap;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}

.usp-container::-webkit-scrollbar {
  display: none;
}

.usp-item {
  display: flex;
  flex: 0 0 auto;
  max-width: none!important;
  width: 100%;
  scroll-snap-align: start;
  transition: transform 0.3s ease-in-out;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.usp-title,
.usp-text {
  max-width: 260px;
  display: block;
  margin: 10px auto;
  padding-bottom: 15px;
  text-align: center;
}

.content-container.usp-flex {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}

.usp-radio+label {
  background-color: #C5C5C5;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  order: 2;
  margin: 0px 2.5px;
}

.usp-radio:checked+label {
  background-color: #707070;
}
<div class="content-container usp-flex">
  <input type="radio" id="usp-1-button" class="usp-radio" name="usp-slide" checked data-target="0" />
  <label for="usp-1-button"></label>

  <input type="radio" id="usp-2-button" class="usp-radio" name="usp-slide" data-target="1" />
  <label for="usp-2-button"></label>

  <input type="radio" id="usp-3-button" class="usp-radio" name="usp-slide" data-target="2" />
  <label id="usp-3-label" for="usp-3-button"></label>

  <input type="radio" id="usp-4-button" class="usp-radio" name="usp-slide" data-target="3" />
  <label id="usp-4-label" for="usp-4-button"></label>

  <div class="usp-container" style="order: 1;">
    <div id="usp-1" class="usp-item">
      <img src="https://www.voordeeluitjes.nl/Images/freeValues/userpanel-door.jpg" width="52" height="52" />
      <span class="usp-title">Uniek kijkje achter de schermen</span>
      <span class="usp-text">Doe mee aan een panelsessie en krijg direct een kijkje achter de schermen.</span>
    </div>
    <div id="usp-2" class="usp-item">
      <img src="https://www.voordeeluitjes.nl/Images/freeValues/userpanel-feedback.jpg" width="52" height="52" />
      <span class="usp-title">Vertel ons over jouw ideale website</span>
      <span class="usp-text">Geef aan wat voor u belangrijk is en misschien ziet u uw ideeën later terug!</span>
    </div>
    <div id="usp-3" class="usp-item">
      <img src="https://www.voordeeluitjes.nl/Images/freeValues/userpanel-reiskosten.jpg" width="52" height="52" />
      <span class="usp-title">Reiskosten worden vergoed</span>
      <span class="usp-text">Komt u bij ons langs op kantoor? Dan vergoeden wij uw reiskosten.</span>
    </div>
    <div id="usp-4" class="usp-item">
      <img src="https://www.voordeeluitjes.nl/Images/freeValues/userpanel-hotel.jpg" width="52" height="52" />
      <span class="usp-title">Maak kans op een GRATIS verblijf</span>
      <span class="usp-text">Neemt u deel aan ons gebruikerspanel? Dan maakt u kans op een gratis uitje!</span>
    </div>
  </div>
Barthy
  • 3,151
  • 1
  • 25
  • 42