Thumbnail Image

Date Posted: Mar 02 2017

Tags: CSS, Design, Responsive, Layout, Fluid, Pop-Up

Creating Pure CSS Modal Pop-ups

Many modern websites utilise modal pop-ups for magnifying content, displaying notifications, offers, input forms and much more. Modal pop-ups are extremely practical, as they do not require the page to be reloaded to display further content on user interaction.

You will come across multiple websites that utilise modal pop-ups by employing external resources or scripting languages such as Javascript. However, there are several alternative methods available that can achieve the same effect using only CSS and HTML; over the next couple of weeks, I will show you a few of my preferred methods.

This particular article will demonstrate a trick you can use, with URL anchor tags and the CSS selector :target, to create modal popups.

Click to view a demo of the Pure CSS Modal Pop-up that we will be creating.

SETTING UP THE BASIC LAYOUT

We are going to recreate the example shown in the demo above. The first step will be to set up a basic HTML markup and link to a stylesheet to contain the CSS styles that we will be applying throughout the article:


<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="x-au-compatible" content="ie=edge">
	<title>CSS Modal Pop-Ups</title>
	<meta name="description" content="CSS Modal Pop-Ups">
	<meta name="author" content="Author Name Here">
	<meta name="viewport" content="width=device-width, intitial scale=1">
	<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
</body>
</html>

Add a background colour to the page body:


body {
	background: #50527A;
}

Next, we will create an interactive menu so that we can select the pop-ups we would like to display. Create a div element with the id menu and 3 child div elements with the class button.


<body>
	<div id="menu">
		<div class="button"></div><div class="button"></div><div class="button"></div>
	</div>
</body>

Now add the following CSS styles to the id menu.


#menu {
	display: block;
	position: relative;
	width: 80%;
	max-width: 500px;
	height: 100px;
	margin: 0 auto;
	border-radius: 0 0 15px 15px;
	background: #FFF;
}

Why use max-width?

We could simply set a width of 500px. However, this would break on any devices with an available display of less than 500px width.

To avoid these complications, we will first declare a fluid width of 80%; this gives us a width value of 80% of the available display and allows the remaining 20% to be available for left and right margins. By declaring max-width as 500px the width will be capped at 500px even when 80% of the display's width is greater than 500px.

margin: 0 auto

In cases where the width is capped at 500px by max-width the space remaining on either side of the pop-up is going to be greater than 20%. We use the left and right margin value of auto to centre the menu div element, leaving margins of equal size to the left and right of the element.

Next, add the following styles for the class button:


.button {
	display: inline-block;
	width: 30%;
	height: 70px;
	margin: 15px 0 15px 2.5%;
	border-radius: 15px;
	text-align: center;
	background: #FF5C63;
}

Using the display value inline-block allows the buttons to be positioned next to each other, rather than each one on a new line. We need to declare this to override the default display value for a div element; the default value is block.

As there are 3 buttons, we will use a fluid width value of 30%, leaving us with 10% width available for spacing. To separate the buttons evenly, we will set a fluid left margin of 2.5% to the button class.

Note that we leave no spacing between the div elements with button class in our HTML markup, as inline elements are affected by whitespace in the markup; and spaces between the inline-block styled div elements would break the fluid spacing of the buttons.

It can become quite hard to read the markup when elements have no spacing between them, here is an optional trick you can use to solve this:


<body>
	<div id="menu">
		<div class="button"></div><!--
		--><div class="button"></div><!--
		--><div class="button"></div>
	</div>
</body>

By adding HTML Comments between the inline elements, you can create whitespace in your markup that will be ignored by the inline elements. Using HTML Comments is an optional step and a personal preference I use myself, as I find when the markup gets more complicated it is a lot easier to read when formatted in this way.

Now add a paragraph element to each button that will contain the corresponding number to its pop-up:


<body>
	<div id="menu">
		<div class="button"><p>1</p></div><!--
		--><div class="button"><p>2</p></div><!--
		--><div class="button"><p>3</p></div>
	</div>
</body>

Add some styling to the text and also a nice hover effect to the button:


.button p {
	color: #FFF;
	font-size: 20px;
	font-family: Verdana, Geneva, sans-serif;
}

.button:hover {
	background: #FF797F;
}

If you find that your menu is not flush to the top of the page like in the image below, this may be due to default margin settings applied to the body element. Default margins differ depending on the browser used, and not all browsers share the same default values.

Image example of default margin spacing

For now, add a margin with the value of 0 to the body styles:


body {
	background: #50527A;
	margin: 0;
}

I highly recommend checking out normalize.css at https://necolas.github.io/normalize.css/.
Normalize.css is a small CSS file that you can include in your projects, which resets browser default values and allows a more consistent rendering of your projects across all browsers.

