Below is my solution. This leverages the browser's own scrolling mechanisms and adds minimal runtime overhead, so scrolling stays lightweight, portable, and efficient. The caller includes this script and then says something like:
<script>
// This must be during the bubble phase (i.e., last argument =
// false) so that inner objects have an opportunity to override it.
document.addEventListener('touchmove', function(e) { e.preventDefault(); }, false);
var scroller = document.getElementById('scroller');
preventOverScroll(scroller);
</script>
at the bottom of the HTML document.