如何在Bootstrap v4模态框中垂直对齐

40

在Bootstrap 4中垂直居中模态框。

注意: 下面的要求是为了明确我正在寻找一种合适的方式来垂直居中Bootstrap模态框,覆盖所有可能的情况,在所有可能的设备和浏览器上。在我的情况下,我希望在整个应用程序中重复使用同一个模态框,因此需要它在每种情况下都能正常工作。

它应该:

  • 使弹出框内容在所有设备上都可以访问,即使高度超过设备高度
  • 适用于任何市场份额大于1%的设备和浏览器组合
  • 不使用display:table-cell或类似的技巧(任何非设计用于布局的布局技术)
  • .modal-content之外的任何地方(包括上方和下方)单击或点击即可关闭
  • 尽可能减少使用jQuery / JavaScript
  • (可选) 在默认的Bootstrap示例中工作,不需要进行标记修改

可能是如何使用CSS垂直居中Bootstrap V4模态框?的重复问题。 - Carol Skelly
@ZimSystem,这个问题不是重复的。它比“原始问题”早两个月被提出。此外,它有明确的要求,而你的答案没有满足。另外,从技术上讲,你的答案是错误的。高度超过视口高度的模态框将被剪切并且无法访问其顶部部分。尝试使用200vh高度的模态框,你就会明白了。 - tao
可能是重复内容。另外,在Beta 3中,新增了一个名为modal-dialog-centered的类。 - Carol Skelly
@ZimSystem,请解释一下一个旧问题如何“可能重复”一个新问题。感谢Bootstrap方法的更新。我已经更新了答案。干杯! - tao
当然,您可以以任何方式查看它,但我标记重复项是为了帮助用户在将来找到答案。根据标题,这个问题是通用的,但描述概述了特定的v中心要求。我建议另一个答案作为解决方案,可能不适用于所有情况,而不是引起对我的回答的关注。当我回答其他问题时遇到了这个问题,因为我总是在回答之前寻找重复项。由于它不是完全重复的,所以我在回答后指出了它。现在问题已经链接,希望它能防止另一个用户问另一个v中心引导4模态问题。 - Carol Skelly
具体要求是为了防止未涵盖所有情况(即:需要滚动的长内容)和使用display:table的低质量答案。您可以用一个词总结所有要求,即垂直居中模态框的正确方式。 - tao
10个回答

90
更新至Beta 3版本后,[文档]如下:

.modal-dialog-centered 添加到 .modal-dialog 中以垂直居中模态框。


原始答案:

SCSS

.modal-dialog {
  min-height: calc(100vh - 60px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: auto;
  @media(max-width: 768px) {
    min-height: calc(100vh - 20px);
  }
}

或者 无前缀的 CSS:

.modal-dialog {
    min-height: calc(100vh - 60px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    overflow: auto;
}
@media(max-width: 768px) {
  .modal-dialog {
    min-height: calc(100vh - 20px);
  }
}

注意1:请注意,完全使用前缀的CSS渐渐变得过时,因为浏览器对某些属性的支持发生了变化。获取更新的无前缀CSS的正确方法是:

  • 将无前缀的CSS复制/粘贴到Autoprefixer中。
  • 在底部框中设置所需设置的过滤器(对于最大的浏览器支持,请使用> 0%)。
  • 从右侧框中获取最新代码。

注意2:本答案是在v4alpha 3或4)的早期阶段添加的,现在已经进入beta。您可以通过向.modal-dialog添加以下类来安全地替换本答案的CSS部分:

h-100 d-flex flex-column justify-content-center my-0

正如下面的评论中@Androbaut指出的那样。您仍然需要JavaScript(请参见下文)来关闭模态窗口,以在模态窗口上方/下方单击或轻敲。


jQuery(需要在单击/轻敲模态框上方/下方时关闭模态框):

$('.modal-dialog').on('click tap', function(e){
  if ($(e.target).hasClass('modal-dialog')) {
    $('.modal').modal('hide');
  }
})

就是这样。


工作示例,完全前缀的CSS和标记,使用不同的模态尺寸:

$('.modal-dialog').on('click tap', function(e){
  if ($(e.target).hasClass('modal-dialog')) {
   $('.modal').modal('hide');
  }
})
.modal-dialog {
  min-height: -webkit-calc(100vh - 60px);
  min-height: -moz-calc(100vh - 60px);
  min-height: calc(100vh - 60px);
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
     -moz-box-orient: vertical;
     -moz-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
     -moz-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  overflow: auto; 
}
@media (max-width: 768px) {
  .modal-dialog {
    min-height: -webkit-calc(100vh - 20px);
    min-height: -moz-calc(100vh - 20px);
    min-height: calc(100vh - 20px);   
  }
}

/* you don't need the CSS below this line. It's mainly cosmetic and for aligning the modal launch buttons */

.modal-content {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
     -moz-box-orient: vertical;
     -moz-box-direction: normal;
      -ms-flex-direction: column;
          flex-direction: column; }
.modal-content > * {
  -webkit-box-flex: 0;
  -webkit-flex: 0 0 auto;
     -moz-box-flex: 0;
      -ms-flex: 0 0 auto;
          flex: 0 0 auto; 
}
.modal-content > *.modal-body {
  -webkit-box-flex: 1;
  -webkit-flex-grow: 1;
     -moz-box-flex: 1;
      -ms-flex-positive: 1;
          flex-grow: 1; 
}

#Modal_2 .modal-content {
  min-height: 50vh; 
}