CREATING THE POP-UPS

We now have a menu for controlling our modal pop-ups which we will come back to later. Now we need to create the actual pop-ups.

Create a div element with the id popup1 below the menu div element; it requires no styles.


<body>
	<div id="menu">
		<div class="button"><p>1</p></div><!--
		--><div class="button"><p>2</p></div><!--
		--><div class="button"><p>3</p></div>
	</div>
	<div id="popup1">
	</div>
</body>

We are going to add a dark overlay with a slightly transparent opacity that covers the full page behind our pop-up, this is commonly known as fog.

Create a div element with the class popup-fog as a child of the div with id popup1:


<div id="popup1">
	<div class="popup-fog"></div>
</div>

Apply the following styles:


.popup-fog {
	position: fixed;
	top: 0;
	left: 0;
	height: 100%;
	width: 100%;
	background: rgba(0,0,0,0.4);
}

We are using a position value of fixed; this places the element relative to the browser window rather than to its parent element.

Top and Left values of 0 declare the position of the fixed element.

Using height and width values of 100% creates an element that fills the full size of the page.

The background colour is an RGBA (Red, Green, Blue, Alpha) value. The red, green and blue values set to 0 give us a black colour. The alpha value determines the opacity of the background colour, 0 being fully transparent with an opacity of 0% and 1 being fully opaque with an opacity of 100%. We are using the value 0.4, the equivalent of 40% opacity.

You should now have a dark overlay covering your page like in the image example below:

Image example of dark overlay

Next, create a new div element also as a child of popup1 with the class popup-window; this is going to be the container for the modal pop-up.


<div id="popup1">
	<div class="popup-fog"></div>
	<div class="popup-window"></div>
</div>

Apply the following styles:


.popup-window {
	position: fixed;
	top: 50%;
	left: 50%;
	-o-transform: translate(-50%, -50%);
	-moz-transform: translate(-50%, -50%);
	-webkit-transform: translate(-50%, -50%);
	-ms-transform: translate(-50%, -50%);
	transform: translate(-50%, -50%);
	height: 300px;
	width: 300px;
	max-width: 70%;
	max-height: 70%;
	background: #FFF;
	border-radius: 15px;
	text-align: center;
}

Again we use a position value of fixed. This time, however, we want the element to be centred vertically and horizontally.

Vertically centring an element can be difficult in CSS, especially when we are not using a fixed height, but this can be achieved by using the CSS transform property. This trick allows us to centre a fluid sized element both horizontally and vertically.

Using a top and left value of 50% centres the element by positioning it 50% from the left and top of its parent. In this case, due to our element being of fixed position, it will be 50% left and top of the page. Unfortunately, it does not centre the element from the centre point of the element itself but instead from the top-left corner of the element.

Luckily, when using a percentage value with transform translate the value is calculated based on the size of the applied element rather than the size of its parent. For example, if the element was of 280px width; translating the object 50% will move the object by 140px regardless of the size of the element's parent.

Knowing this we can translate the element -50% vertically and horizontally; this moves the element by half of its width and height towards the left and top of the page, this corresponds to the exact amount required to move the element’s centre point to the centre point of the page.

You should now have a container for your modal pop-ups as shown below:

Image example of modal-popup container

Let's add a close button and also a paragraph element to number this pop-up modal for our reference.

Starting with the close button, create a div element with the class close, with a paragraph element containing the text "CLOSE" as a child of popup-window.


<div id="popup1">
	<div class="popup-fog"></div>
	<div class="popup-window">
		<div class="close"><p>CLOSE</p></div>
	</div>
</div>

Style the close class with the following styles:


.close {
	display: inline-block;
	width: auto;
	height: auto;
	margin: 10px auto;
	padding: 5px 20px;
	border-radius: 15px;
	text-align: center;
	background: #4285F4;
}

.close:hover {
	background: #4399F9;
}

We are going to use the same styles for this paragraph element that were used previously for the paragraph element that is a child of the button class. To avoid code replication, we will add the following selector to the previous styles:


.button p, .close p {
	color: #FFF;
	font-size: 20px;
	font-family: Verdana, Geneva, sans-serif;
}


Next, add a paragraph element with the text "1" as a child of popup-window; This is to identify the modal pop-up, as we will be adding 3 in total, one for each button on the menu.


<div id="popup1">
	<div class="popup-fog"></div>
	<div class="popup-window">
		<div class="close"><p>CLOSE</p></div>
		<p>1</p>
	</div>
</div>

You should now have a modal pop-up like the one in the image below:

Image example of modal-popup

