0

I am trying to track the center of a carousel where the elements can be dynamically fully replaced when looping. With the full element replacement in mind, simply watching for the index to change and adding an active class causes a moment of jank while the styles and transitions apply after the carousel has already moved, producing a poor effect.

To overcome this I decided to use CSS to target the 2nd out of 3 elements so that regardless of how the change occurs, the centre of the three should always be targeted via css. Hoever, this isn't working as expected since the nth-child doesn't appear to recalculate when I change the targetted set of elements via JavaScript.

I have reduced the example to find that the nth-child css rule I'm using doesn't appear to be recalculated when changing the set of active elements using JavaScript.

For example:

set of five elements, three of which have the additional active class. Targeting nth-child(3n+2) to aim at the middle of the three active classes at all times.

On a button press, a javascript function removes the first active class and applies it to the next non-active element instead.

Expected: the new centre element should be selected by the nth-child css selector Actual: the css rules remain applied to the same element and do not get updated with what should be the new position.

Visually, the effect looks like this:

Before button press:

Initial state with correct nth-child selected (red)

After button press:

After first buttno press, first active class has been removed and avtive has been added to the next non-active element. Expect nth-child to select the middle of the new trio

Here's my test case code, It's a simple as I can get it and replicates exactly the behaviour I'm seeing in my real-world case.

// extremely crude but always have 3 active blocks and shift them by 1 on each button press, n.b. it doesn't wrap so it'll just break if you go off the end.
nav = e => {
  var active = document.querySelectorAll('.stuff.active');

  var first = active[0];
  var last = active[2];
  first.classList.remove('active');

  document.querySelector('.active + :not(.active)').classList.add('active');

}
.list-of-stuff {
  height: 450px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
}

.stuff {
  flex-grow: 1;
  background-color: blue;
}

.active {
  background-color: green;
}

.active:nth-child(3n+2) {
  background-color: red;
}

button {
  display: block;
  background: orange;
  color: white;
  border: 0;
  outline: 0;
  padding: 10px 15px;
  margin-bottom: 10px;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <button onclick="nav()">go</button>

  <div class="list-of-stuff">
    <div class="stuff active"></div>
    <div class="stuff active"></div>
    <div class="stuff active"></div>
    <div class="stuff"></div>
    <div class="stuff"></div>
    <div class="stuff"></div>
    <div class="stuff"></div>
    <div class="stuff"></div>
    <div class="stuff"></div>
    <div class="stuff"></div>
  </div>

</body>

</html>

Live example:

https://jsbin.com/qeyoyux/edit?html,css,js,console,output

Kobe
  • 6,226
  • 1
  • 14
  • 35
Peter Mellett
  • 542
  • 5
  • 18
  • 1
    Possible duplicate of [nth-child doesn't respond to class](https://stackoverflow.com/questions/5428676/nth-child-doesnt-respond-to-class) and [Can I combine :nth-child() or :nth-of-type() with an arbitrary selector?](https://stackoverflow.com/questions/5545649/can-i-combine-nth-child-or-nth-of-type-with-an-arbitrary-selector) – Pete Jul 12 '19 at 10:40
  • Oh you might be right, I didn't come across that while searching – Peter Mellett Jul 12 '19 at 10:42

0 Answers0