Pure CSS Dynamic Sized Centered Modals

I recently came across this article “Vertical align anything with just 3 lines of CSS”, describing a technique for vertical alignment using the CSS property transform (caniuse):

.element {
  position: relative;
  top: 50%;
  transform: translateY(-50%);
}

It was sort of an “Aha!” moment as I have never really thought about using transform for alignment.

The next day I was working on a project and needed to create a simple modal for an app to display some help content. Modal positioning has always been a thorn in my side as it seemed every method I have ever used had undesired draw backs.

Fixed Size / Absolute Positioned for Centering

I could used fixed size modals absolute positioning:

.modal {
  height: 800px;
  margin-top: -450px;
  margin-left: -450px;
  position: absolute;
    top: 50%
    left: 50%;
  width: 800px;
}

But if my content was small I was stuck with tons of white space and I would have to write media queries for resizing things on small resolutions.

Not ideal.

Dynamically Sized / Fixed Position from Top

I would create a dynamically sized modal and then just ensure there were a certain amount of spacing around the modal:

.modal {
  height: 80%;
  margin: 30px;
  position: absolute;
    top: 0;
    left: 50%;
  width: 80%;
}

But again, tons of potential white space and also not centered.

Again, not ideal.

The JavaScript Solution

I could use JavaScript to determine the size of my modal when rendered and then position dynamically. While this would accomplish my goal of being centred and only as large as my content… 2004 called and wants their solution back. :trollface:

I don’t like using JS for doing things that CSS should… plus now I would have to deal with testing JS on mobile and other horribly boring and tedious things.

The Solution I Used

So armed with my new enlightened thought process on using transform for vertical positioning and my love of :heart: calc :heart: (caniuse), I set off to create a modal with these three goals:

So, first the positioning:

.modal {
  position: fixed;
    top: 50%;
    left: 50%;
  transform: translate(-50%, -50%);
}

Check. Now our modal will position to the center of the page and then dynamically ‘negative margin’ the top and left ½ the size of the rendered window. This means no matter how large the window it, it will be centered.

Second we get for free. Since we didn’t give the modal a height or width it will :sparkles: automagically :sparkles: be sized by the browser. We do however want to make sure that that even if the content is huge it doesn’t scroll off the screen. so we we add in a little max-height action. Using calc we don’t have to worry about % that could potentially get strange on different resolutions.

.modal {
  max-height: calc(100% - 100px);
  position: fixed;
    top: 50%;
    left: 50%;
  transform: translate(-50%, -50%);
}

Check.

Finally… well our solution is pure CSS soooo … check.

Check it out over on codepen.io. Try resizing your browser to see how it scales. There is some other CSS in there to deal with content for scrolling which may be helpful as well.