在移动浏览器上打开Bootstrap 3模式时如何防止后台滚动?

时间:2013-09-27 21:25:47

标签: html twitter-bootstrap modal-dialog twitter-bootstrap-3

如何在移动平台上打开Bootstrap 3模式时阻止后台滚动?在桌面浏览器上,阻止后台滚动并按预期工作。

在移动浏览器(Safari ios,Chrome ios等)上,当打开模态并使用手指滚动它时,背景也会像模态一样滚动。我该如何预防?

20 个答案:

答案 0 :(得分:36)

见这里:https://github.com/twbs/bootstrap/issues/7501

所以试试:

$('body').css('overflow','hidden');
$('body').css('position','fixed');

V3.0.0。应该已经解决了这个问题。你使用的是最新版本吗?如果是,请在https://github.com/twbs/bootstrap/

上发布问题

答案 1 :(得分:24)

试试这个,

 body.modal-open {
    overflow: hidden;
    position:fixed;
    width: 100%;
}

答案 2 :(得分:19)

我尝试了接受的答案,这个答案阻止了身体滚动但是滚动到顶部的问题。这应该解决这两个问题。

作为旁注,它似乎是溢出的:只有当iOS Chrome正常工作时,隐藏并不适用于iOS Safari的正文。

public class GameWindow<E> {

private JFrame frame;
static JProgressBar progressBar1;
static JButton upGardenerButton;
private Timer gameTimer;

public static Player player;
public static Worker worker;
private static JLabel labelMoney;
private JTable table;
private JLabel lblMultiplier;
boolean timerStop;

/**
 * Create the application.
 */
public GameWindow() {
    worker = new Worker(50, 75, 5000);
    player = new Player();

    initialize();
}

protected void endGame() {
    frame.dispose();
    timerStop = true;
}

public void StartGame() {
    EventQueue.invokeLater(new Runnable() {

        int gardenerTime = 0;

        public void run() {
            try {
                GameWindow<Object> window = new GameWindow<Object>();
                window.frame.setVisible(true);
                ActionListener taskPerformer = new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                        gardenerTime += 10;
                        progressBar1.setValue(gardenerTime);        
                        if(gardenerTime >= worker.time) {
                            player.money.add(worker.getProfit());
                            gardenerTime = 0;
                        }

                        labelMoney.setText(player.money.getMoney()+"$");    

                        if(gardenerTime % 100 == 0) System.out.println("Timer bezi. " + MenuWindow.gameStarted );

                        if(MenuWindow.gameStarted == false) gameTimer.stop();
                    }
                };

                int delay = 10;
                gameTimer = new Timer(delay, taskPerformer);
                gameTimer.start();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    frame = new JFrame();
    frame.getContentPane().setBackground(UIManager.getColor("Panel.background"));
    frame.setBounds(100, 100, 571, 287);

    WindowListener exitListener = new WindowAdapter() {

        @Override
        public void windowClosing(WindowEvent e) {
            int confirm = JOptionPane.showOptionDialog(
                 null, "Opravdu chceš ukončit hru?", 
                 "Konec?!", JOptionPane.YES_NO_OPTION, 
                 JOptionPane.QUESTION_MESSAGE, null, null, null);
            if (confirm == 0) {
               frame.setVisible(false);
               endGame();
               System.out.println("timerstop: "+timerStop);
               //MenuWindow.open();
            }
        }
    };

    frame.addWindowListener(exitListener);
    frame.getContentPane().setLayout(null);

    progressBar1 = new JProgressBar();
    progressBar1.setBounds(6, 89, 146, 27);
    progressBar1.setStringPainted(true);
    progressBar1.setMaximum(worker.time);
    progressBar1.setMinimum(0);
    progressBar1.setString(worker.getProfit()+"$");
    frame.getContentPane().add(progressBar1);

    upGardenerButton = new JButton(worker.getUpgradeCost()+" $   "+"level "+worker.level);
    upGardenerButton.setBounds(159, 89, 165, 27);
    upGardenerButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            if(player.money.getMoney() >= worker.getUpgradeCost()) {
                worker.upgrade();
            }
        }
    });
    frame.getContentPane().add(upGardenerButton);

