3

I have a list done with CSS FlexBox. I have assigned by some criteria order to all flexbox items, so the list is visually sorted. Also I have a button that toggles flex-direction of flexbox container, so I can revert the presentation order. I have limited space, so using overflow-y: scroll; and when I'm reverting visual order of the list with flex-direction, element with order: 1 is being scrolled into the viewport. So when it's on top (flex-direction: column;) - scroll in the the beginning of container (there are 10 items in the list),

but when I apply flex-direction: column-reverse; - I can still see this element, but now scroll is in the bottom of container:

Why is the scroll following the element with lowest order property?

Here is my code in Relative codepen or inlined below

HTML

<div class="alternator">
  <button>Reverse order</button>
</div>

<div class="wrapper">
  <div class="item a10">10 away</div>
  <div class="item a2">2 upon</div>
  <div class="item a3">3 a</div>
  <div class="item a4">4 time</div>
  <div class="item a5">5 in</div>
  <div class="item a6">6 a</div>
  <div class="item a7">7 galaxy</div>
  <div class="item a1">1 once</div>
  <div class="item a8">8 very</div>
  <div class="item a9">9 far</div>
</div>

CSS

.wrapper {
  display: flex;
  flex-direction: column;
  overflow-y: scroll;
  max-height: 350px;
  border: 2px solid green;
  width: 150px;
}

.wrapper.reversed {
  flex-direction: column-reverse;
}

.item {
  height: 30px;
  padding: 20px;
}

.a1{order: 1;}
.a2{order: 2;}
.a3{order: 3;}
.a4{order: 4;}
.a5{order: 5;}
.a6{order: 6;}
.a7{order: 7;}
.a8{order: 8;}
.a9{order: 9;}
.a10{order: 10;}

button {
  margin-bottom: 20px;
  width: 150px;
  height: 30px;
}

JS

const btn = document.querySelector('.alternator button');
const list = document.querySelector('.wrapper');

btn.addEventListener('click', () => {
  list.classList.toggle('reversed');
})

UPDATE As answer below deals with scrolling side, I must add here that flex-direction: *-reverse works like order property - namely only visually changes the order of elements, so first element in DOM tree remains there after rendering:

“Note: The reordering capabilities of flex layout intentionally affect only the visual rendering, leaving speech order and navigation based on the source order. This allows authors to manipulate the visual presentation while leaving the source order intact for non-CSS UAs and for linear models such as speech and sequential navigation.” - Ordering and Orientation

Reference from MDN.

zmii
  • 4,123
  • 3
  • 40
  • 64
  • I don't think the problem is related to the `order` property. I believe it's related to the `column-reverse` value. Are you aware that the vertical scrollbar itself, in `column-reverse`, doesn't work in Firefox and IE? Check your code in those browsers. Also see this post: https://stackoverflow.com/q/34249501/3597276 – Michael Benjamin Jun 12 '18 at 22:38

2 Answers2

1

I'm not sure why exactly this is, but I'm thinking it has to do with that the scroll works in that way - it starts out at the first element in the DOM.

According to MDN concerning the target of scroll (https://developer.mozilla.org/en-US/docs/Web/Events/scroll):

The event target (the topmost target in the DOM tree).

But here's a little hack that might fix it:

add item 0 to the top of the list <div class="item a0">000</div> and then do the following:

btn.addEventListener('click', () => {
    list.classList.toggle('reversed');
    if(list.classList.contains('reversed') ){
        list.children[0].style.order = 100;
    } else {
        list.children[0].style.order = 0;
    }
    list.children[0].scrollIntoView();
});
Winter
  • 2,407
  • 1
  • 19
  • 28
  • hi, @Winter. Can you please point me where this is written in documentation or some good article: `scroll works in that way - it starts out at the first element in the DOM.` ? – zmii Jun 12 '18 at 09:48
  • 1
    Well, I found a little hint in the MDN documentation on scroll. I have updated my answer. Hope it helps. – Winter Jun 12 '18 at 10:19
0

Use an extra div inside the (scrollable) wrapper as the flexbox container.

HTML

<div class="wrapper">    <-- scrollable
    <div>                <-- flexbox container
        <div></div>
        <div></div>
        ...
        <div></div>
    <div>
<div>    

CSS

.wrapper {
  overflow-y: scroll;
  max-height: 350px;
  border: 2px solid green;
  width: 150px;
}
.wrapper > div {
  display: flex;
  flex-direction: column;
}
.wrapper.reversed > div {
  flex-direction: column-reverse;
}

CodePen example

close
  • 77
  • 1
  • 8