39

Vertically center modal dialogues in Bootstrap 4.

Note: The requirements below have been added to make it clear I am looking for a proper way to vertically center a Bootstrap modal, covering all possible cases, on all possible devices, in all browsers. In my case, I wanted it for a large SPA reusing the same modal throughout the app so I needed it to work in each case.

It should:

  • keep modal contents accessible, on all devices, even when taller than device height
  • work on any device+browser combination with a market share larger than 1%
  • not use display:table-cell or similar hacks (any layout-ing technique not meant or designed for layout-ing)
  • close on click or tap anywhere outside of .modal-content (including above and below).
  • limit usage of jQuery/JavaScript as much as possible
  • (optional) work on default Bootstrap examples without need of markup modifications
tao
  • 82,996
  • 16
  • 114
  • 150
  • Possible duplicate of [How can I vertically centralize a Bootstrap V4 modal with CSS?](https://stackoverflow.com/questions/42405989/how-can-i-vertically-centralize-a-bootstrap-v4-modal-with-css) – Carol Skelly Aug 23 '17 at 19:05
  • @ZimSystem, this question is **not** a duplicate. It was asked 2 months prior to the "original". Besides, it has clear requirements which your answer does not meet. Additionally, your answer is wrong, technically. Modals taller than the viewport height will have their top part cut off and inaccessible. Try with a modal of `200vh` height and you'll understand. – tao Aug 24 '17 at 06:09
  • as it says "possible dup". Also, as of Beta 3 there is a new `modal-dialog-centered` class. – Carol Skelly Jan 17 '18 at 13:51
  • @ZimSystem, please explain how an older question could "possibly duplicate" a newer one. Thanks for the update on Bootstrap methods. I've updated the answer. Cheers! – tao Jan 17 '18 at 15:17
  • OFC you can see it whatever way you like, but I mark dups to help users find answers in the future. Based on the title this question is generic, but the description outlines specific v center req's. I suggested the other answer as a solution that may or may not work in all cases, not to draw attention to my answer. I encountered this when answering the other as I always look for dups before answering. Since it wasn't an exact dup I pointed after I answered. Now the questions are linked hopefully it prevents another user asking another v center bootstrap 4 modal question. – Carol Skelly Jan 17 '18 at 15:27
  • The specific requirements were added to prevent answers that did not cover all cases (i.e.: long content requiring scroll) and low quality answers using `display:table`. You can sum all requirements in one word **proper** vertical centering a modal. – tao Jan 17 '18 at 15:33

10 Answers10

89

Update, as of Beta 3, [docs]:

Add .modal-dialog-centered to .modal-dialog to vertically center the modal.


Original answer:

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);
  }
}

or unprefixed 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);
  }
}

Note 1: Please note fully prefixed CSS gradually becomes obsolete as browser support for certain properties changes. The right way of getting the updated prefixed CSS is to:

  • copy/paste the unprefixed CSS into Autoprefixer.
  • set the filter in the bottom box to the desired setting (for max. browser support use > 0%).
  • get the latest code from the box on the right.

Note 2: This answer was added in early stages of v4 (alpha 3 or 4), which is now currently in beta. You can safely replace the CSS part of this answer by adding the following classes to .modal-dialog:

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

..., as pointed out by @Androbaut in the comment below. You will still need the JavaScript (see below) to close the modal window on click tap below/above the modal window.


jQuery (needed to close modal on click/tap above/below):

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

That's it.


Working snippet, fully-prefixed CSS and markup using different modal sizes:

