0

While implementing a horizontal scroller for webapp I ran into an unusual and very elegant way to create one with minimal JS code based on a suggestion by @Sitemas3 in this SO thread. One can create a very responsive (in the sense of speed) horizontal scroller by simply reassigning the order attribute of the children in a display:flex container.

No issues thus far. However, for some of horizontal scrollers I have one further requirement. I want to make the first (in the sense of the one displayed on the extreme left of the screen) child element of the scroller wider. Not a problem in itself - just find "which" child element is on the left and add the relevant class to its classList.

There is just one problem - since all I have done perform the scroll is reassign the order attribute the order of the scroller's children in its children attribute no longer reflects their current display position on the screen. This brings me to my question - is there a method that I am unaware of that will provide me the list of children in their display order as opposed to their order in the markup?


Strictly this does not matter - I can always loop through the child elements and apply the additional class as required but in my quest for efficiency I wondered if there is not a DOM method that does the hard lifting for me

A rough example of the way I am doing things is shown below. To summarize

  • I have a position:relative outer container
  • Within it I have a position:absolute inner container

Given that the context here is mobile screens these two containers will always be 100vw

Within the inner container I have the actual contents which consist of

  • A flex box
  • Its children with an assigned order

Try clicking the Rotate Left button to simulate a horizontal scroll from left to right. And then the Rotate Right button to simulate a horizontal scroll from right to left. You will see that the actual scroll happens and the DISPLAY ORDER of the children changes. However, the order of the children in the DOM tree is unchanged.

function elFromId(id){return document.getElementById(id);}

elFromId('rotLeft').addEventListener('click',rotateLeft);
elFromId('rotRight').addEventListener('click',rotateRight);

function rotateLeft()
{
 elFromId('one').style.order = 1;
 elFromId('two').style.order = 2;
 elFromId('three').style.order = 0;
}

function rotateRight()
{
 elFromId('one').style.order = 0;
 elFromId('two').style.order = 1;
 elFromId('three').style.order = 2;
}
.relBox
{
 position:relative;
} 

.absBox
{
 position:absolute;
 left:0;
 top:0;
 right:0;
 bottom:calc(100vh - 50px);
} 

#container
{
 min-height:50px;
 display:flex;
 column-gap:2em;
}

#container > div
{
 display:flex;
 align-items:center;
 justify-content:center;
 font-weight:bold;
 font-size:2em;
~ 
<button id='rotLeft'>Rotate Left</button>
<button id='rotRight'>Rotate Right</button>

<div class='relBox'>
 <div class='absBox'>
  <div id='container'>
   <div id='one' style='order:0'>One</div>
   <div id='two' style='order:1'>Two</div>
   <div id='three' style='order:3'>Three</div>
  </div>
 </div>
</div>
DroidOS
  • 8,530
  • 16
  • 99
  • 171
  • Please could you put an example of your code actually into your question so we can see more plainly how it works. At the moment I'm not understanding why you can't just set the size of the element with order 1 to be larger, so I'm obviously not understanding the method completely. – A Haworth Dec 01 '21 at 16:14
  • There you go - a rough example has been added – DroidOS Dec 01 '21 at 16:31
  • Couple of queries. The snippet isn't doing what I'd expect a slider to do - rotating left on One Two Three ends up with Three Two One where I'd expect it to be Two Three One. Whatever the result of a rotate is it the element which now has order: 0 that you want to be larger? – A Haworth Dec 01 '21 at 16:45
  • You are right - my hastily coded example yesterday was not showing the right "rotate" effect. That has now been corrected. Needless to say, in the real thing the scroller could well have many more than 3 items and swipe left/right will cause the child element order to change in a rather more complex way. However, regardless of complexity it should always be child with `order:0` that should be styled differently. This can be done anyway. However, I am wondering if there is a DOM method somewhere tat returns children in display, not tree/markup, order. – DroidOS Dec 02 '21 at 07:25
  • I can't see how there can be given the order property is purely CSS, not actually 'physicall'y changing anything, only visually reordering. To find the 'visual order' I think you'd need to plod through looking at that property with JS. Will be interesting to see if someone has an alternative approach. – A Haworth Dec 02 '21 at 07:33

0 Answers0