Hovering Over Flexbox Columns Moves Them Together

Viewed 67

I'm trying to hover over each column on the right side and have them expand while the rest contract. The issue is if the purple one is currently transitioning to a contracted state, and I quickly hover over to the blue one, they all contract.

The goal would be to have the blue one simultaneously open while the others contract. Open to using JS.

Here's an example, try having purple fully expanded and then quickly going to the blue column:

https://codepen.io/niko-dellic/pen/MWvvGMz

#wrapper {
  height: 100vh;
  display: flex;
  flex-direction: row;
  transition: 1s ease-in-out;
}

#wrapper>* {
  flex: 0 1 2vw;
  /* outline: 0; */
  transition: 1s ease-in-out;
  border: 1px solid black;
}

#wrapper>div:hover {
  /* flex: 1 1 33vw; */
  flex-grow: 1;
  transition: 1s ease-in-out;
}

#wrapper>#open {
  /* flex: 1 1 1vw; */
  flex-grow: 2;
  transition: 1s ease-in-out;
}

#wrapper>#closed {
  transition: 1s ease-in-out;
}
<div id="wrapper">
  <div class='chapter' style="background-color:red;"></div>
  <div class='chapter' id="open"></div>
  <div class='chapter' style="background-color:blue;"></div>
  <div class='chapter' style="background-color:green;"></div>
  <div class='chapter' style="background-color:purple;"></div>
</div>

1 Answers

Never occurred to me that css Transitions/animations might mess up your css hover pseudo states.

You could certainly mitigate these issues, by decreasing the transition timings. (or rather prevent undesired display states)

Honestly, I'm not a browser/css rendering engine developer, but I assume, the constantly changing hover area during transition is causing this behaviour.
Besides, I pretty sure this is a deliberately implemented behaviour to prevent too many width calculations while transitioning between 2 flex-grow: states.

However, I assume you want to populate your collapsible/expandable containers with content (text, images etc.). From a usability and accessibility point of view, you should use a layout transition / animation based on a click event anyway.

You're basically searching for a horizontal accordion concept thats collapsing or expanding your contents. I found this pen by Arjan Jassal that might be a good template pen by Arjan Jassal

Here is a vanilla js version.

var sections = document.querySelectorAll('.li-acc-hor');

function toggleAccordion(sections, current) {
    if(sections.length){
        for (var i=0; i<sections.length; i++){
              sections[i].classList.remove('active');
        }
        current.classList.add('active');
    }
}

if(sections.length){
    for (var i=0; i<sections.length; i++){
        sections[i].addEventListener('click', function(e){
            var thisBtn = e.target.closest('.li-acc-hor');
            toggleAccordion(sections, thisBtn);         
        } )
    }
}
* {
  box-sizing: border-box;
}

body {
  font-family: "Segoe UI";
  font-size:1vw;
}

ul {
  display: flex;
  min-height: 100vh;
  max-height: 100vh;
  margin: 0;
  padding: 0;
  overflow: hidden;
  list-style-type: none;
}

li {
  flex: 1;
  display: flex;
  align-items: stretch;
  padding: 0.1vw;
  background: #E74C3C;
  cursor: pointer;
  transition: all 0.5s ease;
}

li:hover {
  background: #e53f2e;
}
li.active {
  flex: 5;
  background: #fff;
  cursor: default;
}
li.active h2 {
  color: #E74C3C;
}
li.active .section-content {
  flex: 4;
  opacity: 1;
  transform: scaleX(1);
  color: #E74C3C;
}
li .section-title {
  flex: 1;
  display: flex;
  align-items: center;
  width: 100%;
  margin: 0;
  padding: 0;
  text-align: center;
  color: white;
}
li .section-title h2 {
  margin: 0;
  transform: rotate(-90deg);
  white-space: nowrap;
}
li .section-content {
  flex: 1;
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0;
  opacity: 0;
  transition: all 0.25s 0.1s ease-out;
}
<ul class="ul-acc-hor">
  <li class="li-acc-hor">
    <div class="section-title">
      <h2>Section 1</h2>
    </div>
    <div class="section-content">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Suscipit voluptatum temporibus dicta reprehenderit tempore quisquam consequuntur porro omnis laboriosam praesentium at et sapiente, provident sit! Suscipit recusandae, ab ratione dignissimos.</p>
    </div>
  </li>
  <li class="li-acc-hor active">
    <div class="section-title">
      <h2>Section 2</h2>
    </div>
    <div class="section-content">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempora totam delectus, eius nostrum aspernatur voluptas enim fugit ipsa magni voluptatem, odio sit accusamus vel id, commodi consequuntur possimus repellat necessitatibus!</p>
    </div>
  </li>
  <li class="li-acc-hor">
    <div class="section-title">
      <h2>Section 3</h2>
    </div>
    <div class="section-content">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Pariatur saepe vel facilis quae nihil ad aspernatur ex delectus. Tenetur nulla voluptates similique quos, quia possimus, magnam esse natus quis ipsa.</p>
    </div>
  </li>
  <li class="li-acc-hor">
    <div class="section-title">
      <h2>Section 4</h2>
    </div>
    <div class="section-content">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, optio illo, delectus deleniti animi accusamus. Laboriosam maiores totam provident aliquam. Unde, incidunt amet officia a obcaecati, ducimus at molestiae nemo.</p>
    </div>    
  </li>
</ul>

Benefits adding javaScript instead of "css-only"

  1. Hover/Mouseover states aren't properly available on mobile/touch devices. Working with click events let you add/toggle visibility related attributes (e.g. css classes or ARIA-attributes)
  2. Using click events for contextual "content delivery" prevents undesired displays of content (e.g if a user accidentally moves the mouse cursor while reading the previously hovered content section)
Related