HTML
CSS
JS
Result
Skip Results Iframe
EDIT ON
Live
Live
Live
This Pen is owned by
web.dev
on
CodePen
.
See more by @web-dot-dev on CodePen
External CSS
https://codepen.io/web-dot-dev/pen/XWqWYgB.css
https://codepen.io/web-dot-dev/pen/ZExZWBQ.css
External JavaScript
https://codepen.io/web-dot-dev/pen/XWqWYgB.js
https://codepen.io/web-dot-dev/pen/ZExZWBQ.js
{"__browser":{"country":"US","device":"unknown_device","mobile":false,"name":"unknown browser","platform":"unknown_platform","version":"0"},"__constants":{},"__CPDATA":{"domain_iframe":"https://cdpn.io","environment":"production","host":"codepen.io","iframe_allow":"accelerometer; ambient-light-sensor; camera; display-capture; encrypted-media; geolocation; gyroscope; microphone; midi; payment; vr; web-share","iframe_sandbox":"allow-forms allow-modals allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation-by-user-activation allow-downloads allow-presentation"},"__graphql":{"data":{"data":null,"errors":[{"message":"Cannot return null for non-nullable field Query.sessionUser"}]},"url":"https://codepen.io/graphql","api":"cprails"},"__pay_stripe_public_key":"pk_live_2GndomDfiklqpSNQn8FrGuwZSMIMzha7DkLJqlYe7IR0ihKAlKdiHg68JJc5eVPt68rzAjzAAVXcUwjySHRCsgjQQ00gtRBUFNH","__pay_braintree_env":"production","__boomboom":{"serve_url":"https://cdpn.io/cpe/boomboom","store_url":"https://codepen.io/cpe/boomboom/store"},"__pageType":"embed","__item":"{\"editor_settings\":{\"auto_run\":true,\"autocomplete\":false,\"code_folding\":true,\"css_pre_processor\":\"none\",\"css_prefix\":\"neither\",\"css_starter\":\"neither\",\"emmet_active\":true,\"font_size\":14,\"font_type\":\"system\",\"format_on_save\":true,\"html_pre_processor\":\"none\",\"indent_with\":\"spaces\",\"js_pre_processor\":\"none\",\"key_bindings\":\"normal\",\"line_numbers\":true,\"line_wrapping\":true,\"match_brackets\":true,\"snippets\":{\"markupSnippets\":{},\"stylesheetSnippets\":{}},\"tab_size\":2,\"theme\":\"twilight\",\"id\":\"QWrwLdp\",\"auto_save\":true},\"hashid\":\"QWrwLdp\",\"itemType\":\"pen\",\"resources\":[{\"url\":\"https://codepen.io/web-dot-dev/pen/XWqWYgB.css\",\"order\":0,\"resource_type\":\"css\",\"par_content\":\"\"},{\"url\":\"https://codepen.io/web-dot-dev/pen/XWqWYgB.js\",\"order\":0,\"resource_type\":\"js\",\"par_content\":\"\"},{\"url\":\"https://codepen.io/web-dot-dev/pen/ZExZWBQ.css\",\"order\":1,\"resource_type\":\"css\",\"par_content\":\"\"},{\"url\":\"https://codepen.io/web-dot-dev/pen/ZExZWBQ.js\",\"order\":1,\"resource_type\":\"js\",\"par_content\":\"\"}],\"tags\":[],\"id\":62926028,\"user_id\":5928893,\"html\":\"<div popover=\\\"manual\\\" class=\\\"window popup og\\\">\\n <div class=\\\"title-bar\\\">\\n <div class=\\\"title-bar-text\\\">OG Pop-up</div>\\n </div>\\n <div class=\\\"window-body\\\">\\n <p>Using this pop-up, generate lots of other pop-ups.</p>\\n <p>We're using JavaScript to manage which pop-ups get a <code>::backdrop</code>.<br>\\n In this case, we only ever want one <code>::backdrop</code>.\\n </p>\\n <section class=\\\"field-row\\\">\\n <button data-popup-clearer=\\\"true\\\">Clear pop-ups</button>\\n <button data-popup-generator=\\\"true\\\">Generate pop-up</button>\\n </section>\\n </div>\\n</div>\",\"css\":\"@import url(\\\"https://unpkg.com/xp.css\\\");\\n\\n@layer demo {\\n button[popover] {\\n top: 50%;\\n left: 50%;\\n translate: -50% -50%;\\n scale: 1.25;\\n margin: 0;\\n }\\n\\n code {\\n background: transparent;\\n color: var(--red-8);\\n }\\n\\n .popup {\\n transform: translate(-50%, -50%);\\n text-align: center;\\n position: fixed;\\n left: calc(var(--x, 50) * 1%);\\n top: calc(var(--y, 50) * 1%);\\n white-space: nowrap;\\n margin: 0;\\n border: 0;\\n }\\n\\n .popup[data-hasbackdrop]::backdrop {\\n background: hsl(0 10% 10%/ 0.35);\\n backdrop-filter: blur(2px);\\n }\\n\\n .popup[data-hasbackdrop]:open::backdrop {\\n opacity: 1;\\n }\\n\\n .window-body {\\n display: flex;\\n flex-direction: column;\\n }\\n\\n .window-body p {\\n padding: var(--size-2) var(--size-4);\\n font-size: 12px;\\n letter-spacing: unset;\\n line-height: 1.2;\\n }\\n\\n .title-bar {\\n height: auto;\\n min-height: 28px;\\n }\\n\\n .title-bar-controls button {\\n height: 21px;\\n }\\n\\n .field-row {\\n justify-content: flex-end;\\n }\\n\\n button {\\n height: auto;\\n color: #000;\\n }\\n}\\n\\n@layer base {\\n *,\\n *:after,\\n *:before {\\n box-sizing: border-box;\\n }\\n\\n body {\\n display: grid;\\n place-items: center;\\n min-height: 100vh;\\n background: var(--gradient-7);\\n font-family: \\\"Google Sans\\\", sans-serif, system-ui;\\n }\\n\\n :where([popover]) {\\n margin: auto;\\n border-width: initial;\\n border-style: solid;\\n }\\n}\\n\",\"js\":\"const OG_POP = document.querySelector(\\\".og[popover]\\\");\\nconst ADDER = document.querySelector(\\\"button[data-popup-generator]\\\");\\nconst CLEARER = document.querySelector(\\\"button[data-popup-clearer]\\\");\\nconst BACKDROP_ATTRIBUTE = \\\"data-hasbackdrop\\\";\\n\\nlet popUps = [];\\n\\nconst randomInRange = (min, max) =>\\n Math.floor(\\n Math.random() * (Math.floor(max) - Math.ceil(min) + 1) + Math.ceil(min)\\n );\\n\\nconst destroyPopUp = (e) => {\\n // Remove the id from the list\\n const popIndex = popUps.indexOf(e.target.id);\\n if (popIndex !== -1) {\\n // If there is an index before, add the attribute to that.\\n popUps.splice(popIndex, 1);\\n if (popUps.length !== 0)\\n document\\n .querySelector(`#${popUps[0]}`)\\n .setAttribute(BACKDROP_ATTRIBUTE, true);\\n e.target.remove();\\n }\\n};\\n\\nconst createPopUp = () => {\\n const pop = Object.assign(document.createElement(\\\"div\\\"), {\\n id: `pop--${popUps.length}`,\\n popover: \\\"manual\\\",\\n className: \\\"window popup\\\",\\n innerHTML: `\\n <div class=\\\"title-bar\\\">\\n <div class=\\\"title-bar-text\\\">Generated Pop-up</div>\\n <div class=\\\"title-bar-controls\\\">\\n <button aria-label=\\\"Close\\\"></button>\\n </div>\\n </div>\\n <div class=\\\"window-body\\\">\\n <p>There's only ever one backdrop!</p>\\n <section class=\\\"field-row\\\">\\n <button autofocus>Add another pop-up</button>\\n <button>Cancel</button>\\n </section>\\n </div>\\n `\\n });\\n\\n const POP_BUTTONS = pop.querySelectorAll(\\\"button\\\");\\n\\n POP_BUTTONS[0].addEventListener(\\\"click\\\", () => pop.hidePopover());\\n POP_BUTTONS[1].addEventListener(\\\"click\\\", createPopUp);\\n POP_BUTTONS[2].addEventListener(\\\"click\\\", () => pop.hidePopover());\\n\\n pop.addEventListener(\\\"popuphide\\\", destroyPopUp);\\n\\n if (popUps.length === 0) pop.setAttribute(BACKDROP_ATTRIBUTE, true);\\n\\n document.body.insertBefore(pop, OG_POP);\\n\\n pop.style.setProperty(\\\"--x\\\", randomInRange(20, 80));\\n pop.style.setProperty(\\\"--y\\\", randomInRange(20, 80));\\n\\n popUps.push(pop.id);\\n pop.showPopover();\\n // Remove and Re-add the OG to promote it above others in the top layer\\n OG_POP.hidePopover();\\n OG_POP.showPopover();\\n};\\n\\nconst clearPopUps = () => {\\n const POPS = document.querySelectorAll(\\\"[popover]:not(.og)\\\");\\n for (const POP of POPS) {\\n POP.hidePopover();\\n }\\n};\\n\\nADDER.addEventListener(\\\"click\\\", createPopUp);\\nCLEARER.addEventListener(\\\"click\\\", clearPopUps);\\nOG_POP.showPopover();\\n\",\"html_pre_processor\":\"none\",\"css_pre_processor\":\"none\",\"js_pre_processor\":\"none\",\"html_classes\":\"popup-support\",\"css_starter\":\"neither\",\"js_library\":null,\"created_at\":\"2022-09-03T20:06:51.983Z\",\"updated_at\":\"2023-01-19T11:20:35.242Z\",\"title\":\"19. Managing ::backdrop\",\"description\":\"\",\"slug_hash\":\"QWrwLdp\",\"head\":\"\",\"private\":false,\"has_animation\":false,\"team_id\":0,\"css_prefix\":\"neither\",\"template\":false,\"parent_id\":0,\"comments_count\":0,\"custom_screenshot_filename\":null,\"loves_count\":0,\"pick\":false,\"popularity_score\":0,\"views_count\":0,\"pick_visible_at\":null,\"cpid\":\"018304f6-934f-7d68-bd7a-9eb6f04c0b5c\",\"is_new_editor_pen\":false,\"pen_hash\":null}","__processorsMap":{"autoprefixer":"autoprefixer-10","babel":"babel-7","coffeescript":"coffeescript-2","format-1":"format-1","flutter":"flutter-1","haml":"haml-4","less":"less-3","lint-1":"lint-1","livescript":"livescript-1","markdown":"markdown-11","postcss":"postcss-7","pug":"pug-2","sass":"sass-1","scss":"sass-1","sass-ruby-3":"sass-ruby-3","sass-ruby-compass-3":"sass-ruby-compass-3","slim":"slim-3","stylus":"stylus-0","typescript":"typescript-4","vue":"vue-2","vue3":"vue-3"},"__favicon_mask_icon":"https://cpwebassets.codepen.io/assets/favicon/logo-pin-b4b4269c16397ad2f0f7a01bcdf513a1994f4c94b8af2f191c09eb0d601762b1.svg","__favicon_shortcut_icon":"https://cpwebassets.codepen.io/assets/favicon/favicon-aec34940fbc1a6e787974dcd360f2c6b63348d4b1f4e06c77743096d55480f33.ico","__path_to_iframe_console_runner":"https://cpwebassets.codepen.io/assets/editor/iframe/iframeConsoleRunner-6d8bf8b4b479137260842506acbb12717dace0823c023e08b96360e60b0840d9.js","__path_to_iframe_refresh_css":"https://cpwebassets.codepen.io/assets/editor/iframe/iframeRefreshCSS-44fe83e49b63affec96918c9af88c0d80b209a862cf87ac46bc933074b8c557d.js","__path_to_iframe_runtime_errors":"https://cpwebassets.codepen.io/assets/editor/iframe/iframeRuntimeErrors-4f205f2c14e769b448bcf477de2938c681660d5038bc464e3700256713ebe261.js","__path_to_processor_worker":"https://cpwebassets.codepen.io/assets/packs/router.js","__path_to_stop_execution_on_timeout":"https://cpwebassets.codepen.io/assets/common/stopExecutionOnTimeout-2c7831bb44f98c1391d6a4ffda0e1fd302503391ca806e7fcc7b9b87197aec26.js","__pen_normalize_css_url":"https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css","__pen_prefix_free_url":"https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js","__pen_reset_css_url":"https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css","__path_to_infinite_loop_detection":"https://cpwebassets.codepen.io/assets/packs/js/infiniteLoopDetection-f0d5935eb4c2121dfc41.js"}