Scrolling with an easing function
Now assuming you simply just want to use standard APIs and ES6 (because from a cross-browser point of view, this code isn't guaranteed to work)...


onClick is unnecessarily pulled out. You can just inline it. Also, I believe return false are unnecessary when you already have preventDefault. You wouldn't want to prevent bubbling as something else might be delegating their handlers.

document.addEventListener('DOMContentLoaded', () =&gt;  {
    document.querySelector('#foo').addEventListener('click', e =&gt; {
      event.preventDefault();
      scroll(400);
    }, false);
});

Variable declarations are also unnecessarily separated. It's not like they're defined somewhere in the middle (where you sometimes need to pull them up for visibility).

var start = performance.now();
var travelled = 0;
var html = document.querySelector('html');

Pull out your move function from your scroll. What happens is that every call to scroll, you're creating move.
I also suggest you schedule you call requestAnimationFrame first thing in the callback. That's so your code won't hold up the scheduling of the next frame. Should you want to bail out, you can always use cancelAnimationFrame.
Math.floor can be substituted by | 0 (bitwise or). Under the hood, it transforms the number from float to int, dropping the decimals. It's fast one some engines, but your mileage may vary.
Your "bail out" conditions can simply be combined:

if((1 - fractionDone) &lt;= 0 || window.scrollY + window.innerHeight === html.offsetHeight) return