zachleat / idea-book

A public dump of ideas for side projects, for public upvoting/downvoting/commenting.
Creative Commons Attribution 4.0 International
24 stars 1 forks source link

Horizontal Overflow Debugger #14

Open zachleat opened 7 years ago

zachleat commented 7 years ago

When working on a responsive design, it’s somewhat common during integration testing to find rendering issues that cause horizontal overflow and horizontal scrollbars.

A lot of the time it isn’t immediately obvious what node is causing the issue (especially if it’s not immediately visible).

I want a bookmarklet that iterates (top down, optimized search) through nodes at the current viewport size to hide the current node and see if the scrollbar goes away. If it does, reinstate the node and iterate over its children. Keep going until you find a leaf node that does this.

This will isolate the node(s) causing the scrollbars, making it easier to debug.

JMPerez commented 6 years ago

I think this snippet does what you are asking for.

function findNodes(root) {
  let nodes = [];
  const children = root.childNodes;
  for (let i = 0; i < children.length; i++) {
    const child = children[i];
    const hasHorizontalScrollbar = child.scrollWidth > child.clientWidth;
    if (hasHorizontalScrollbar) {
      // try hiding it
      const oldDisplay = child.style.display;
      child.style.display = 'none';
      const afterHasHorizontalScrollbar = child.scrollWidth > child.clientWidth;
      // restore
      child.style.display = oldDisplay;
      if (afterHasHorizontalScrollbar) {
        const results = findNodes(child);
        nodes = nodes.concat(results);
      } else {
        nodes.push(child);
      }
    }
  }
  return nodes;
}
console.log(findNodes(document.body));

It returns a list of all the elements causing horizontal scrollbars (there might be more than one on a page). Not sure how to best highlight the elements. At the moment it just prints them out in the console.

Minified it would result in a snippet like this

console.log(function(b){var c=[];b=b.childNodes;for(var d=0;d<b.length;d++){var a=b[d];if(a.scrollWidth>a.clientWidth){var e=a.style.display;a.style.display="none";var f=a.scrollWidth>a.clientWidth;a.style.display=e;f?(a=findNodes(a),c=c.concat(a)):c.push(a)}}return c}(document.body));

Let me know what you think and if you have any ideas to improve it.

zachleat commented 6 years ago

Hey @JMPerez this is great! I think it needs a little love though, looks like the check for a scrollbar are only specific to a single element, which isn’t quite what I was going for. Close though!

Check this: https://jsbin.com/nureliz/edit?html,console,output

You can see two divs there, one overflowing the viewport and one not. The “Overflowing” div should show in the results.

JMPerez commented 6 years ago

I have changed the snippet. This one does work with your example. It checks whether toggling the visibility of a child toggles also the presence of a horizontal scrollbar:

 function findNodes(root) {
    let nodes = [];
    const hasHorizontalScrollbar = root.scrollWidth > root.clientWidth;
    if (hasHorizontalScrollbar) {
      const children = root.childNodes;
      for (let i = 0; i < children.length; i++) {
        const child = children[i];
        if (child.style) {
          // try hiding it
          const oldDisplay = child.style.display;
          child.style.display = 'none';
          const afterHasHorizontalScrollbar = root.scrollWidth > root.clientWidth;;
          // restore
          child.style.display = oldDisplay;
          if (afterHasHorizontalScrollbar) {
            const results = findNodes(child);
            nodes = nodes.concat(results);
          } else {
            nodes.push(child);
          }
        }
      }
    }
    return nodes;
  }
  console.log(findNodes(document.body));