    JPanel panel = new JPanel();
    panel.setBounds(6, 37, 175, 32);
    panel.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
    panel.setBackground(Color.LIGHT_GRAY);
    frame.getContentPane().add(panel);
    panel.setLayout(new MigLayout("", "[149px]", "[23px]"));

    labelMoney = new JLabel("");
    labelMoney.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);
    panel.add(labelMoney, "cell 0 0,alignx trailing,aligny baseline");

    JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
    tabbedPane.setBounds(357, 6, 192, 236);
    frame.getContentPane().add(tabbedPane);

    JScrollPane scrollPane = new JScrollPane();
    tabbedPane.addTab("Upgrades", null, scrollPane, null);

    String[] columnNames = {"Upgrades", ""};
    Object[][] data =
    {
        {"Vozík +2",    "2000$"},
        {"Kalhoty +3",  "15000$"},
        {"Šperháky +4", "50000$"},
        {"Auto *2",     "200000$"},
    };

    DefaultTableModel model = new DefaultTableModel(data, columnNames){
         @Override
         public boolean isCellEditable(int row, int column) {
               if(column != 1) return false;
               else return true;
            }
    };
    JTable table = new JTable( model );

    Action upgradeMultiplier = new AbstractAction()
    {
        int count = 0;
        public void actionPerformed(ActionEvent e)
        {
            JTable table = (JTable)e.getSource();
            int modelRow = Integer.valueOf( e.getActionCommand() );                
            String sPrice = (String) table.getModel().getValueAt(modelRow, 1);
            int price = Integer.parseInt(sPrice.substring(0,sPrice.length()-1));    
            String sMultip = (String) table.getModel().getValueAt(modelRow, 0);
            if(sMultip.lastIndexOf("*") != -1) {
                int multip = Integer.parseInt(sMultip.substring(sMultip.lastIndexOf("*")+1,sMultip.length()));
                if(player.money.getMoney() >= price) {
                    player.money.deduct(price);
                    worker.multiplyMultiplier(multip);
                    ((DefaultTableModel)table.getModel()).removeRow(modelRow);  
                }
            } else if(sMultip.lastIndexOf("+") != -1) {
                int multip = Integer.parseInt(sMultip.substring(sMultip.lastIndexOf("+")+1,sMultip.length()));
                if(player.money.getMoney() >= price) {
                    player.money.deduct(price);
                    worker.plusMultiplier(multip);
                    ((DefaultTableModel)table.getModel()).removeRow(modelRow);
                }
            }
            progressBar1.setString(worker.getProfit()+"$");
            lblMultiplier.setText(worker.multiplier+"x");
        }
    };

    ButtonColumn buttonColumn = new ButtonColumn(table, upgradeMultiplier, 1);
    buttonColumn.setMnemonic(KeyEvent.VK_D);

    scrollPane.setViewportView(table);

    JLabel lblMultiplierStatic = new JLabel("Multiplier:");
    lblMultiplierStatic.setBounds(17, 9, 55, 16);
    frame.getContentPane().add(lblMultiplierStatic);

    lblMultiplier = new JLabel("1x");
    lblMultiplier.setBounds(83, 9, 43, 16);
    frame.getContentPane().add(lblMultiplier);

    JButton btnNewButton = new JButton("New button");
    btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            timerStop = true;
        }
    });
    btnNewButton.setBounds(65, 185, 98, 26);
    frame.getContentPane().add(btnNewButton);


}
}

答案 3 :(得分:9)

$('.modal') 
.on('shown', function(){ 
  console.log('show'); 
  $('body').css({overflow: 'hidden'}); 
}) 
.on('hidden', function(){ 
  $('body').css({overflow: ''}); 
}); 

使用这个

答案 4 :(得分:5)

不需要脚本。

BS 3在body上设置一个.modal-open类,可用于设置位置和溢出值(使用LESS)。

body {
    font-family:'Open Sans';
    margin:0;

    &.modal-open {
        position:fixed;
        overflow:hidden;

        .modal { 
            overflow: scroll;

            @media only screen and (min-resolution:150dpi) and (max-width: @screen-sm),
            only screen and (-webkit-min-device-pixel-ratio:1.5) {
                overflow: scroll; 
                -webkit-overflow-scrolling: touch; 
            }
        }
    }   
}

答案 5 :(得分:3)

