问题
Is there any way of freezing the browser window intentionally like alert
, confirm
and prompt
(in short: "acp") does?
I want to show a modal dialog with custom css instead of the native popups for "acp" but also want to have the ability to freeze the browser until I have users feedback just like "acp".
But man, why? This is bad practice (uh I have to downvote)!
So when it is bad practice - then why does "acp" actually offer this synchronous behavior? Because in some particular scenarios its just exactly the right tool for an appropriate UX. Those native modals do look so ugly and are also very limited at the same time.
Here's just one quick and dirty example where it would be totally fine to freeze the browser until the user gives feedback. Lets say we have a form
with an input[type="reset"]
-element. So before we really let the form
reset we ask the user something like: "Are you sure you want to reset (data will be lost)?".
If I would be fine with the native modal look (which I'm not) I could do:
var handleSubmit = function( e ) {
confirm('Are you sure you want to reset (data will be lost)?') || e.preventDefault()
};
$('form').on( 'reset', handleSubmit ); // just using jQuery here for the sake of shortness
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<input placeholder="type something, reset and cancel to keep input value" style="width:100%">
<input type="reset">
</form>
So "everybody" should agree (edit: or at least somebody could) this isn't bad practice, right?
But how can we achieve the same with a custom styled modal/dialog/popup?
I'm -of course- not asking for the HTML
/CSS
part but for the capability of freezing the browser window via JavaScript!
To be honest, I actually expect some downvotes for this but maybe there is this one Killer JavaScript Ninja, who have this one special hack to make it possible...
NOTE: I know exactly how to achieve the same result in the end but I'm looking for an actual freeze/synconous feature to keep the code straight forward and less hack-ish.
回答1:
You can place everything within a div except for your popup. You can then turn on/off pointer events via css.
Everything within the div will no longer be interactable. This will give the appearance of freezing the browser window.
.freeze { pointer-events: none; }
Note: When adding pointer-events
to an element this affects all child elements as well, so placing it on the body would also lock the popup.
Once the popup has been closed, we can remove the freeze
class from the div and everything will start working again.
const content = document.getElementById('content')
const overlay = document.querySelector('.overlay')
const a = document.querySelector('.open-overlay')
const close = document.querySelector('.overlay .close')
// Open a popup and freeze the browser content
a.addEventListener('click', e => {
e.preventDefault()
content.classList.add('freeze')
overlay.classList.remove('hidden')
})
// Close the popup window and unfreeze the browser content
close.addEventListener('click', e => {
e.preventDefault()
content.classList.remove('freeze')
overlay.classList.add('hidden')
})
.freeze { pointer-events: none; }
.hidden { display: none; }
.overlay {
position: fixed;
z-index: 100;
padding: 20px;
background: white;
border: solid 1px #ccc;
width: 300px;
top: 20px;
left: 0;
right: 0;
margin: auto;
}
<div class="overlay hidden">
<h1>Overlay</h1>
<a href="" class="close">Close</a>
</div>
<div id="content">
<a href="" class="open-overlay">Open Overlay</a>
<p>Hello World</p>
<p>Hello World</p>
<p>Hello World</p>
<p>Hello World</p>
<p>Hello World</p>
<form>
<input type="text">
</form>
</div>
回答2:
You can't freeze the browser application like the native dialogs do. Those are not built with JavaScript, they are built with native code and can affect the browser application in any way. JavaScript is prohibited from affecting the client application in such ways.
But, you can freeze interactions with your page content within the browser window....
Just place a window sized div
above the page with fixed positioning. That will prevent the user from being able to interact with anything on the main page (behind it). Then, display your modal dialog on top of that. When the user clears the modal, hide it and the window sized div, thus making the main page interactive again.
let modal = document.querySelector(".modal");
let pageCover = document.querySelector(".pageCover");
let main = document.querySelector("main");
document.getElementById("open").addEventListener("click", function(){
modal.classList.remove("hidden");
pageCover.classList.remove("hidden");
main.addEventListener("focus", preventFocus);
});
document.getElementById("close").addEventListener("click", function(){
modal.classList.add("hidden");
pageCover.classList.add("hidden");
main.removeEventListener("focus", preventFocus);
});
function preventFocus (evt){
evt.preventDefault();
}
.hidden { display:none; }
.pageCover {
position:fixed;
z-index:10;
background-color:rgba(0,0,0,.25);
width:100vw;
height:100vh;
top:0;
left:0;
}
.modal {
position:absolute;
z-index:100;
background-color:aliceblue;
border:2px double grey;
width:200px;
height:200px;
top:30%;
left:30%;
text-align:center;
}
.modalTitle {
margin:0;
background-color:#00a;
color:#ff0;
padding:5px;
font-weight:bold;
font-size:1.1em;
}
#close {
background-color:#800080;
color:#ff0;
border:1px solid #e0e0e0;
padding:5px 10px;
}
#close:hover { background-color:#c000c0; }
<main>
<h1>This is some page content</h1>
<p>And more content</p>
<button id="open">Click Me To Show Modal</button>
<div>More content</div>
</main>
<div class="hidden pageCover"></div>
<div class="hidden modal">
<div class="modalTitle">Modal Title Here</div>
<p>
Now, you can only interact with the contents of this "modal".
</p>
<button id="close" >Close</button>
</div>
来源:https://stackoverflow.com/questions/55942922/how-to-freeze-browser-window-intentionally-like-alert-confirm-and-prompt-does