π Hello, Dear developers π©βπ»
Today we will be lookup on how to build a responsive modal using CSS, so stay tunnedπ₯
Introduction
Modal Popups are used very often in modern websites or Apps, to display notifications or alerts, handle user's sign up or login forms, newsletters & much more β¨
I created this tutorial, on how to create a responsive modal popup box with a clean design, with the help of HTML as markup, CSS for styling and vanilla javascript for adding functionality π§ π
Here's how it will look once we are finished in the below GIFβ¬οΈ
But Before that, You can view the code tutorial of the finished product before continuing this blog β¬οΈ
Code Tutorial
You can also view a live demo πΊ of it as well.
Now Let's start on building this from scratch !
HTML Markup β¬οΈ
Let's start with html markup for the modal
<div class="container">
<button class="share__modal_btn">share</button>
<main class="share__modal">
<div class="share__modal_content">
<div class="share__modal__header">
<span>share</span>
<button class="close_modal_btn">
<i class="bx bx-x bx-sm"></i>
</button>
</div>
<div class="share__modal__options">
<ul class="list">
<li class="list__item">
<div class="icon_holder" data-icon="twitter">
<img
class="social__logo"
src="./img/twitter-logo.png"
alt="twitter-logo"
/>
</div>
<span>twitter</span>
</li>
<li class="list__item">
<div class="icon_holder" data-icon="facebook">
<img
class="social__logo"
src="./img/facebook-logo.png"
alt="facebook-logo"
/>
</div>
<span>facebook</span>
</li>
<li class="list__item">
<div class="icon_holder" data-icon="reddit">
<img
class="social__logo"
src="./img/reddit-logo.png"
alt="reddit-logo"
/>
</div>
<span>reddit</span>
</li>
<li class="list__item">
<div class="icon_holder" data-icon="discord">
<img
class="social__logo"
src="./img/discord-logo.png"
alt="discord-logo"
/>
</div>
<span>discord</span>
</li>
<li class="list__item">
<div class="icon_holder" data-icon="whatsapp">
<img
class="social__logo"
src="./img/whatsapp-logo.png"
alt="whatsapp-logo"
/>
</div>
<span>whatsapp</span>
</li>
<li class="list__item">
<div class="icon_holder" data-icon="messenger">
<img
class="social__logo"
src="./img/messenger-logo.png"
alt="messenger-logo"
/>
</div>
<span>messenger</span>
</li>
<li class="list__item">
<div class="icon_holder" data-icon="telegram">
<img
class="social__logo"
src="./img/telegram-logo.png"
alt="telegram-logo"
/>
</div>
<span>telegram</span>
</li>
<li class="list__item">
<div class="icon_holder" data-icon="wechat">
<img
class="social__logo"
src="./img/wechat-logo.png"
alt="wechat-logo"
/>
</div>
<span>wechat</span>
</li>
</ul>
</div>
<div class="share__modal_link">
<span>page link</span>
<div class="share__modal_input">
<input
type="text"
placeholder="https://www.sharethispage.io"
/>
<i class="bx bx-copy copy_icon"></i>
</div>
</div>
</div>
</main>
</div>
So here, we have a few components added to our markup.
First, we have a simple open modal button which is named a share button, when clicked on, it triggers the function of opening the modal, then we have the close modal button which performs the opposite operation/function to the open button to close modal, then we have few social sharing option's and at last, we have the input box with just fake placeholder value in it.
for images, please follow my GitHub repository inorder to use them.
CSS Styles π¨
Let's add the styles stepwise to understand what we're doing,
First of all, we will look at making some basic changes in our CSS file which includes resets of the root, HTML & variables.
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;600&display=swap");
*,
*::before,
*::after {
box-sizing: border-box;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Inter", sans-serif;
}
:root {
/*========== Colors ==========*/
--first-color: #373d46;
--modal-bg-color: #fff;
--text-input-bg: #f8f9fa;
--text-color: #95989d;
--container-bg: #c7ad91;
--btn-color: #ddc0a1;
/* ===== SOCIAL ICONS BACKGROUND COLOR ===== */
--twitter: #e8f6fe;
--whatsapp: #e9fbf0;
--facebook: #e8f1fe;
--reddit: #ffece6;
--discord: #f1f3fb;
--messenger: #e6f3ff;
--telegram: #e6f3fa;
--wechat: #f2f7ea;
/*========== Font and typography ==========*/
--normal-font-size: 0.88rem;
--large-font-size: 1.25rem;
--share-link-span: 0.9869em;
--share-input-font-size: 0.8em;
/*========== z index ==========*/
--z-modal: 1000;
}
@media screen and (min-width: 991px) {
:root {
--large-font-size: 1.5rem;
--normal-font-size: 1rem;
--share-link-span: 1.1em;
--share-input-font-size: 1em;
}
}
/*=============== BASE ===============*/
body{
font-weight: 500;
background-color: var(--btn-color);
}
button{
background-color: transparent;
outline: none;
border: none;
cursor: pointer;
font-family: inherit;
}
img{
max-width: 100%;
height: auto;
}
ul li {
margin: 0;
padding: 0;
list-style-type: none;
}
.container{
height: 100vh;
display: grid;
place-items: center;
background-color: var(--container-bg);
}
Okay Nice ! we are moving further πββοΈπββοΈ
So after adding those base styles, we look up our markup and use the classes that we have given to each component (tag) in order to add them styles individually.
1. Share modal button
.share__modal_btn {
background-color: #857361;
padding: 0.9em 1.5em;
font-size: var(--share-link-span);
text-transform: capitalize;
border-radius: 0.7em;
box-shadow: 0 10px 10px -2px rgba(0, 0, 0, 0.1);
color: #eee;
letter-spacing: 0.25px;
}
.share__modal_btn:hover {
background-color: #6f6051;
}
The styles for the share modal button are background color, font size along with visual goodies like padding, border-radius & pseudo hover class on background color.
Result β¬οΈ
2. Share modal
The share modal is the most important, where all of the content is situated
we added an absolute position on it at the bottom with a 0% percentage value along the visual goodies like box shadow, border radius, opacity, and extra white space by using padding and transition property as well.
.share__modal {
background-color: var(--modal-bg-color);
position: absolute;
bottom: 0;
width: 100%;
height: 50%;
display: grid;
align-items: flex-end;
overflow: auto;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2);
border-radius: 1.3em 1em 0 0;
z-index: var(--z-modal);
opacity: 0;
transition: 0.5s ease;
visibility: hidden;
}
.share__modal_content {
padding: 1.5em;
display: flex;
flex-direction: column;
row-gap: 2.6em;
}
.share__modal__header {
display: flex;
align-items: center;
justify-content: space-between;
}
.share__modal__header span {
font-size: var(--large-font-size);
font-weight: 600;
color: var(--first-clr);
text-transform: capitalize;
opacity: 0.88;
}
.close_modal_btn {
color: var(--first-clr);
}
Result β¬οΈ
3. Social sharing options
These options are structured with the help of CSS Grid, for the background color of social sharing options, we used the data-icon attribute property on each tag in html file & added light color as a background to add contrast against the actual logo.
.list {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 1.125em;
}
.list__item {
display: flex;
flex-direction: column;
row-gap: 0.5em;
align-items: center;
justify-content: center;
text-transform: capitalize;
color: var(--first-clr);
font-size: var(--normal-font-size);
font-weight: 500;
opacity: 0.9;
cursor: pointer;
}
.icon_holder {
width: 4.5em;
height: 4.5em;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.social__logo {
width: 2em;
height: 2em;
}
[data-icon="twitter"] {
background-color: var(--twitter);
}
[data-icon="facebook"] {
background-color: var(--facebook);
}
[data-icon="reddit"] {
background-color: var(--reddit);
}
[data-icon="discord"] {
background-color: var(--discord);
}
[data-icon="whatsapp"] {
background-color: var(--whatsapp);
}
[data-icon="messenger"] {
background-color: var(--messenger);
}
[data-icon="telegram"] {
background-color: var(--telegram);
}
[data-icon="wechat"] {
background-color: var(--wechat);
4. Share link input
we use the input with the fake placeholder value to share the link of the current page, the style for these is pretty generic & straight forward.
.share__modal_link {
display: flex;
flex-direction: column;
row-gap: 1.1em;
}
.share__modal_link span {
font-weight: 500;
font-size: var(--share-link-span);
text-transform: capitalize;
color: var(--first-clr);
}
.share__modal_input {
position: relative;
}
.share__modal_input input {
width: 100%;
background-color: var(--text-input-bg);
padding: 0.88em;
border-radius: 0.5em;
border: none;
outline: none;
font-size: var(--share-input-font-size);
}
.copy_icon {
position: absolute;
right: 1.5em;
top: 1em;
color: var(--first-clr);
cursor: pointer;
}
5. Show modal
Before moving to the final, here is the class that handles the styles when the modal is opened.
.show-modal {
opacity: 1;
visibility: visible;
}
6. Media queries to make it responsive π±
Finally, we want to make it responsive or at least look good on both mobile and desktop, so below are the few breakpoints on the share modal button, modal, modal content, and list.
@media screen and (min-width: 768px) {
.share__modal_btn {
padding: 0.9em 1.75em;
font-size: var(--share-link-span);
}
.share__modal {
width: 28em;
height: 30em;
border-radius: 1.3em;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
}
.share__modal_content {
padding: 2.5em;
}
.list {
grid-template-columns: repeat(4, 1fr);
row-gap: 1.5em;
column-gap: 1em;
}
}
Desktop View
Mobile View
π€ Finally, To make our modal popup box intractive or actually work, we will be using few lines of javascript logic π§
Javascript code β¬οΈ
/*=============== SHOW MODAL ===============*/
const openBtn = document.querySelector(".share__modal_btn");
const modalContainer = document.querySelector(".share__modal");
if (openBtn && modalContainer) {
openBtn.addEventListener("click", () => {
modalContainer.classList.add("show-modal");
});
}
/*=============== CLOSE MODAL ===============*/
const closeBtn = document.querySelector(".close_modal_btn");
function closeModal() {
const modalContainer = document.querySelector(".share__modal");
modalContainer.classList.remove("show-modal");
}
closeBtn.addEventListener("click", closeModal);
/*====== ESC BUTTON TO CLOSE MODAL ======*/
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
closeModal();
}
});
So here we have three event listeners who are adding or removing the show-modal class from the modalContainer :
When OpenBtn is clicked, we want to add a show-modal class to modalContainer in order to show the modal to users.
When closeBtn is clicked, we perform the opposite operation to open the button that is to remove the show-modal class & hide the modal.
Escape key-down event listener on dom to hide the modal by simply calling the closeModal() function.
So, the end result will finally look like this β¬οΈ
and that's what we wanted π₯³π€
I hope you find this post to be helpful and thanks for reading it π
Conclusion
As always, I hope you found it interesting. If you noticed any
errors in this article, please mention them in the comments. π§π»βπ»
Top comments (2)
Although this is a good task to challenge yourself, I don't recommend you do this in business projects. Building a modal requires much attention, like locking the screen, close on clicking outside, beying responsive to keyboard events, having the correct aria, dynamic loading modal content, render it in a higher place in the DOM, etc.
Thank You & Yeah sure, I will definitely try to make it to the business level by considering the above suggestions. Thanks for reading this blog π₯³π€