$('.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>

If you find any bugs or shortcomings please let me know. I will take the time to improve the answer and keep it useful. Help with this task is welcome.

tao
  • 82,996
  • 16
  • 114
  • 150
  • 6
    This can also be done using Bootstrap 4's built-in classes: `div class="modal-dialog h-100 d-flex flex-column justify-content-center my-0"` Lets me avoid using `calc` & media queries. – Androbaut Jul 23 '17 at 03:33
  • 5
    As of Bootstrap 4 beta 2, you no longer need JavaScript to close when clicking above/below. See https://github.com/twbs/bootstrap/pull/22704 – claviska Oct 26 '17 at 18:48
  • @claviska Thanks for the update. I'll edit the answer when I get to a computer. – tao Oct 26 '17 at 18:52
  • Thanks! the update worked as a charm!! <3 – Frijey Labs Feb 28 '22 at 18:46
11

Simply add modal-dialog-centered class along with model-dialog as below

<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>
Muthu Prasanth
  • 301
  • 5
  • 13
7

Here's a simple Flexbox Approach.

SCSS

.modal-open .modal {
    display: flex!important;
    align-items: center!important;
    .modal-dialog {
        flex-grow: 1;
    }
}

Working Demo

Surjith S M
  • 6,642
  • 2
  • 31
  • 50
  • 1
    This approach will cause the modal's top and bottom to go off-screen when you have a lot of content (e.g. BS4 beta's long scrolling demo). – claviska Oct 03 '17 at 20:34
  • your example works well bootstrap4 but has a little bug, you need to put off .modal-dialog { flex-grow: 1; } for 100% width on mobile. – J261 Oct 10 '18 at 01:52
5

Just use this class " modal-dialog-centered " for showing Modal on center of screen Vertically .

for exmaple:

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

Thanks

Tayyab Roy
  • 423
  • 5
  • 7
3

This solution works for small and long modals thats needs scroll.

Add these custom css rules:

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

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

And add these classes:

  • To modal-dialog: h-100 my-0 mx-auto d-flex flex-column justify-content-center
  • To modal-content: m-2

Like this:

<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>
Mikel
  • 5,902
  • 5
  • 34
  • 49
3

Add .modal-dialog-centered to .modal-dialog to vertically center the modal.

<!-- 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>
Zoha Irshad
  • 427
  • 5
  • 5
2

By adding following css to '.modal-dialog' class, it works fine for me. You can override with custom css class also.

.modal-dialog {
      height: 100vh;
      display: flex;
      align-items: center;
}
Karthikeyan Vellingiri
  • 1,270
  • 1
  • 17
  • 26
1

Another simple way to make your modal vertical align is to adjust top: 50%;, transform: translateY(-50%); and margin: 0 auto to the modal dialog class.

Edit: The downside is that you also have to set max-height: 100vh; to .modal-content. Otherwise the top of modal is not accessible anymore when your modal is getting heigher than the viewport.

Demo:

.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>
NiZa
  • 3,806
  • 1
  • 21
  • 29
  • 1
    Except when the modal is taller than the viewport, in which case, the top part of the modal becomes inaccessible. – tao Jun 28 '17 at 17:34
  • Yes thanks, I just noticed. Applying this style has only sense on a tablet or desktop. Normally you don't need to have your modal vertically aligned on a mobile device. – NiZa Jun 28 '17 at 17:41
  • 2
    You have the exact same problem on desktop and tablet: if the modal is higher than `100vh` you can't scroll its top into view. With absolute centering method, when you place a taller child inside a parent with `overflow:auto` (like ``), you lose the ability to scroll to top of child. The only way around this would be to limit the `max-height` of modal dialogue and make its `.modal-body` scrollable. Your solution does not meet the first requirement of the question. – tao Jun 28 '17 at 17:54
  • Thanks for you feedback. Edited my answer. I think, still it could be a nice solution for anyone. – NiZa Jun 28 '17 at 18:09
1

There is a much easier way of achieving this without having to write a bunch of CSS overrides or other custom CSS, basically using just the stock bootstrap classes and adding one extra HTML element to control the height.

CSS (Not Needed see below)

.modal > .row{
    flex: 1;
}

HTML (Updated see below)

<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>

Then to use:


JS

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

OR HTML

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

There is probably a way to achieve the desired result using only the bootstrap .row, .col and flex-XXX classes but I was unable to get that to work.

One last note, you might have to add: <body class="d-flex"> to get everything to work depending on the rest of your CSS.

UPDATE


There is a way to achieve this using only bootstrap classes, h-100 and w-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>
Andy Braham
  • 9,594
  • 4
  • 48
  • 56
0

Try this,

::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;
      }
}
Malith
  • 506
  • 5
  • 9