Created
October 11, 2012 10:18
-
-
Save kixxauth/3871453 to your computer and use it in GitHub Desktop.
Good Modal Dialogs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Sane Modal</title> | |
<meta name="viewport" content="width=device-width"> | |
<link rel="stylesheet" href="positioned.css"> | |
</head><body> | |
<div id="base-layer"> | |
<header> | |
<hgroup> | |
<h1>Broken Modal</h1> | |
<h2>There are problems with long dialogs that require scrolling.</h2> | |
</hgroup> | |
</header> | |
<article> | |
<section class="section-aa"> | |
<h3>Call To Action</h3> | |
<p>Please, Please, Please click the button.</p> | |
<div> | |
<button class="open-dialog" href="#dialog">Open Dialog</button> | |
</div> | |
</section> | |
<section class="section-a"> | |
<h3>Section 1</h3> | |
<p> | |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin et justo sit | |
amet felis accumsan auctor. Sed interdum ultricies nulla, et bibendum eros | |
pellentesque sed. Nullam tincidunt elit in odio vestibulum suscipit. Aliquam | |
sed lectus eget magna suscipit rutrum. Proin eu mauris sapien. Class aptent | |
taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. | |
Sed quis mauris ac dolor mattis pulvinar eget a turpis. Fusce venenatis, erat | |
eget volutpat suscipit, arcu leo eleifend magna, faucibus feugiat urna est eu | |
mauris. | |
</p> | |
</section> | |
<section class="section-b"> | |
<h3>Section 2</h3> | |
<p> | |
Nunc eu vehicula ligula. Sed porta vestibulum suscipit. Donec scelerisque | |
libero at tortor fermentum sit amet scelerisque eros auctor. Vestibulum | |
sollicitudin viverra nulla, sed luctus odio condimentum in. Proin feugiat | |
venenatis dictum. Fusce eget arcu dolor, in egestas turpis. Nullam mattis | |
semper ligula a porttitor. | |
</p> | |
</section> | |
<section class="section-c"> | |
<h3>Section 3</h3> | |
<p> | |
Curabitur bibendum euismod nisl, id convallis lorem pellentesque sit | |
amet. Integer sed tortor vestibulum turpis feugiat gravida. Cras lacus | |
eros, varius sed egestas eget, eleifend at mi. Donec bibendum imperdiet | |
est, nec euismod massa pretium nec. Vestibulum ante ipsum primis in | |
faucibus orci luctus et ultrices posuere cubilia Curae; Praesent pulvinar | |
tincidunt mauris, ac viverra sem vehicula eget. In mollis condimentum | |
nisl, eget ultrices orci interdum quis. Aliquam non fermentum justo. | |
Morbi quis mattis metus. Mauris suscipit eleifend metus, eu cursus arcu | |
fermentum non. Vestibulum non libero condimentum felis gravida malesuada. | |
Curabitur egestas sem posuere est fringilla posuere. | |
</p> | |
</section> | |
<section class="section-d"> | |
<h3>Another Call To Action</h3> | |
<div> | |
<button class="open-dialog" href="#dialog">Open Dialog</button> | |
</div> | |
</section> | |
</article> | |
<footer> | |
<h4>Footer</h4> | |
<p> | |
Web Development by | |
<a href="http://www.kixx.name" | |
title="This website is built by Kris Walker.">Kris Walker</a>. | |
</p> | |
</footer> | |
<!-- | |
Markup for the modal dialog is all inside this container, which will be | |
positioned absolutely by CSS in the external stylesheet. The default state is | |
"display:none;" which is set inline here. | |
--> | |
<div id="dialog" style="display:none;"> | |
<form id="dialog-form" action="/foo/bar" method="POST"> | |
<h3 class="header">Subscribe</h3> | |
<p> | |
<label for="id_email">Email:</label> | |
<input name="email" id="id_email" type="email" size="24" placeholder="[email protected]" /> | |
</p> | |
<p> | |
<label for="id_zip">Zip:</label> | |
<input name="zip" id="id_zip" type="text" size="8" placeholder="zip code" /> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<input type="submit" value="Subscribe" /> | |
<input type="reset" value="Cancel" /> | |
</p> | |
</form> | |
</div> | |
</div><!-- #base-layer --> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> | |
<script src="broken.js"></script> | |
</body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var VIEW = (function () { | |
var VIEW = {} | |
, $dialog = $('#dialog') | |
VIEW.showDialog = function () { | |
var $w = $(window) | |
, thisScrollPos = $w.scrollTop() | |
, offset | |
// determine the offset from the top of the page to position the dialog | |
// (adjust these numbers for your UI by experimenting) | |
offset = 20; // default | |
// If this is bigger than a smartphone, then offset should be 10% of | |
// the viewport | |
if ($w.innerWidth() > 700) { | |
offset = $w.innerHeight() * .1; | |
} | |
topPosition = thisScrollPos + offset; | |
// position and show the dialog | |
$dialog.css('top', topPosition + 'px').show(); | |
return false; // use this function as a click handler | |
}; | |
VIEW.closeDialog = function () { | |
$dialog.hide(); | |
return false; // use this function as a click handler | |
}; | |
return VIEW; | |
}()); | |
$('.open-dialog').click(VIEW.showDialog); | |
$('#dialog-form').on('submit reset', VIEW.closeDialog); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Base Styles */ | |
body { | |
color: #0f1318; | |
} | |
article section { | |
margin: 0; | |
padding: 6em 1em 2em; | |
} | |
.section-a { | |
background: #e2e7ed; | |
} | |
.section-b { | |
background: #cdd6e0; | |
} | |
.section-c { | |
background: #b8c4d3; | |
} | |
.section-d { | |
background: #a3b3c6; | |
} | |
footer { | |
margin-top: 2em; | |
background: #0f1318; | |
padding: 2em; | |
} | |
footer, footer a { | |
color: #fff; | |
} | |
/* The base layer wrapper changes to a fixed width box if the device screen is | |
* wider than 768px | |
*/ | |
@media (min-width: 768px) { | |
#base-layer { | |
width: 700px; | |
margin: 0 auto; | |
} | |
} | |
/* Dialog Styles */ | |
#dialog { | |
width: 90%; | |
margin-left: 4%; | |
border: 1px solid #0f1318; | |
background: #ecf0f3; | |
} | |
#dialog-form { | |
margin: 1em; | |
} | |
#dialog textarea { | |
width: 90%; | |
} | |
@media (min-width: 680px) { | |
#dialog { | |
width: 600px; | |
margin-left: auto; | |
margin-right: auto; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Sane Modal</title> | |
<meta name="viewport" content="width=device-width"> | |
<link rel="stylesheet" href="deck.css"> | |
</head><body> | |
<!-- All normal, non-dialog content goes in the base layer --> | |
<div id="base-layer"> | |
<div id="content-card"> | |
<header> | |
<hgroup> | |
<h1>The Card Deck With Smart Scroll Position</h1> | |
<h2>Your Users Will Love You</h2> | |
</hgroup> | |
</header> | |
<article> | |
<section class="section-aa"> | |
<h3>Call To Action</h3> | |
<p>Please, Please, Please click the button.</p> | |
<div> | |
<button class="open-dialog" href="#dialog">Open Dialog</button> | |
</div> | |
</section> | |
<section class="section-a"> | |
<h3>Section 1</h3> | |
<p> | |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin et justo sit | |
amet felis accumsan auctor. Sed interdum ultricies nulla, et bibendum eros | |
pellentesque sed. Nullam tincidunt elit in odio vestibulum suscipit. Aliquam | |
sed lectus eget magna suscipit rutrum. Proin eu mauris sapien. Class aptent | |
taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. | |
Sed quis mauris ac dolor mattis pulvinar eget a turpis. Fusce venenatis, erat | |
eget volutpat suscipit, arcu leo eleifend magna, faucibus feugiat urna est eu | |
mauris. | |
</p> | |
</section> | |
<section class="section-b"> | |
<h3>Section 2</h3> | |
<p> | |
Nunc eu vehicula ligula. Sed porta vestibulum suscipit. Donec scelerisque | |
libero at tortor fermentum sit amet scelerisque eros auctor. Vestibulum | |
sollicitudin viverra nulla, sed luctus odio condimentum in. Proin feugiat | |
venenatis dictum. Fusce eget arcu dolor, in egestas turpis. Nullam mattis | |
semper ligula a porttitor. | |
</p> | |
</section> | |
<section class="section-c"> | |
<h3>Section 3</h3> | |
<p> | |
Curabitur bibendum euismod nisl, id convallis lorem pellentesque sit | |
amet. Integer sed tortor vestibulum turpis feugiat gravida. Cras lacus | |
eros, varius sed egestas eget, eleifend at mi. Donec bibendum imperdiet | |
est, nec euismod massa pretium nec. Vestibulum ante ipsum primis in | |
faucibus orci luctus et ultrices posuere cubilia Curae; Praesent pulvinar | |
tincidunt mauris, ac viverra sem vehicula eget. In mollis condimentum | |
nisl, eget ultrices orci interdum quis. Aliquam non fermentum justo. | |
Morbi quis mattis metus. Mauris suscipit eleifend metus, eu cursus arcu | |
fermentum non. Vestibulum non libero condimentum felis gravida malesuada. | |
Curabitur egestas sem posuere est fringilla posuere. | |
</p> | |
</section> | |
<section class="section-d"> | |
<h3>Another Call To Action</h3> | |
<div> | |
<button class="open-dialog" href="#dialog">Open Dialog</button> | |
</div> | |
</section> | |
</article> | |
<footer> | |
<h4>Footer</h4> | |
<p> | |
Web Development by | |
<a href="http://www.kixx.name" | |
title="This website is built by Kris Walker.">Kris Walker</a>. | |
</p> | |
</footer> | |
</div><!-- #content-card --> | |
<!-- | |
Markup for the modal dialog is all inside this card container. The default | |
state is "display:none;" which is set inline here. | |
--> | |
<div id="dialog" style="display:none;"> | |
<form id="dialog-form" action="/foo/bar" method="POST"> | |
<h3 class="header">Subscribe</h3> | |
<p> | |
<label for="id_email">Email:</label> | |
<input name="email" id="id_email" type="email" size="24" placeholder="[email protected]" /> | |
</p> | |
<p> | |
<label for="id_zip">Zip:</label> | |
<input name="zip" id="id_zip" type="text" size="8" placeholder="zip code" /> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<input type="submit" value="Subscribe" /> | |
<input type="reset" value="Cancel" /> | |
</p> | |
</form> | |
</div><!-- #dialog --> | |
</div><!-- #base-layer --> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> | |
<script src="deck.js"></script> | |
</body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var VIEW = (function () { | |
var VIEW = {} | |
, $dialogCard = $('#dialog') | |
, $contentCard = $('#content-card') | |
, scrollPos = null | |
VIEW.showDialog = function () { | |
var $w = $(window) | |
, thisScrollPos = $w.scrollTop() | |
, offset | |
// Cache the current scroll position of the base layer. This is the | |
// last place where the user has seen the base layer, and we want to | |
// be able to put them right back there after the modal dialog | |
// closes. | |
if (scrollPos === null) scrollPos = thisScrollPos; | |
// hide the main content | |
$contentCard.hide(); | |
// Put the dialog into the layout flow, but don't reveal it to the user | |
// until we have scrolled into position. | |
$dialogCard.css('visibility', 'hidden').show(); | |
$w.scrollTop(0); | |
$dialogCard.css('visibility', 'visible'); | |
return false; // use this function as a click handler | |
}; | |
VIEW.closeDialog = function () { | |
$dialogCard.hide(); // hide the dialog | |
// Put the content card back into the layout flow, but it will not be visible | |
// to the user, since 'visiblity: hidden;' is set. | |
$contentCard.css('visibility', 'hidden').show(); | |
// Return the base view back to the scroll position where the user last | |
// saw it. This way, they don't get lost on your UI. | |
$(window).scrollTop(scrollPos); | |
scrollPos = null; // Reset for the next dialog open event | |
// then show the content card to the user again | |
$contentCard.css('visibility', 'visible'); | |
return false; // use this function as a click handler | |
}; | |
return VIEW; | |
}()); | |
$('.open-dialog').click(VIEW.showDialog); | |
$('#dialog-form').on('submit reset', VIEW.closeDialog); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Base Styles */ | |
body { | |
color: #0f1318; | |
} | |
article section { | |
margin: 0; | |
padding: 6em 1em 2em; | |
} | |
.section-a { | |
background: #e2e7ed; | |
} | |
.section-b { | |
background: #cdd6e0; | |
} | |
.section-c { | |
background: #b8c4d3; | |
} | |
.section-d { | |
background: #a3b3c6; | |
} | |
footer { | |
margin-top: 2em; | |
background: #0f1318; | |
padding: 2em; | |
} | |
footer, footer a { | |
color: #fff; | |
} | |
/* The base layer wrapper changes to a fixed width box if the device screen is | |
* wider than 768px | |
*/ | |
@media (min-width: 768px) { | |
#base-layer { | |
width: 700px; | |
margin: 0 auto; | |
} | |
} | |
/* Dialog Styles */ | |
#dialog { | |
position: absolute; | |
width: 90%; | |
margin-left: 4%; | |
border: 1px solid #0f1318; | |
background: #ecf0f3; | |
} | |
#dialog-form { | |
margin: 1em; | |
} | |
#dialog textarea { | |
width: 90%; | |
} | |
@media (min-width: 680px) { | |
#dialog { | |
width: 600px; | |
left: 50%; | |
margin-left: -300px; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Sane Modal</title> | |
<meta name="viewport" content="width=device-width"> | |
<link rel="stylesheet" href="positioned.css"> | |
</head><body> | |
<!-- All normal, non-dialog content goes in the base layer --> | |
<div id="base-layer"> | |
<header> | |
<hgroup> | |
<h1>Hiding The Background Caching the Scroll Position</h1> | |
<h2>This is an improvement, but not great.</h2> | |
</hgroup> | |
</header> | |
<article> | |
<section class="section-aa"> | |
<h3>Call To Action</h3> | |
<p>Please, Please, Please click the button.</p> | |
<div> | |
<button class="open-dialog" href="#dialog">Open Dialog</button> | |
</div> | |
</section> | |
<section class="section-a"> | |
<h3>Section 1</h3> | |
<p> | |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin et justo sit | |
amet felis accumsan auctor. Sed interdum ultricies nulla, et bibendum eros | |
pellentesque sed. Nullam tincidunt elit in odio vestibulum suscipit. Aliquam | |
sed lectus eget magna suscipit rutrum. Proin eu mauris sapien. Class aptent | |
taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. | |
Sed quis mauris ac dolor mattis pulvinar eget a turpis. Fusce venenatis, erat | |
eget volutpat suscipit, arcu leo eleifend magna, faucibus feugiat urna est eu | |
mauris. | |
</p> | |
</section> | |
<section class="section-b"> | |
<h3>Section 2</h3> | |
<p> | |
Nunc eu vehicula ligula. Sed porta vestibulum suscipit. Donec scelerisque | |
libero at tortor fermentum sit amet scelerisque eros auctor. Vestibulum | |
sollicitudin viverra nulla, sed luctus odio condimentum in. Proin feugiat | |
venenatis dictum. Fusce eget arcu dolor, in egestas turpis. Nullam mattis | |
semper ligula a porttitor. | |
</p> | |
</section> | |
<section class="section-c"> | |
<h3>Section 3</h3> | |
<p> | |
Curabitur bibendum euismod nisl, id convallis lorem pellentesque sit | |
amet. Integer sed tortor vestibulum turpis feugiat gravida. Cras lacus | |
eros, varius sed egestas eget, eleifend at mi. Donec bibendum imperdiet | |
est, nec euismod massa pretium nec. Vestibulum ante ipsum primis in | |
faucibus orci luctus et ultrices posuere cubilia Curae; Praesent pulvinar | |
tincidunt mauris, ac viverra sem vehicula eget. In mollis condimentum | |
nisl, eget ultrices orci interdum quis. Aliquam non fermentum justo. | |
Morbi quis mattis metus. Mauris suscipit eleifend metus, eu cursus arcu | |
fermentum non. Vestibulum non libero condimentum felis gravida malesuada. | |
Curabitur egestas sem posuere est fringilla posuere. | |
</p> | |
</section> | |
<section class="section-d"> | |
<h3>Another Call To Action</h3> | |
<div> | |
<button class="open-dialog" href="#dialog">Open Dialog</button> | |
</div> | |
</section> | |
</article> | |
<footer> | |
<h4>Footer</h4> | |
<p> | |
Web Development by | |
<a href="http://www.kixx.name" | |
title="This website is built by Kris Walker.">Kris Walker</a>. | |
</p> | |
</footer> | |
</div><!-- #base-layer --> | |
<!-- | |
Markup for the modal dialog is all inside this container, which will be | |
positioned absolutely by CSS in the external stylesheet. The default state is | |
"display:none;" which is set inline here. | |
--> | |
<div id="dialog" style="display:none;"> | |
<form id="dialog-form" action="/foo/bar" method="POST"> | |
<h3 class="header">Subscribe</h3> | |
<p> | |
<label for="id_email">Email:</label> | |
<input name="email" id="id_email" type="email" size="24" placeholder="[email protected]" /> | |
</p> | |
<p> | |
<label for="id_zip">Zip:</label> | |
<input name="zip" id="id_zip" type="text" size="8" placeholder="zip code" /> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<label>Another Question:</label><br /> | |
<textarea rows="8"></textarea> | |
</p> | |
<p> | |
<input type="submit" value="Subscribe" /> | |
<input type="reset" value="Cancel" /> | |
</p> | |
</form> | |
</div><!-- #dialog --> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> | |
<script src="positioned.js"></script> | |
</body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var VIEW = (function () { | |
var VIEW = {} | |
, $dialog = $('#dialog') | |
, $base = $('#base-layer') | |
, scrollPos = null | |
function hideBaseLayer() { | |
// by using visibility:hidden; we are able to maintain scroll position | |
$base.css('visibility', 'hidden'); | |
} | |
function showBaseLayer() { | |
// Return the base view back to the scroll position where the user last | |
// saw it. This way, they don't get lost on your UI. | |
$(window).scrollTop(scrollPos); | |
scrollPos = null; // Reset for the next dialog open event | |
$base.css('visibility', 'visible'); // then show the base layer again | |
} | |
VIEW.showDialog = function () { | |
var $w = $(window) | |
, thisScrollPos = $w.scrollTop() | |
, offset | |
// Cache the current scroll position of the base layer. This is the | |
// last place where the user has seen the base layer, and we want to | |
// be able to put them right back there after the modal dialog | |
// closes. | |
if (scrollPos === null) scrollPos = thisScrollPos; | |
hideBaseLayer(); // Make the base layer invisible | |
// determine the offset from the top of the page to position the dialog | |
// at. (adjust these numbers for your UI by experimenting) | |
offset = 20 // default | |
// If this is bigger than a smartphone, then offset should be 10% of | |
// the viewport | |
if ($w.innerWidth() > 700) { | |
offset = $w.innerHeight() * .1; | |
} | |
topPosition = thisScrollPos + offset; | |
// position and show the dialog | |
$dialog.css('top', topPosition + 'px').show(); | |
return false; // use this function as a click handler | |
}; | |
VIEW.closeDialog = function () { | |
$dialog.hide(); | |
showBaseLayer(); | |
return false; // use this function as a click handler | |
}; | |
return VIEW; | |
}()); | |
$('.open-dialog').click(VIEW.showDialog); | |
$('#dialog-form').on('submit reset', VIEW.closeDialog); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment