lenis icon indicating copy to clipboard operation
lenis copied to clipboard

Idea: Auto wrapper and content detection

Open drewbaker opened this issue 1 year ago • 11 comments

We've built similar things to Lenis before, and the way we did it was to detect which element was trying to be scrolled, the same way your browser would do it. So rather than having settings like wrapper and content we would do something like the below code on mouse wheel event.

The big advantage to this approach was we could enable it once, and not have to worry about init/destroy on modals/overlays etc... My guess is 99% of people are using Lenis to replace scrolling on the entire site, not just one scrolling element.

Anyway, I thought this might help and inspire a new wrapper setting of auto perhaps.

/**
 * Figures out if an element has scrollbars
 * https://stackoverflow.com/a/42681820/503546
 * @param {HTMLElement} element
 * @returns {object}
 */
function isScrollable(el) {
  const style = getComputedStyle(el);

  const hidden = style.overflow === "hidden";
  const xHidden = style.overflowX === "hidden";
  const yHidden = style.overflowY === "hidden";

  // If overflow:hidden, then no scorll bars ever
  if (hidden) {
    return {
      x: false,
      y: false
    };
  }

  // Calculate if element is overflowing
  var y1 = el.scrollTop;
  el.scrollTop += 1;
  var y2 = el.scrollTop;
  el.scrollTop -= 1;
  var y3 = el.scrollTop;
  el.scrollTop = y1;
  var x1 = el.scrollLeft;
  el.scrollLeft += 1;
  var x2 = el.scrollLeft;
  el.scrollLeft -= 1;
  var x3 = el.scrollLeft;
  el.scrollLeft = x1;
  let x = x1 !== x2 || x2 !== x3;
  let y = y1 !== y2 || y2 !== y3;

  // Force no scrollbars if set as hidden in CSS
  if (xHidden) {
    x = false;
  }
  if (yHidden) {
    y = false;
  }

  return {
    x,
    y
  };
}

/**
 * Finds the scrollable ancestors of an element in the correct direction
 * @param {HTMLElement} element
 * @returns {HTMLElement}
 */
function getScrollParent(direction, element) {
  // Check upwards to find out if that is a scrollable
  // element in the correct direction
  for(var parent = element; parent; parent = parent.parentElement) {
    if(getScrollable(direction, parent))  return parent;
  }
}

drewbaker avatar Feb 05 '23 16:02 drewbaker