We now want to hide the modal pop-up we have created. We are going to do this by changing the height value of popup-fog and popup-window to 0 so that they are no longer visible. We will also add an overflow value of hidden to popup-window so that the contents contained will also not be displayed as they overflow the 0 height.


.popup-fog {
	position: fixed;
	top: 0;
	left: 0;
	height: 0;
	width: 100%;
	background: rgba(0,0,0,0.4);
}

.popup-window {
	position: fixed;
	top: 50%;
	left: 50%;
	-o-transform: translate(-50%, -50%);
	-moz-transform: translate(-50%, -50%);
	-webkit-transform: translate(-50%, -50%);
	-ms-transform: translate(-50%, -50%);
	transform: translate(-50%, -50%);
	height: 0;
	width: 300px;
	max-width: 70%;
	max-height: 70%;
	background: #FFF;
	border-radius: 15px;
	text-align: center;
	overflow: hidden;
}

The modal pop-up and fog are no longer visible.

Using the CSS selector :target we can make the modal pop-up visible again when we click the corresponding button on the menu.

Add the following CSS selectors and styles:


#popup1:target .popup-fog {
	height: 100%;
}

#popup1:target .popup-window {
	height: 300px;
}

When the id popup1 is targeted, the height styles will apply to popup-fog and popup-window.

To target the popup1 id we add the anchor tag #popup1 to the end of the URL. So, for example, if the URL is:


		www.website.com/index.html#popup1
	

popup1 will be targeted.

Adding #popup1 to the URL is simple, and is achieved by adding an HTML anchor to the button element:


<div id="menu">
		<a href="#popup1"><div class="button"><p>1</p></div></a><!--
		--><div class="button"><p>2</p></div><!--
		--><div class="button"><p>3</p></div>
	</div>

Now when we click the button, it will add #popup1 to the URL without reloading the page.

We also need to add an HTML anchor to our close button to remove #popup1 from the URL; this will remove the targeting and will result in the :target styles no longer applying.

An optional feature is to add an HTML anchor to popup-fog so that if a user clicks away from the modal pop-up, it will also close.


<div id="popup1">
		<a href="#"><div class="popup-fog"></div></a>
		<div class="popup-window">
			<a href="#"><div class="close"><p>CLOSE</p></div></a>
			<p>1</p>
		</div>
	</div>

As a result of adding an anchor element to the popup-fog element we now get a pointer cursor when hovering over the element, we can remove the pointer by adding cursor: default style to the popup-fog element.


.popup-fog {
	position: fixed;
	top: 0;
	left: 0;
	height: 0;
	width: 100%;
	background: rgba(0,0,0,0.4);
	cursor: default;
}

We now have a fully functioning modal pop-up.

Lastly, we will add 2 additional modal pop-ups to correspond with our other 2 buttons.


<body>
	<div id="menu">
		<a href="#popup1"><div class="button"><p>1</p></div></a><!--
		--><a href="#popup2"><div class="button"><p>2</p></div></a><!--
		--><a href="#popup3"><div class="button"><p>3</p></div></a>
	</div>
	<div id="popup1">
		<a href="#"><div class="popup-fog"></div></a>
		<div class="popup-window">
			<a href="#"><div class="close"><p>CLOSE</p></div></a>
			<p>1</p>
		</div>
	</div>
	<div id="popup2">
		<a href="#"><div class="popup-fog"></div></a>
		<div class="popup-window">
			<a href="#"><div class="close"><p>CLOSE</p></div></a>
			<p>2</p>
		</div>
	</div>
	<div id="popup3">
		<a href="#"><div class="popup-fog"></div></a>
		<div class="popup-window">
			<a href="#"><div class="close"><p>CLOSE</p></div></a>
			<p>3</p>
		</div>
	</div>
</body>

Also add the following selectors to our previous styles for popup1:target to avoid code replication:


#popup1:target .popup-fog, #popup2:target .popup-fog, #popup3:target .popup-fog {
	height: 100%;
}

#popup1:target .popup-window, #popup2:target .popup-window, #popup3:target .popup-window {
	height: 300px;
}

This method of using the CSS :target selector can be used to toggle many different features. For example, it could also be used to toggle animations, sidebars, font-size and much more.

The key benefit of this method compared to others is that you can trigger the :target styles on page load by linking to the page with the anchor tag included, other methods first require user interaction to trigger.

In my next article, I will be going over one of my favourite methods that utilise HTML forms, labels and checkboxes. This approach does not require modification of URLS.

Feel free to post any of your projects using this technique in the comments as we would love to see your creations.

Author Avatar

BY CODIN

Owner of Codesmite.com

Codin is a self taught web developer based in London, UK.
Over the years he has dedicated a lot of time to helping new developers, becoming a well known moderator at Team Treehouse