diff --git a/js/modal.js b/js/modal.js
index f6dc477b10b880a5302b81ebb71a755751aa9257..454d7d57a35bc7371372b6d065eb4936a4c47178 100644
--- a/js/modal.js
+++ b/js/modal.js
@@ -15,6 +15,7 @@
 
   var Modal = function (element, options) {
     this.options   = options
+    this.$body     = $(document.body)
     this.$element  = $(element)
     this.$backdrop =
     this.isShown   = null
@@ -48,6 +49,9 @@
 
     this.isShown = true
 
+    this.$body.addClass('modal-open')
+
+    this.setScrollbar()
     this.escape()
 
     this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
@@ -56,7 +60,7 @@
       var transition = $.support.transition && that.$element.hasClass('fade')
 
       if (!that.$element.parent().length) {
-        that.$element.appendTo(document.body) // don't move modals dom position
+        that.$element.appendTo(that.$body) // don't move modals dom position
       }
 
       that.$element
@@ -96,6 +100,9 @@
 
     this.isShown = false
 
+    this.$body.removeClass('modal-open')
+
+    this.resetScrollbar()
     this.escape()
 
     $(document).off('focusin.bs.modal')
@@ -153,7 +160,7 @@
       var doAnimate = $.support.transition && animate
 
       this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
-        .appendTo(document.body)
+        .appendTo(this.$body)
 
       this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
         if (e.target !== e.currentTarget) return
@@ -188,6 +195,26 @@
     }
   }
 
+  Modal.prototype.setScrollbar =  function () {
+    if (document.body.clientHeight <= window.innerHeight) return
+    var scrollbarWidth = this.measureScrollbar()
+    var bodyPad        = parseInt(this.$body.css('padding-right') || 0)
+    if (scrollbarWidth) this.$body.css('padding-right', bodyPad + scrollbarWidth)
+  }
+
+  Modal.prototype.resetScrollbar = function () {
+    this.$body.css('padding-right', '')
+  }
+
+  Modal.prototype.measureScrollbar = function () { // thx walsh
+    var scrollDiv = document.createElement('div')
+    scrollDiv.className = 'modal-scrollbar-measure'
+    this.$body.append(scrollDiv)
+    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
+    this.$body[0].removeChild(scrollDiv)
+    return scrollbarWidth
+  }
+
 
   // MODAL PLUGIN DEFINITION
   // =======================
@@ -236,8 +263,4 @@
       })
   })
 
-  $(document)
-    .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') })
-    .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })
-
 }(jQuery);
diff --git a/less/modals.less b/less/modals.less
index 8438a1616a784fcc6ef202ccdfaee805d69a5d76..093d051315dab5f4a282aef1636a6fd6bfa19127 100644
--- a/less/modals.less
+++ b/less/modals.less
@@ -118,6 +118,15 @@
   }
 }
 
+// Measure scrollbar width for padding body during modal show/hide
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll;
+}
+
 // Scale up the modal
 @media (min-width: @screen-sm-min) {
   // Automatically set modal's width for larger viewports