I recently read this article about creating a pure CSS modal box:
- Creating a modal window with HTML5 & CSS3
I've tested the code and it works great. I'm using it for my site's contact and register/log-in pages.
There is one part of the code I haven't fully grasped.
How does this...
<a href="#close" title="Close" class="close">X</a>
...close the box?
There is nothing in the CSS that hides or removes an element with a close
class, nor any similar function targeting href
, #close
or title
. It's simply that one line of code by itself, and when the use clicks on it, the modal window closes (neatly and elegantly, I might add).
It's clear that the "close" text doesn't matter. The text could be anything and the function works. But if "#" is removed, the styling fails, but the window still closes.
So what's so special about "#"?
.modalDialog {
position: fixed;
font-family: Arial, Helvetica, sans-serif;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.8);
z-index: 99999;
opacity: 0;
transition: opacity 400ms ease-in;
pointer-events: none;
}
.modalDialog:target {
opacity: 1;
pointer-events: auto;
}
.modalDialog > div {
width: 400px;
position: relative;
margin: 10% auto;
padding: 5px 20px 13px 20px;
border-radius: 10px;
background: #fff;
}
.close {
background: #606061;
color: #FFFFFF;
line-height: 25px;
position: absolute;
right: -12px;
text-align: center;
top: -10px;
width: 24px;
text-decoration: none;
font-weight: bold;
border-radius: 12px;
box-shadow: 1px 1px 3px #000;
}
.close:hover {
background: #00d9ff;
}
<a href="#openModal">Open Modal</a>
<div id="openModal" class="modalDialog">
<div>
<a href="#" title="Close" class="close">X</a>
<h2>Modal Box</h2>
<p>This is a sample modal box that can be created using the powers of CSS3.</p>
<p>You could do a lot of things here like have a pop-up ad that shows when your website loads, or create a login/register form for users.</p>
</div>
</div>
When you click on href="#openModal", it finds the fragment with id="openModal" and puts the focus on it. Changing its state. The css .modalDialog:target comes into action making the modal visible with opacity:1.
When you click on href="#close", it tries to find fragment id="close", which is not present. It also removes focus from any other fragment, making modalDialog loose focus. So nothing remains in focus. and modal closes.
The hash mark #
matters for two reasons.
- provides the
target
as an internal location.
- allows the
target
to change, thereby allowing the modal to close, via CSS.
By definition, the character string that follows the #
represents the URL fragment.
From MDN
A URL fragment is a name preceded by a hash mark (#), which specifies an internal target location (an ID) within the current document.
Though its commonly re-purposed when used with scripts [1], when used by itself - the hash mark without a name represents an empty fragment identifier (exhibiting the scroll to top behaviour).
While navigating to a fragment, the algorithm involved can be read about in the HTML5 docs which includes a reference to this behaviour.
If fragid is the empty string, then the indicated part of the document is the top of the document.
Context
If just the #
mark is used, when the modal is closed, we will observe a scroll top. Provided the contents of the page exceed the viewport and the modal is opened somewhere halfway down.
If #
is removed, the empty href
simply hyperlinks to your current document, thereby reloading the page.
The CSS Modal example uses #close
which may not make much sense, but it prevents the scroll to top behaviour by referencing it to an internal location which does not exist. Probably not the right way, but this usage points to a preventDefault()
implemented via CSS. Thus making it a 'Pure CSS Modal'.
Here is an example.
.scrollable-area {
min-height: 150vh
}
<span>Top of Document</span>
<div class="scrollable-area"></div>
<a href="#">Empty. Scroll to top.</a><br>
<a href="#close">Non Empty. Stay Put.</a>
References:
- https://stackoverflow.com/a/11246131/5496966
- [1] - Repurposing the Hash Sign for the New Web
First, to clarify:
The :target pseudo-class is used to style an element that is the
target of an internal link in a document.
This element is not on any focus state, it is just the target of an internal link.
Basically, the #
represents a fragment identifier within a HTML Object. It follows the URL of the whole object, that's why the #
is needed as a separation.
The fragment identifier at the end of the URI is also known as the
“hash” of the URL.
So, the real question...
What happens if you do not declare the hash?
When the fragment id is not present or void, the target is now the whole object. Meaning the target is now your whole HTML document.
You can see this behavior when you close your modal, it will jump all the way to the top of your document to your <html>
tag.
See this here after scrolling:
body {
height: 300vh;
}
a:first-of-type {
position: fixed;
}
.modalDialog {
position: fixed;
font-family: Arial, Helvetica, sans-serif;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.8);
z-index: 99999;
opacity: 0;
transition: opacity 400ms ease-in;
pointer-events: none;
}
.modalDialog:target {
opacity: 1;
pointer-events: auto;
}
.modalDialog > div {
width: 400px;
position: relative;
margin: 10% auto;
padding: 5px 20px 13px 20px;
border-radius: 10px;
background: #fff;
}
.close {
background: #606061;
color: #FFFFFF;
line-height: 25px;
position: absolute;
right: -12px;
text-align: center;
top: -10px;
width: 24px;
text-decoration: none;
font-weight: bold;
border-radius: 12px;
box-shadow: 1px 1px 3px #000;
}
.close:hover {
background: #00d9ff;
}
<a href="#openModal">Open Modal</a>
<div id="openModal" class="modalDialog">
<div>
<a href="#" title="Close" class="close">X</a>
<h2>Modal Box</h2>
<p>This is a sample modal box that can be created using the powers of CSS3.</p>
<p>You could do a lot of things here like have a pop-up ad that shows when your website loads, or create a login/register form for users.</p>
</div>
</div>
On a side note:
I'm working on something similar in my website, currently using two modals with pure CSS, and stumbled upon the problem that it was jumping all the way to the top, that's why I made some research. I didn't want this behavior, so what I did is I defined an id to my fixed menu and made that the fragment id of the close button.
What you can do however is define an empty element with an id right next to your opening element, so that it will not jump to the top when you close your modal.
"hash mark" is a selector (in js, css...) to point an ID, so if you have <div id="test">
and you want to apply some functionality or some css styling with js you will select it as '#test' (the code will be different if you use jQuery framework or not). Jquery is the most used nowadays so you'll find $('#test'). I'll try to explain how modals closing work, but first I need to explain all modal parts to put us in situation As explanation I will use as example bootstrap's modal (as its the most used at this moment). The modal:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Example</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Modal Example</h2>
<!-- Trigger the modal with a button -->
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#myModal">Open Modal</button>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<p>Some text in the modal.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
The "Trigger" part:
To trigger the modal window, you need to use a button or a link.
Then include the two data-* attributes:
data-toggle="modal" opens the modal window
data-target="#myModal" points to the id of the modal
The "Modal" part:
The parent <div>
of the modal must have an ID that is the same as the value of the data-target attribute used to trigger the modal ("myModal").
The .modal class identifies the content of <div>
as a modal and brings focus to it.
The .fade class adds a transition effect which fades the modal in and out. Remove this class if you do not want this effect.
The attribute role="dialog" improves accessibility for people using screen readers.
The .modal-dialog class sets the proper width and margin of the modal.
The "Modal content" part:
The <div>
with class="modal-content" styles the modal (border, background-color, etc.). Inside this <div>
, add the modal's header, body, and footer.
The .modal-header class is used to define the style for the header of the modal. The <button>
inside the header has a data-dismiss="modal" attribute which closes the modal if you click on it. The .close class styles the close button, and the .modal-title class styles the header with a proper line-height.
The .modal-body class is used to define the style for the body of the modal. Add any HTML markup here; paragraphs, images, videos, etc.
The .modal-footer class is used to define the style for the footer of the modal. Note that this area is right aligned by default.
Modal Size
Change the size of the modal by adding the .modal-sm class for small modals or .modal-lg class for large modals.
Add the size class to the <div>
element with class .modal-dialog:
Small:
<div class="modal-dialog modal-sm">
Large:
<div class="modal-dialog modal-lg">
NOTE: To let modal at medium size let it "as is" without adding modal-* class. By default, modals are medium in size.
To resume and answer your question, the button with data-dismiss="modal" and the close class are readed by bootstrap's javaScript (using jQuery, but this is not relevant in that case) then changes the display:block; to display:none; and many other stylings, compare yourself:
Opened modal:
bottom:0px;
box-sizing:border-box;
color: rgb(51, 51, 51);
display:block;
font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
font-size:14px;
height:89px;
left:0px;
line-height:20px;
opacity:1;
outline-color:rgb(51, 51, 51);
outline-style:none;
outline-width:0px;
overflow-x:hidden;
overflow-y:auto;
padding-left:17px;
position:fixed;
right:0px;
top:0px;
transition-delay:0s;
transition-duration:0.15s;
transition-property:opacity;
transition-timing-function:linear;
width:1329px;
z-index:1050;
Closed modal:
bottom:0px;
box-sizing:border-box;
color:rgb(51, 51, 51);
display:none; /* changed */
font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
font-size:14px;
height:auto; /* changed */
left:0px;
line-height:20px;
opacity:0; /* changed */
outline-color:rgb(51, 51, 51);
outline-style:none;
outline-width:0px;
overflow-x:hidden;
overflow-y:hidden;
position:fixed;
right:0px;
top:0px;
transition-delay:0s;
transition-duration:0.15s;
transition-property:opacity;
transition-timing-function:linear;
width:auto; /* changed */
z-index:1050;
Note that others like padding-left disappeared.
This can be reached simply using jQuery as this:
<script type="text/javascript">
$('#CloseButtonID').click(){
$('#modalID').css('display','none');
$('#modalID').css('opacity', 0);
}
</script>
In your case, using simply css3 modal, the fact is on modalDialog, when is on :target state it changes opacity:0 to opacity:1. How?
When you click on <a href="#openModal">
the target points to <div id="openModal" class="modalDialog">
(note that # points to an ID), so modalDialog changes to modalDialog:target.
And what about closing the modal?
When you click on <a href="#">
the target goes to # (when # is used single on href means the same page where you are) so it makes modalDialog loose the :target and comes back to opacity: 0;
Expanding on my comment, this modal example is wholly dependent on the fragment identifier of the url. It is not only used to "trigger" the modal display in the first place but it is also used within the anchor link to suppress the href. The text following the #
is irrelevant in this case and should be omitted.
As the article explains, it uses a :target in the CSS to trigger opacity: 1; Open the box, inspect the close class and change the opacity value to see what actually happens.