#Modal_3 .modal-content {
  min-height: 85vh; 
}

#Modal_4 .modal-content {
  min-height: 200vh; 
}

.full-page-center {
  display: -webkit-box;
  display: -webkit-flex;
  display: -moz-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
  -webkit-justify-content: center;
     -moz-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  -webkit-box-align: center;
  -webkit-align-items: center;
     -moz-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  min-height: 100vh; 
}
.full-page-center button {
  margin: 15px; 
}
@media (max-width: 768px) {
  .full-page-center {
    -webkit-flex-wrap: wrap;
        -ms-flex-wrap: wrap;
            flex-wrap: wrap;   
  }
  .full-page-center button {
    display: block;
    min-width: 100%;
    margin: 10px 15px;
  }
  .full-page-center::after {
    display: none;
    -webkit-box-flex: 0;
    -webkit-flex-grow: 0;
       -moz-box-flex: 0;
        -ms-flex-positive: 0;
            flex-grow: 0;
  }
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://npmcdn.com/tether@1.2.4/dist/js/tether.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/js/bootstrap.min.js"></script>


<div class="container full-page-center">
  <button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#Modal_1">
    Tiny modal
  </button>
  <button type="button" class="btn btn-default btn-lg" data-toggle="modal" data-target="#Modal_2">
    Normal modal
  </button>
  <button type="button" class="btn btn-success btn-lg" data-toggle="modal" data-target="#Modal_3">
    Large modal
  </button>
  <button type="button" class="btn btn-warning btn-lg" data-toggle="modal" data-target="#Modal_4">
    Very large modal
  </button>
</div>
<div class="modal fade" id="Modal_1" tabindex="-1" role="dialog" aria-labelledby="modalLabel_1" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title" id="modalLabel_1">Tiny modal</h4>
      </div>
      <div class="modal-body">
        I am cute...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>
<div class="modal fade" id="Modal_2" tabindex="-1" role="dialog" aria-labelledby="modalLabel_2" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title" id="modalLabel_2">Dull modal</h4>
      </div>
      <div class="modal-body">
        I am normal...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Some action</button>
      </div>
    </div>
  </div>
</div>
<div class="modal fade" id="Modal_3" tabindex="-1" role="dialog" aria-labelledby="modalLabel_3" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title" id="modalLabel_3">Don't call me fat</h4>
      </div>
      <div class="modal-body">
        Call me "oversized".
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-success">Some action</button>
      </div>
    </div>
  </div>
</div>
<div class="modal fade" id="Modal_4" tabindex="-1" role="dialog" aria-labelledby="modalLabel_4" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title" id="modalLabel_4">Huge modal</h4>
      </div>
      <div class="modal-body">
        Comments, anyone?
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-warning">Some action</button>
      </div>
    </div>
  </div>
</div>

如果您发现任何漏洞或不足,请告诉我。我会花时间改进答案,使其更加有用。欢迎协助完成此任务。

6
这也可以使用Bootstrap 4内置的类来实现: div class="modal-dialog h-100 d-flex flex-column justify-content-center my-0" 这让我避免使用calc和媒体查询。 - Androbaut
5
从 Bootstrap 4 beta 2 开始,你不再需要使用 JavaScript 来关闭(点击上方或下方)。请参阅 https://github.com/twbs/bootstrap/pull/22704。 - claviska
@claviska 感谢您的更新。我一到电脑前就会编辑答案。 - tao
谢谢!更新成功了,太棒了!!<3 - Frijey Labs

11

只需将 modal-dialog-centered 类与 model-dialog 一起添加,如下所示:

<head>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</head>
 <button class="btn btn-success" data-toggle="modal" data-target="#MyModal">Launch Modal</button>     
<div class="modal align-middle" id="MyModal">
    <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Modal Title</h5>
                <button class="close" data-dismiss="modal">&times;</button>
            </div>
            <div class="modal-body">Lorem Ipsum is simply dummy text of the                        printing and typesetting industry</div> 
            <div class="modal-footer">
                <button class="btn btn-info" data-dismiss="modal">Close</button>
            </div>                
        </div>
    </div>
</div>


7
这里有一个简单的Flexbox解决方法。
SCSS
.modal-open .modal {
    display: flex!important;
    align-items: center!important;
    .modal-dialog {
        flex-grow: 1;
    }
}

工作演示


1
当你有很多内容时(例如BS4 beta的长滚动演示),这种方法会导致模态框的顶部和底部超出屏幕。 - claviska
你的示例在Bootstrap4上运行良好,但有一个小错误,你需要在移动设备上取消 .modal-dialog { flex-grow: 1; } 以实现100%的宽度。 - J261

5

只需使用这个类 "modal-dialog-centered",即可在屏幕垂直中心显示模态框。

例如:

<div class="modal-dialog modal-dialog-centered" role="document">

谢谢


3

这个解决方案适用于需要滚动的小型和长型模态框。

添加以下自定义 CSS 规则:

.modal-header {
  flex-shrink: 0;
}

.modal-body {
  overflow-y: auto;
}

并添加以下类:

  • 对于modal-dialogh-100 my-0 mx-auto d-flex flex-column justify-content-center
  • 对于modal-contentm-2

像这样:

<div class="modal-dialog h-100 my-0 mx-auto d-flex flex-column justify-content-center" role="document">
  <div class="modal-content m-2">
     ...
  </div>
</div>

3
将 .modal-dialog-centered 添加到 .modal-dialog 中,以垂直居中模态框。
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalCenter">
  Launch demo modal
</button>

<!-- Modal -->
<div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLongTitle">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

2
通过将以下css添加到“.modal-dialog”类,对我来说它可以正常工作。您也可以使用自定义css类进行覆盖。"最初的回答"
.modal-dialog {
      height: 100vh;
      display: flex;
      align-items: center;
}

1
另一种使您的模态垂直对齐的简单方法是调整模态对话框类的top: 50%;transform: translateY(-50%);margin: 0 auto编辑: 缺点是您还必须将max-height: 100vh;设置为.modal-content。否则,当您的模态高度超过视口时,无法再访问模态的顶部。 演示:

.modal.vertically-modal .modal-dialog {
  transform: translateY(-25%);
  top: 50%;
  margin: 0 auto;
}

.modal.vertically-modal.show .modal-dialog {
  transform: translateY(-50%);
}

.modal-content {
  max-height: 100vh;
  overflow-y: auto;
  padding: 40px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js "></script>

<button class="btn btn-primary" data-toggle="modal" data-target=".vertically-modal">Show modal</button>

<div class="modal fade vertically-modal" tabindex="-1" role="dialog" aria-hidden="true">
  <div class="modal-dialog modal-lg">
    <div class="modal-content">
      Vertically modal
    </div>
  </div>
</div>


1
除非模态框比视口更高,否则模态框的顶部将无法访问。 - tao
是的,谢谢,我刚刚注意到了。这种样式只有在平板电脑或台式机上才有意义。通常情况下,在移动设备上不需要将模态垂直对齐。 - NiZa
2
你在桌面和平板电脑上遇到了完全相同的问题:如果模态框高度超过 100vh,则无法将其顶部滚动到视图中。使用绝对居中方法时,当你将一个更高的子元素放置在具有 overflow:auto(如 <body>)的父元素内时,你失去了滚动到子元素顶部的能力。唯一的解决方法是限制模态对话框的 max-height 并使其 .modal-body 可滚动。你的解决方案不符合问题的第一个要求。 - tao
感谢您的反馈。我编辑了我的答案。我认为,这仍然是一个不错的解决方案,适用于任何人。 - NiZa

1

有一种更简单的方法可以实现这一点,而无需编写大量CSS覆盖或其他自定义CSS,基本上只使用原始bootstrap类并添加一个额外的HTML元素来控制高度。

CSS(不需要,请见下文)

.modal > .row{
    flex: 1;
}

HTML(下面有更新)

<div id="dialogBox" class="modal fade d-flex">
    <div class="row justify-content-center"> <!-- Vertically Align Modal -->
        <div class="modal-dialog align-self-center" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Modal title</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p>Modal body text goes here.</p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-primary">Save changes</button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                </div>
            </div>
        </div>
    </div>
</div>

然后使用:

JS

$("#dialogBox").modal('show');

OR HTML

<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#dialogBox">
  Launch demo modal
</button>

也许只使用Bootstrap的.row.colflex-XXX类就可以达到所需的结果,但我无法让它起作用。

最后需要注意的是,根据您的CSS的其余部分,您可能需要添加:<body class="d-flex">才能使所有内容正常工作。

更新


有一种方法可以仅使用Bootstrap类h-100w-100来实现此目的:

<div id="dialogBox" class="modal fade d-flex">
    <div class="row justify-content-center w-100"> <!-- Vertically Align Modal -->
        <div class="modal-dialog align-self-center" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Modal title</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p>Modal body text goes here.</p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-primary">Save changes</button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                </div>
            </div>
        </div>
    </div>
</div>

0

试试这个,

::ng-deep{
    .modal-body{
        padding: 0.25rem;
        width: 600px !important;
    }
    .modal-content {
        position: relative;
        display: flex;
        flex-direction: row;
        margin-top: auto;
        margin-bottom: auto;
        width: 600px !important;
      }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接