Laggy element position update on mobile scrolling
Asked Answered
E

2

8

I'm trying to make a sticky header + first column table. Works fine on desktop browsers.

However, when I scroll the table's x-axis on a mobile device, the position update is dragging i.e. not fast enough.

I've read various SO-threads that suggest iScroll. I'm not really sure how to use it appropriately in this case. Should intercept the tbody scroll event, perevent the default behaviour and update the position based on iScroll's event values? Please point me in the right direction here :)

$(function() {
  var $tbody = $('tbody');

  $tbody.on('scroll', function(e) { 
    var left = $tbody.scrollLeft();
    $('thead').css('left', -left); 
    $('tbody td:nth-child(1), thead th:nth-child(1)').css('left', left);
  });

  var iScroll = new IScroll($tbody[0], { probeType: 3 });
  iScroll.on('scroll', function(){
    console.log('not fired?');
  });
});

https://jsfiddle.net/97r799gr/

To reproduce the problem, it's probably easiest for you to visit https://jsfiddle.net/97r799gr/show on your mobile. I'm using an SGS7 edge so I think this will be reproducible on pretty much any mobile device.

Ed answered 30/1, 2017 at 8:34 Comment(14)
I will go on a guessig spree and say that the use of selectors is extremely inneficient. Try storing the results into variables.Throckmorton
@IsmaelMiguel Could have been the case, but it's not :)Ed
You could try replacing every single td:nth-child(1) with td:first-child. Then, add var $thead= $('thead'); under the var $tbody. $('thead').css('left', -left); can be replaced with $thead.css('left', -left);. Then, replace $('tbody td:nth-child(1), thead th:nth-child(1)') with $tbody.find('td:first-child').css('left', left); $thead.find('th:first-child').css('left', left);. This should work and speed up things a bit. You could go a bit further and store those results into a varThrockmorton
Actually, the simplest answer is: Just use datatables! Here's what you want to implement: datatables.net/extensions/fixedcolumns/examples/initialisation/… It is one heavy plugin, but does anything you need with the table.Throckmorton
@IsmaelMiguel Thanks, but the problem is that the datatables plugin is rather laggy on a mobile device too...Ed
Then there's something else burning CPU timeThrockmorton
I just tested this on my mac laptop in safari 10.0.2 and it is super laggy as well - so not just mobile!Bullion
A different approach might be to make the table scrollable (instead of the page) and set the names set as position absolute (using js to calculate there position on page load / resize).Umbria
Check here, this may help you. #3402795 You may also be interested in datatables.net/extensions/fixedcolumnsSignifics
I have done something similar, but I'm using Zurb's Foundation. Have a look at their responsive table plugin here: zurb.com/playground/responsive-tablesHolyhead
@WimMertens Still only one axis though? I need both a sticky header and first columnEd
@Johan, yes you're right. Found this post, might be useful: #21449839 check the fiddle in the answer: jsfiddle.net/mayekarsaurabh/7w8TC/52Holyhead
@WimMertens Thanks, but it's the same solution more or less :/ The difference beeing using js for the y axis instead of x...Ed
@WimMertens a little laggy on anroid. But it works!Pettigrew
P
2

IScroll uses a wrapper with fixed dimensions with one scrollable content in it. Therefore we can't use tbody as a wrapper. We should wrap the whole table and hold desired elements with CSS when scrolling.

I've created a fiddle with iscroll-probe.js code in it (iscroll.js hasn't got a scroll event). Bad news is that it works only on my iPhone. Scrolling is suddenly stops when scrolling it on my android5.1 device.

// main code
$(document).ready(function(){ 
  $('#pos').text('initialize iscroll');
  try{
    var iScroll = new IScroll('#wrapper', { 
      interactiveScrollbars: true, 
      scrollbars: true, 
      scrollX: true, 
      probeType: 3, 
      useTransition:false, 
      bounce:false
    });
  } catch(e) {
    $('#error').text('Error ' + e.name + ":" + e.message + "\n" + e.stack);
  }

  $('#pos').text('initialized');

  iScroll.on('scroll', function(){
    var pos = $('#scroller').position();
    $('#pos').text('pos.left=' + pos.left + ' pos.top=' + pos.top);

    // code to hold first row and first column
    $('#scroller th:nth-child(1)').css({top: (-pos.top), left: (-pos.left), position:'relative'});
    $('#scroller th:nth-child(n+1)').css({top: (-pos.top), position:'relative'});

    $('#scroller td:nth-child(1)').css({left: (-pos.left), position:'relative'});
  });
});

https://jsfiddle.net/0qv1kjac/11/

Pettigrew answered 3/2, 2017 at 19:44 Comment(5)
Awesome, this looks promising! Any ideas about the android problem though? I'm experiencing it tooEd
I can't improve the answer any more. It is a known issue. github.com/cubiq/iscroll/issues/91 and github.com/cubiq/iscroll/issues/751 can possibly help you.Pettigrew
Ah I see. Thanks a lot for your help, appreciate it!Ed
@Ed This does not work on desktop (at least not macOS Sierra, Chrome 55). You're ok with an iPhone-only solution?Hilburn
@Hilburn Yeah, my main concern was the iPad actually. Thanks for asking :) Also, it works fine on latest Chrome on windows 10.Ed
C
0

I wasn't able to make it work with pure CSS, so I decided to remove iScroll and rewrite the javascript in vanilla js. It works fine on my iphone now. I don't have an android to test with.

New fiddle: https://jsfiddle.net/66a1b2rw/

Everything is the same as your original fiddle except the js:

updated js

var tbody = document.querySelector('tbody');
var thead = document.querySelector('thead');
var firstCol = document.querySelectorAll('tbody td:nth-child(1), thead th:nth-child(1)');
console.log(firstCol);
tbody.addEventListener('scroll', function() {
    var left = tbody.scrollLeft;
  thead.style.left = '-' + left + 'px';
  firstCol.forEach(function(x) {x.style.left = left + 'px'})
})
Cubism answered 2/2, 2017 at 3:59 Comment(1)
Thanks for the suggestion. I'm afraid this didn't help much for me though. I think you need to resort to a third party framework like iScroll to intercept the native scrolling eventEd

© 2022 - 2024 — McMap. All rights reserved.