No bla bla bla, lets get things done. To a better comprehension of this post would be good for you to know something about HTML, SCSS and CSS Vars.
The ideia is to write a responsive modal front end structure using only flexbox and no media queries. A fluid modal. I'll try to highlight the key points of the (S)CSS style, anyway this is the result:
Use this link to see on "full" screen:
https://codepen.io/felipperegazio/full/LYPvQBe
There is no behavior added on this modal, its Style Only. Do as you prefer or feel free to ask me in the comments how to add JS functions to open, close, callbacks etc.
So, lets start with the modal HTML. We gonna need a wrapper (which will also be our backdrop), and a content div to hold the header, main content and footer. Because we are using flexbox, this modal will be also dynamic, you could omit the header or the footer without break anything.
<div class="container">
<div class="simple-modal" tabindex="0">
<div class="simple-modal__content">
<header>
<h4>Title</h4>
<span>close</span>
</header>
<div class="modal-main">
<!-- Content goes here -->
</div>
<footer>
<button>Ok</button>
</footer>
</div>
</div>
</div>
Really simple, huhn? There is no much to say about it. The container could be anything in the page, its for eye candy purposes only (we'll add a background on it).
The modal starts in the .simple-modal
div. This will be our wrapper and backdrop. This is also where you apply the visibility and display rules to show or hide the modal when adding behavior.
Then we add the .simple-modal__content
div, which will be the content of our modal, containing the header, main-content and footer.
So, lets start defining some CSS vars that we may need:
.simple-modal {
--gutter: 14px; // spacing reference
--modal-color: #800000; // just color
--soft-color: #fafafa; // just another color
}
Then lets do our wrapper/backdrop:
.simple-modal {
--gutter: 14px;
--modal-color: #800000;
--soft-color: #fafafa;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 2000;
position: fixed;
background-color: rgba(0,0,0,.7);
padding-top: 2%;
}
Key points: the .simple-modal
div will be fixed on the screen, so will be where the modal content will be placed. The z-index
will keep the modal always on front of the other page elements. The padding-top can be modified, but i think 2 or 3 percent scales really well from desk to mobo, this padding will determine how distant from the page top the modal content will be.
Now, lets add the content element, a blank square on the middle.
To do it we gonna use the .simple-modal__content
div:
.simple-modal {
/* ... previous stuff ... */
&__content {
width: 95vw;
max-width: 600px;
height: 90vh;
max-height: 700px;
position: relative;
overflow: hidden;
border-radius: 4px;
margin: 0 auto;
background-color: #ffffff;
display: flex;
flex-direction: column;
}
}
Key points: We start given the modal a width: 95vw
and max-width: 600px
. So, we get a decent content width on desktop which also fits well on mobile, cuz on < 600px screens, the width will be 95vh, or 95% of the viewport, given 5% of space to emulate the padding. The height and max-height here will do the same thing with the height.
Then at last not least, the display: flex
will give a fluid behavior for our modal content elements. But flex is horizontal driven by default, so we use flex-direction: column
to change it to vertical. Now, things will be vertically stretched on our modal content. Dont forget the margin:0 auto
to centralize and overflow:hidden
to prevent unwanted scroll bars.
Its time to add the modal elements:
Header, Main Content and Footer
header {
min-height: 60px;
height: 60px;
color: #ffffff;
background-color: var(--modal-color);
display: grid;
padding-left: var(--gutter);
align-items: center;
grid-template-columns: auto 60px;
h4 {
margin: 0;
text-align: left;
}
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
font-size: 20px;
opacity: .8;
cursor: pointer;
&:hover {
opacity: 1;
}
}
}
.modal-main {
flex: 1;
text-align: left;
overflow: auto;
padding: var(--gutter);
}
footer {
height: auto;
text-align: right;
border-top: solid 1px #cccccc;
padding: var(--gutter);
background-color: #ffffff;
background-color: var(--soft-color);
button, input {
margin: 0;
&:not(:last-child) {
margin-right: var(--gutter);
}
}
}
If you note, this part of the code its almost pure aesthetics. Almost no style behavior added, except for the flex:1
on the .modal-main
.
The flex 1 tells to the .modal-main
to grow along the parent as much as possible, but it will be stopped by the &__content
div limits. Then we add the min-height
on the header. For the footer id prefer to not to given a height and let the children do it for me, then when the footer is empty, it will became just a cool border on the bottom.
Conclusion
Because our modal content holder is display:flex
with column direction, all the content will be vertically placed in a way that the main content (flex 1) will grow in a delimited size (&__content height and width) and without break its header, but will grow. Also important to add the overflow:auto
on your main content .modal-main
, so you can have large contents inside the .modal-main
.
The final code must be like this:
.simple-modal {
--gutter: 14px;
--modal-color: #800000;
--soft-color: #fafafa;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 2000;
position: fixed;
background-color: rgba(0,0,0,.7);
padding-top: 2%;
&__content {
width: 95vw;
height: 90vh;
max-height: 700px;
max-width: 600px;
position: relative;
overflow: hidden;
border-radius: 4px;
margin: 0 auto;
background-color: #ffffff;
display: flex;
flex-direction: column;
header {
min-height: 60px;
height: 60px;
color: #ffffff;
background-color: var(--modal-color);
display: grid;
padding-left: var(--gutter);
align-items: center;
grid-template-columns: auto 60px;
h4 {
margin: 0;
text-align: left;
}
span {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
font-size: 20px;
opacity: .8;
cursor: pointer;
&:hover {
opacity: 1;
}
}
}
.modal-main {
flex: 1;
text-align: left;
overflow: auto;
padding: var(--gutter);
}
footer {
height: auto;
text-align: right;
border-top: solid 1px #cccccc;
padding: var(--gutter);
background-color: #ffffff;
background-color: var(--soft-color);
button, input {
margin: 0;
&:not(:last-child) {
margin-right: var(--gutter);
}
}
}
}
}
You can use the .container
div to add a cool background:
// just an eye candy
.container {
width: 100vw;
height: 100vh;
background-size: cover;
background-repeat: no-repeat;
background-image: url(http://picsum.photos/2000);
}
Thats all folks :)
Top comments (4)
Great article, thank you for this. As a back-end dev I'm diving into the front-end a bit more and knew there had to be an easier way to make a flexible login modal.
really nice to read an answer like that, tks for your feedback : )
great one! thanks :)
thank you, the very helpful tutorial save my day.