{"id":2341,"date":"2024-05-23T08:41:24","date_gmt":"2024-05-23T14:41:24","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=2341"},"modified":"2024-05-24T07:40:58","modified_gmt":"2024-05-24T13:40:58","slug":"animating-dialog","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/animating-dialog\/","title":{"rendered":"Animating the Dialog Element"},"content":{"rendered":"\n<p>When the <code>&lt;dialog&gt;<\/code> element became widely available in 2022, I was thrilled. Opening a dialog? Easy. Closing a dialog? Even easier. Nested dialogs and keyboard interactions? Built-in, for free. It\u2019s like living in the future.<\/p>\n\n\n\n<p>But what about animating? That\u2019s a little trickier. At first glance it doesn\u2019t appear to be animatable in CSS\u2014transitions and animations don\u2019t seem to work. JavaScript can do it, but that requires managing the state of your dialogs manually, losing some of the simplicity of using <code>&lt;dialog><\/code> in the first place.<\/p>\n\n\n\n<p>Fortunately, thanks to modern CSS, we can do it without resorting to JavaScript.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_QWRywza\" src=\"\/\/codepen.io\/anon\/embed\/QWRywza?height=450&amp;theme-id=47434&amp;slug-hash=QWRywza&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed QWRywza\" title=\"CodePen Embed QWRywza\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Here we&#8217;ll take a look at opening and closing animations separately, discussing solutions using transitions and animations for each.<\/p>\n\n\n\n<p>To keep my code simple I\u2019ll stick to only animating opacity, though these techniques still apply to more complex examples.<\/p>\n\n\n\n<div class=\"wp-block-group learn-more\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p>The nice thing about only animating opacity is we don\u2019t have any extra accessibility concerns. If you\u2019re involving some form of motion in your animations, you\u2019ll need to ensure the relevant code is wrapped in a media query like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@media<\/span> (<span class=\"hljs-attribute\">prefers-reduced-motion:<\/span> no-preference) { }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Opening Animations<\/strong><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Transition with <code>@starting-style<\/code><\/h3>\n\n\n\n<p>You might have tried something like this, only to find it <strong>doesn\u2019t work<\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dialog<\/span> {\n  <span class=\"hljs-attribute\">transition<\/span>: opacity <span class=\"hljs-number\">1s<\/span>;\n  <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">0<\/span>;\n  \n  &amp;&#91;open] {\n    <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">1<\/span>;\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_JjqXLEb\" src=\"\/\/codepen.io\/anon\/embed\/JjqXLEb?height=450&amp;theme-id=47434&amp;slug-hash=JjqXLEb&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed JjqXLEb\" title=\"CodePen Embed JjqXLEb\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>The problem here is when a <code>&lt;dialog&gt;<\/code> opens, the browser doesn\u2019t know what opacity value it\u2019s meant to transition from. The first style update our <code>&lt;dialog open&gt;<\/code> receives sets <code>opacity: 1<\/code> , and since that\u2019s also our end value, no transition takes place. We see this problem pop up whenever we attempt to transition any element that changes to or from display: none. How do we fix this?<\/p>\n\n\n\n<p>One way is with <code>@starting-style<\/code>, an at-rule that allows us to specify the values we\u2019d like to transition from when the element is first rendered.<\/p>\n\n\n\n<p>We can nest it directly in our existing <code>[open]<\/code> rule like so:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dialog<\/span> {\n  <span class=\"hljs-attribute\">transition<\/span>: opacity <span class=\"hljs-number\">1s<\/span>;\n  <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">0<\/span>;\n  \n  &amp;&#91;open] {\n    <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">1<\/span>;\n\t  \n    @starting-style {\n      <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">0<\/span>;\n    }\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_GRaZxNx\" src=\"\/\/codepen.io\/anon\/embed\/GRaZxNx?height=450&amp;theme-id=47434&amp;slug-hash=GRaZxNx&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed GRaZxNx\" title=\"CodePen Embed GRaZxNx\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Success! That\u2019s all it takes, our &lt;dialog&gt; will now transition opacity while opening.<\/p>\n\n\n\n<p>We can think of <code>@starting-style<\/code> as a third state for our dialog, the \u2018pre-open\u2019 state. Often we\u2019d want this to be the same as our \u2018closed\u2019 state, and while this might seem like an annoying bit of duplication, it\u2019s useful that we can define it separately as it allows our opening and closing transitions to be different.<\/p>\n\n\n\n<p>The downside here, at least at the time of writing, is browser support. <code>@starting-style<\/code> isn\u2019t in Firefox, and only in recent versions of Chromium and WebKit based browsers. Depending on your requirements that can easily be good enough since:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>We\u2019re using <code>@starting-style<\/code> as a progressive enhancement. In non-supporting browsers the dialog will simply open with no transition.<\/li>\n\n\n\n<li><code>@starting-style<\/code> is an Interop 2024 target, so we can expect cross-browser support by the end of the year.<\/li>\n<\/ol>\n\n\n\n<p>So what if we need a cross-browser opening animation right now? Are we out of luck? Fortunately not.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Animation with <\/strong><strong>@keyframes<\/strong><\/h3>\n\n\n\n<p>By using <code>@keyframes<\/code> we can get the same effect with browser support limited only by <code>&lt;dialog&gt;<\/code> itself and remove the need to use <code>@starting-style<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dialog<\/span><span class=\"hljs-selector-attr\">&#91;open]<\/span> {\n  <span class=\"hljs-attribute\">animation<\/span>: open <span class=\"hljs-number\">1s<\/span> forwards;\n}\n\n<span class=\"hljs-keyword\">@keyframes<\/span> open {\n  <span class=\"hljs-selector-tag\">from<\/span> { <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">0<\/span> }\n  <span class=\"hljs-selector-tag\">to<\/span>   { <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">1<\/span> }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_bGypvem\" src=\"\/\/codepen.io\/anon\/embed\/bGypvem?height=450&amp;theme-id=47434&amp;slug-hash=bGypvem&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed bGypvem\" title=\"CodePen Embed bGypvem\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>That\u2019s all we need! We solve the problem of the browser needing to know what initial value to use by explicitly declaring it within the animation.<\/p>\n\n\n\n<p><code>@keyframes<\/code> debatably has a few downsides, mostly notably its need for a unique name. That doesn\u2019t sound like a big deal, but naming things can be hard, and name conflicts can be confusing to debug. All else being equal, a technique requiring a unique name is worse than a technique that doesn\u2019t.<\/p>\n\n\n\n<p>Personally however, until <code>@starting-style<\/code> has near universal support, this will remain my preferred technique. In my opinion it\u2019s equally readable, rarely more verbose, and the fact it works everywhere makes me (and my clients) happy.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Closing Animations<\/strong><\/h2>\n\n\n\n<p>Unfortunately when our <code>&lt;dialog&gt;<\/code> closes, we run into a few more problems:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>It changes to <code>display: none<\/code>.<\/li>\n\n\n\n<li>It\u2019s removed from the top layer.<\/li>\n<\/ol>\n\n\n\n<p>Both of these things happen as soon as the close event is fired, and since they both hide our element, any animations or transitions we attempt won&#8217;t be visible. We\u2019ll need to delay these while our animation completes, and we can do it in one line with CSS:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">transition<\/span>:\n  <span class=\"hljs-selector-tag\">display<\/span> 1<span class=\"hljs-selector-tag\">s<\/span> <span class=\"hljs-selector-tag\">allow-discrete<\/span>,\n  <span class=\"hljs-selector-tag\">overlay<\/span> 1<span class=\"hljs-selector-tag\">s<\/span> <span class=\"hljs-selector-tag\">allow-discrete<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>There\u2019s a few new things in this one declaration, so let&#8217;s expand on each of them.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>transition-behavior: allow-discrete<\/code><\/h3>\n\n\n\n<p>Usually when attempting to transition discrete properties we see it doesn\u2019t work, or more accurately, the property\u2019s value updates at 0%, causing an instant change with no transition.<\/p>\n\n\n\n<p>What <code>transition-behavior: allow-discrete<\/code> usually does is allow us to request that this change occur at 50% of the way through the transition, rather than 0%. I say usually, because for transitions that involve display: none, this change will instead occur at either 100% or 0%, based on if we\u2019re animating to or from display: none. This ensures that our element will remain visible for the entire duration of the transition. Problem #1 solved.<\/p>\n\n\n\n<p class=\"learn-more\">Since the value changes at the beginning or end of the transition, it doesn\u2019t matter what value we use for <code>animation-timing-function<\/code> so feel free to omit it from the shorthand.<\/p>\n\n\n\n<p><code>transition-behavior<\/code> is currently not available in Firefox or Safari, but as it&#8217;s also an <a href=\"https:\/\/wpt.fyi\/interop-2024\">Interop 2024<\/a> target along with <code>@starting-style<\/code>, we can be optimistic that it\u2019ll be widely available by the end of the year.<\/p>\n\n\n\n<p>It\u2019s also not available in a non-American spelling, so make sure you leave out the \u2018u\u2019.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>The <\/strong><strong>overlay<\/strong><strong> Property<\/strong><\/h3>\n\n\n\n<p>The overlay property has two possible values: <code>auto<\/code> and <code>none<\/code>, and it specifies if an element in the top layer should be rendered in the top layer. Very simply, an element with <code>overlay: auto<\/code> will render in the top layer and be visible, and an element with <code>overlay: none<\/code> will not.<\/p>\n\n\n\n<p>What complicates this slightly is that the overlay property is fairly unique in that it\u2019s not possible for you to set it yourself. You can\u2019t set it directly on an element, or use it in a <code>@keyframes <\/code>animation. The only one who can change the value of this property is the browser. Using it in a transition in combination with <code>allow-discrete<\/code> is actually our only way of interacting with it at all.<\/p>\n\n\n\n<p>This is also another property that transitions differently than normal discrete properties where it\u2019ll remain <code>overlay: auto<\/code> for the entire transition. Exactly what we need to solve problem #2.<\/p>\n\n\n\n<p>The <code>overlay<\/code> keyword is our only method of keeping an element in the top layer, so any CSS only solution to <code>&lt;dialog&gt;<\/code> closing animations will require it. Unfortunately it\u2019s currently only available Chromium at the time of writing, and since it\u2019s not an Interop 2024 target, we might be waiting a little longer for cross-browser support.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Closing Transition<\/strong><\/h3>\n\n\n\n<p>Lets combine this with our previous example using <code>@starting-style<\/code> by adding to our existing transition declaration:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dialog<\/span> {\n  <span class=\"hljs-attribute\">transition<\/span>:\n    display <span class=\"hljs-number\">1s<\/span> allow-discrete,\n    overlay <span class=\"hljs-number\">1s<\/span> allow-discrete,\n    opacity <span class=\"hljs-number\">1s<\/span>;\n  <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">0<\/span>;\n  \n  &amp;&#91;open] {\n    <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">1<\/span>;\n\t  \n    @starting-style {\n      <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">0<\/span>;\n    }\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_JjqGoPa\" src=\"\/\/codepen.io\/anon\/embed\/JjqGoPa?height=450&amp;theme-id=47434&amp;slug-hash=JjqGoPa&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed JjqGoPa\" title=\"CodePen Embed JjqGoPa\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>And with that we have a <code>&lt;dialog&gt;<\/code> with both opening and closing transitions! If you\u2019re looking for the simplest solution then you can stop here, it doesn\u2019t come easier than this.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Closing Animation with <\/strong><strong>@keyframes<\/strong><\/h3>\n\n\n\n<p>If you\u2019re like me and want to take advantage of CSS animations to provide a cross-browser opening animation, we\u2019ll need to do a bit more.<\/p>\n\n\n\n<p>It\u2019s possible to use our transition only code to handle the closing animation while keeping <code>@keyframes<\/code> for our opening animation. But if you\u2019re like me, you might find it a bit easier to understand if both animations are controlled via keyframes.<\/p>\n\n\n\n<p>Since both display and overlay are set by the browser, we still need to transition these values outside of our animations:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dialog<\/span> {\n  <span class=\"hljs-attribute\">transition<\/span>:\n    display <span class=\"hljs-number\">1s<\/span> allow-discrete,\n    overlay <span class=\"hljs-number\">1s<\/span> allow-discrete;\n\t\t\t\t\t\t\t\n  &amp;&#91;open] {\n    <span class=\"hljs-attribute\">animation<\/span>: open <span class=\"hljs-number\">1s<\/span> forwards;\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>While I find it a little weird to be using both animation and transition, I like that our animation code is kept separate from our management of the browser\u2019s default behaviour.<\/p>\n\n\n\n<p class=\"learn-more\">We need to ensure our <code>animation-duration<\/code> is at least as large as our <code>transition-duration<\/code> to ensure neither overlay or display change before the end of our animation.<\/p>\n\n\n\n<p>Next up is the closing animation itself.<\/p>\n\n\n\n<p>My first instinct was to reuse the same animation but play it in reverse. Unfortunately we can\u2019t do that since it&#8217;s not possible to change <code>animation-direction<\/code> without also starting a new animation with a different name.<\/p>\n\n\n\n<p>Instead, lets define a new set of <code>@keyframes<\/code> for our closing animation and apply it to the default (closed) state:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">dialog<\/span> {\n  <span class=\"hljs-attribute\">transition<\/span>:\n    display <span class=\"hljs-number\">1s<\/span> allow-discrete,\n    overlay <span class=\"hljs-number\">1s<\/span> allow-discrete;\n\t\n  <span class=\"hljs-attribute\">animation<\/span>: close <span class=\"hljs-number\">1s<\/span> forwards;\t\t\t\t\t\n  &amp;&#91;open] {\n    <span class=\"hljs-attribute\">animation<\/span>: open <span class=\"hljs-number\">1s<\/span> forwards;\n  }\n}\n\n<span class=\"hljs-keyword\">@keyframes<\/span> open {\n  <span class=\"hljs-selector-tag\">from<\/span> { <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">0<\/span> }\n  <span class=\"hljs-selector-tag\">to<\/span>   { <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">1<\/span> }\n}\n\n<span class=\"hljs-keyword\">@keyframes<\/span> close {\n  <span class=\"hljs-selector-tag\">from<\/span> { <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">1<\/span> }\n  <span class=\"hljs-selector-tag\">to<\/span>   { <span class=\"hljs-attribute\">opacity<\/span>: <span class=\"hljs-number\">0<\/span> }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_QWRywza\" src=\"\/\/codepen.io\/anon\/embed\/QWRywza?height=450&amp;theme-id=47434&amp;slug-hash=QWRywza&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed QWRywza\" title=\"CodePen Embed QWRywza\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>And that\u2019s all it takes! A <code>&lt;dialog&gt;<\/code> with a cross-browser opening animation and a progressively enhanced closing animation. It\u2019s a little less concise with a bit more duplication than our transition only example, but you can decide if the extra browser support is worth it for you.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Conclusion<\/strong><\/h2>\n\n\n\n<p>It\u2019s honestly quite amazing how little CSS is required to make this happen. Tools like <code>&lt;dialog&gt;<\/code>, <code>overlay<\/code> and <code>transition-behavior<\/code> have taken what was once an incredibly complicated task and reduced it to just a few lines of CSS.<\/p>\n\n\n\n<p>Dialogs are easier than they\u2019ve ever been, and as long as we don\u2019t get tempted to over use them, that\u2019s cause for celebration to me \ud83c\udf89<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What about <code>popover<\/code> and <code>::backdrop<\/code>?<\/strong><\/h2>\n\n\n\n<p>I kept my explanation focused on the <code>&lt;dialog&gt;<\/code> element to keep things simple, but everything we\u2019ve just covered also applies <code>popover<\/code> elements and <code>::backdrop<\/code> too! They exist in the top layer and have their <code>display<\/code> toggled by the browser in the same way <code>&lt;dialog&gt;<\/code> does, so can be animated using these same techniques.<\/p>\n\n\n\n<p>Here&#8217;s Adam Argyle with a snippet that handles popovers and backdrops also, just note it&#8217;s using <code>@starting-style<\/code> so support will be limited for now:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"twitter-tweet\" data-width=\"500\" data-dnt=\"true\"><p lang=\"en\" dir=\"ltr\">steal this dialog and popover snippet <a href=\"https:\/\/twitter.com\/hashtag\/CSS?src=hash&amp;ref_src=twsrc%5Etfw\">#CSS<\/a><br>&#8211; transitions <br>&#8211; entry\/exit  <br>&#8211; backdrop included <br><br>ready for richer design system integration<br><br>try on Codepen <a href=\"https:\/\/t.co\/I4yAV2tWNO\">https:\/\/t.co\/I4yAV2tWNO<\/a> <a href=\"https:\/\/t.co\/ygY9wS4Liv\">pic.twitter.com\/ygY9wS4Liv<\/a><\/p>&mdash; Adam Argyle (@argyleink) <a href=\"https:\/\/twitter.com\/argyleink\/status\/1793302054859063718?ref_src=twsrc%5Etfw\">May 22, 2024<\/a><\/blockquote><script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script>\n<\/div><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>It might seem like you could just set a transition on the opacity of the dialog element in CSS from 0 to 1, but it doesn&#8217;t work. You&#8217;ll need to learn about @starting-style, and the overlay and allow-discrete keywords.<\/p>\n","protected":false},"author":23,"featured_media":2371,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[7,98],"class_list":["post-2341","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-css","tag-dialog"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/05\/animate-modal-thumb.jpg?fit=1000%2C500&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2341","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/23"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=2341"}],"version-history":[{"count":16,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2341\/revisions"}],"predecessor-version":[{"id":2398,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2341\/revisions\/2398"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/2371"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=2341"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=2341"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=2341"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}