如果使用jQuery,可以使用scrollTop

执行此操作
  1. 保存正文的垂直滚动位置;
  2. 禁用正文滚动;
  3. 显示模态;
  4. 关闭模式;
  5. 重新启用正文滚动;
  6. 设置已保存的滚动位置。
  7. #modal {
        bottom: 0;
        position: fixed;
        overflow-y: scroll;
        overflow-x: hidden;
        top: 0;
        width: 100%;
    }

    $('.open-modal').click(function (e) {
        e.preventDefault();
        $('#modal').toggle();
        scrollTo = $('body').scrollTop();
        $('body').css("position", "fixed");
    });
    
    $('.close-modal').click(function (e) {
        e.preventDefault();
        $('#modal').toggle();
        $('body').css("position", "static");
        $('body').animate({scrollTop: scrollTo}, 0);
    });

答案 6 :(得分:3)

所选解决方案有效,但它们也会将背景捕捉到顶部滚动位置。我将上面的代码扩展为修复“跳转”。

//Set 2 global variables
var scrollTopPosition = 0;
var lastKnownScrollTopPosition = 0;

//when the document loads
$(document).ready(function(){

  //this only runs on the right platform -- this step is not necessary, it should work on all platforms
  if( navigator.userAgent.match(/iPhone|iPad|iPod/i) ) {

    //There is some css below that applies here
    $('body').addClass('platform-ios');

    //As you scroll, record the scrolltop position in global variable
    $(window).scroll(function () {
      scrollTopPosition = $(document).scrollTop();
    });

    //when the modal displays, set the top of the (now fixed position) body to force it to the stay in the same place
    $('.modal').on('show.bs.modal', function () {

      //scroll position is position, but top is negative
      $('body').css('top', (scrollTopPosition * -1));

      //save this number for later
      lastKnownScrollTopPosition = scrollTopPosition;
    });

    //on modal hide
    $('.modal').on('hidden.bs.modal', function () {

      //force scroll the body back down to the right spot (you cannot just use scrollTopPosition, because it gets set to zero when the position of the body is changed by bootstrap
      $('body').scrollTop(lastKnownScrollTopPosition);
    });
  }
});

css非常简单:

// You probably already have this, but just in case you don't
body.modal-open {
  overflow: hidden;
  width: 100%;
  height: 100%;
}
//only on this platform does it need to be fixed as well
body.platform-ios.modal-open {
  position: fixed;
}

答案 7 :(得分:1)

这可能有点像在这里击败死马......但是,我目前通过vanilla JS实现的DIY模式解决方案:

On modal show:

if (document.body.style.position !== 'fixed') {
    document.body.style.top = -window.scrollY + 'px';
    document.body.style.position = 'fixed';
}

关于模态隐藏:

document.body.style.position = '';
window.scrollTo(0, -parseInt(document.body.style.top, 10));
document.body.style.top = '';

答案 8 :(得分:1)

还有一个问题,iPhone + Safari需要添加:

position: fixed;

如其他地方所述,这创造了一个滚动到顶部的问题。修复对我有用的是在模态打开时捕获位置到顶部,然后在模态关闭时动画到该位置

在模态打开时:

scrollTo = $('body').scrollTop();
$('body').css("position", "fixed");

关于模态关闭

$('body').css("position", "static");
$('body').animate({scrollTop: scrollTo}, 0);

答案 9 :(得分:1)

上述答案没有用,所以我做的是:

.modal {
  -webkit-overflow-scrolling: touch; 
}

我特别的问题是我在加载后增加了模态大小。

这是一个已知的iOS问题,see here。由于它没有破坏任何其他因素,上述解决方案足以满足我的需求。

答案 10 :(得分:1)

我认为您可能忘记将属性data-toggle="modal"添加到触发模态弹出事件的链接或按钮。首先,我也遇到了同样的问题但是,在添加上面的属性后,它对我来说效果很好。

答案 11 :(得分:0)

我找到了一个简单的javascript / jquery解决方案,该解决方案利用了bootstrap模态事件。

我的解决方案还修复了position:fixed问题,它将背景页面一直滚动到顶部,而不是在打开/关闭模态窗口时保持原位。

查看详情here

答案 12 :(得分:0)

我在模态后打开一个模态,事实上模态滚动的错误,这个CSS解决了我的问题:

.modal {
    overflow-y: auto;
    padding-right: 15px;
}

答案 13 :(得分:0)

JDiApice提供,iOS 8.x modal scroll issue #14839合成并扩展了其他贡献者的工作:

@media only screen and (max-device-width:768px) {

body.modal-open {
    // block scroll for mobile;
    // causes underlying page to jump to top;
    // prevents scrolling on all screens
    overflow: hidden;
    position: fixed;
    }
}

body.viewport-lg {
    // block scroll for desktop;
    // will not jump to top;
    // will not prevent scroll on mobile
    position: absolute;
}

body {
    overflow-x: hidden;
    overflow-y: scroll !important;
}

/* The reason the media specific is on there is 
   on a desktop i was having issues with when the modal would open 
   all content on the page would shift from centered to left. 
   Looked like crap. So this targets up to tablet size devices 
   where you would need to scroll. There is still a slight shift 
   on mobile and tablet but its really not much. */

与我们尝试的其他解决方案不同,它在弹出模式关闭后不会将背景滚动到顶部。

答案 14 :(得分:0)

使用position:fixed会产生将身体滚动到顶部的副作用。

如果你的身体没有滚动到顶部,请注意使用position:fixed。如果模态打开,只需在身体上禁用touchmove。 注意:模态本身仍然可以在触摸时滚动(如果大于屏幕)。

CSS:

body.modal-open {
    overflow: hidden;
    width: 100%;
    /* NO position:fixed here*/
}

JS:

$('.modal').on('show.bs.modal', function (ev) { // prevent body from scrolling when modal opens
    $('body').bind('touchmove', function(e){
        if (!$(e.target).parents().hasClass( '.modal' )){ //only prevent touch move if it is not the modal
            e.preventDefault()
        }
    })
})
$('.modal').on('hide.bs.modal', function (e) { //unbind the touchmove restrictions from body when modal closes
    $('body').unbind('touchmove');
})

编辑: 请注意,对于非常小的模态,您可能必须将以下行添加到CSS中:

.modal-dialog{
    height: 100%;
}

答案 15 :(得分:0)

我知道这已经得到了回答,但这些解决方案都不适用于我。我需要采取不同的方法。我正在使用PhoneGap并且我本地编译我的代码所以我不得不将背景移动到正文。我希望这有助于其他人。或者,如果有更简洁的方法,请随时发表评论......

$(document).on('shown.bs.modal', '.modal', function (e) {

    $("#" + e.target.id).find(".modal-backdrop").css("z-index", $("#" + e.target.id).css("z-index")).insertBefore("#" + e.target.id);

});

答案 16 :(得分:0)

嘿伙计们,所以我觉得我找到了解决办法。这对我来说在iphone和android上工作。它是一个小时的搜索,阅读和测试的混搭。因此,如果您在此处看到部分代码,那么信用证会转到您的身上。

@media only screen and (max-device-width:768px){

body.modal-open {
// block scroll for mobile;
// causes underlying page to jump to top;
// prevents scrolling on all screens
overflow: hidden;
position: fixed;
}
}

body.viewport-lg {
// block scroll for desktop;
// will not jump to top;
// will not prevent scroll on mobile
position: absolute; 
}

body {  
overflow-x: hidden;
overflow-y: scroll !important;
}

媒体特定的原因是在桌面上我遇到问题,当模式打开时,页面上的所有内容都会从中心向左移动。看起来像废话。因此,这需要针对您需要滚动的平板电脑尺寸设备。手机和平板电脑仍有轻微转变,但实际上并不多。如果这适用于你们,请告诉我。希望这能把钉子放在棺材里

答案 17 :(得分:0)

来自@Karthick Kumar answer

bootstrap docs的补充
  在事件开始时触发

显示

     

显示会在动作完成后触发

......所以它应该是:

$('.modal')
    .on('show.bs.modal', function (){
            $('body').css('overflow', 'hidden');
        })
    .on('hide.bs.modal', function (){
            // Also if you are using multiple modals (cascade) - additional check
            if ($('.modal.in').length == 1) {
                $('body').css('overflow', 'auto');
            }
        });

答案 18 :(得分:-1)

防止背景滚动而不用大惊小怪。

还可以防止页面跳过丢失的滚动条

body.modal-open {
        position: fixed;
        overflow-y: scroll;
    }

答案 19 :(得分:-2)

我的解决方案......

Ver en jsfiddle

//Fix modal mobile Boostrap 3
function Show(id){
    //Fix CSS
    $(".modal-footer").css({"padding":"19px 20px 20px","margin-top":"15px","text-align":"right","border-top":"1px solid #e5e5e5"});
    $(".modal-body").css("overflow-y","auto");
    //Fix .modal-body height
    $('#'+id).on('shown.bs.modal',function(){
        $("#"+id+">.modal-dialog>.modal-content>.modal-body").css("height","auto");
        h1=$("#"+id+">.modal-dialog").height();
        h2=$(window).height();
        h3=$("#"+id+">.modal-dialog>.modal-content>.modal-body").height();
        h4=h2-(h1-h3);      
        if($(window).width()>=768){
            if(h1>h2){
                $("#"+id+">.modal-dialog>.modal-content>.modal-body").height(h4);
            }
            $("#"+id+">.modal-dialog").css("margin","30px auto");
            $("#"+id+">.modal-dialog>.modal-content").css("border","1px solid rgba(0,0,0,0.2)");
            $("#"+id+">.modal-dialog>.modal-content").css("border-radius",6);               
            if($("#"+id+">.modal-dialog").height()+30>h2){
                $("#"+id+">.modal-dialog").css("margin-top","0px");
                $("#"+id+">.modal-dialog").css("margin-bottom","0px");
            }
        }
        else{
            //Fix full-screen in mobiles
            $("#"+id+">.modal-dialog>.modal-content>.modal-body").height(h4);
            $("#"+id+">.modal-dialog").css("margin",0);
            $("#"+id+">.modal-dialog>.modal-content").css("border",0);
            $("#"+id+">.modal-dialog>.modal-content").css("border-radius",0);   
        }
        //Aply changes on screen resize (example: mobile orientation)
        window.onresize=function(){
            $("#"+id+">.modal-dialog>.modal-content>.modal-body").css("height","auto");
            h1=$("#"+id+">.modal-dialog").height();
            h2=$(window).height();
            h3=$("#"+id+">.modal-dialog>.modal-content>.modal-body").height();
            h4=h2-(h1-h3);
            if($(window).width()>=768){
                if(h1>h2){
                    $("#"+id+">.modal-dialog>.modal-content>.modal-body").height(h4);
                }
                $("#"+id+">.modal-dialog").css("margin","30px auto");
                $("#"+id+">.modal-dialog>.modal-content").css("border","1px solid rgba(0,0,0,0.2)");
                $("#"+id+">.modal-dialog>.modal-content").css("border-radius",6);               
                if($("#"+id+">.modal-dialog").height()+30>h2){
                    $("#"+id+">.modal-dialog").css("margin-top","0px");
                    $("#"+id+">.modal-dialog").css("margin-bottom","0px");
                }
            }
            else{
                //Fix full-screen in mobiles
                $("#"+id+">.modal-dialog>.modal-content>.modal-body").height(h4);
                $("#"+id+">.modal-dialog").css("margin",0);
                $("#"+id+">.modal-dialog>.modal-content").css("border",0);
                $("#"+id+">.modal-dialog>.modal-content").css("border-radius",0);   
            }
        };
    });  
    //Free event listener
    $('#'+id).on('hide.bs.modal',function(){
        window.onresize=function(){};
    });  
    //Mobile haven't scrollbar, so this is touch event scrollbar implementation
    var y1=0;
    var y2=0;
    var div=$("#"+id+">.modal-dialog>.modal-content>.modal-body")[0];
    div.addEventListener("touchstart",function(event){
        y1=event.touches[0].clientY;
    });
    div.addEventListener("touchmove",function(event){
        event.preventDefault();
        y2=event.touches[0].clientY;
        var limite=div.scrollHeight-div.clientHeight;
        var diff=div.scrollTop+y1-y2;
        if(diff<0)diff=0;
        if(diff>limite)diff=limite;
        div.scrollTop=diff;
        y1=y2;
    });
    //Fix position modal, scroll to top.    
    $('html, body').scrollTop(0);
    //Show
    $("#"+id).modal('show');
}