{"id":3559,"date":"2024-08-28T12:11:01","date_gmt":"2024-08-28T17:11:01","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=3559"},"modified":"2024-09-13T11:51:23","modified_gmt":"2024-09-13T16:51:23","slug":"the-dialog-element-with-entry-and-exit-animations","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/the-dialog-element-with-entry-and-exit-animations\/","title":{"rendered":"The Dialog Element with Entry *and* Exit Animations"},"content":{"rendered":"\n<p>Una Kravets blogged the other day that <a href=\"https:\/\/web.dev\/blog\/baseline-entry-animations?hl=en#enabling_discrete_animations_with_allow-discrete\">animating entry effects are now supported<\/a> in the latest stable version of all major browsers. The <em>new cool<\/em> way to do it, that is. We&#8217;ve long had trickery like applying a <code>@keyframe<\/code> animation with a <code>to<\/code> frame that would behave like an &#8220;entry effect&#8221;, but it was a bit awkward and didn&#8217;t work in all situations. Specifically one like using the new and very useful <code>&lt;dialog&gt;<\/code> element. <\/p>\n\n\n\n<p>This bit of code says a lot:<\/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-selector-tag\">dialog<\/span><span class=\"hljs-selector-attr\">&#91;open]<\/span> {\n  <span class=\"hljs-attribute\">transition<\/span>: \n    translate <span class=\"hljs-number\">0.7s<\/span> ease-out, \n    display <span class=\"hljs-number\">0.7s<\/span> ease-out allow-discrete;\n\n  <span class=\"hljs-comment\">\/* Post-Entry (Normal) State *\/<\/span>\n  <span class=\"hljs-attribute\">translate<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span>;\n\n  <span class=\"hljs-comment\">\/* Pre-Entry State *\/<\/span>\n  @starting-style {\n    <span class=\"hljs-attribute\">translate<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">100vh<\/span>;\n  }\n}<\/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>\n\n\n<p>There are two big things at work there:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>The <code>display<\/code> property is listed in the transitions, with the keyword <code>allow-discrete<\/code>. The code for it is hidden in User-Agent stylesheets, but when a <code>&lt;dialog&gt;<\/code> moves from close (default) to open, the <code>display<\/code> goes from <code>none<\/code> to <code>block<\/code>. Using this keyword means that the <code>display<\/code> property is changed <em>after<\/em> the animation timing, so animations can actually happen.<\/li>\n\n\n\n<li>The <code>@starting-style<\/code> gives us an opportunity to apply styling to the element <em>just as it&#8217;s entering it&#8217;s current state<\/em>, meaning the transition will happen between the styles declared inside and outside that block.<\/li>\n<\/ol>\n\n\n\n<p>Golf clap. Everything is awesome.<\/p>\n\n\n\n<p>What Una <em>didn&#8217;t<\/em> cover, on purpose surely, was <em>exit<\/em> animations (because they aren&#8217;t in &#8220;Baseline&#8221; yet, meaning not supported across browsers). But they <em>are<\/em> supported in Chrome-n-friends land, so I thought it was worth looking at. To me, they are just as interesting, cool, and useful as the entry kind.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Both Entry and Exit<\/h2>\n\n\n\n<p>The trick isn&#8217;t terribly different than the code above, it&#8217;s just to have very specific styles for both the open and closed (i.e. <code>:not([open])<\/code> states. Like this:<\/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 shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-selector-tag\">dialog<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">--duration<\/span>: <span class=\"hljs-number\">0.34s<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">transition<\/span>: \n<\/span><\/span><span class='shcb-loc'><span>    translate <span class=\"hljs-built_in\">var<\/span>(--duration) ease-in-out, \n<\/span><\/span><span class='shcb-loc'><span>    scale     <span class=\"hljs-built_in\">var<\/span>(--duration) ease-in-out,\n<\/span><\/span><span class='shcb-loc'><span>    filter    <span class=\"hljs-built_in\">var<\/span>(--duration) ease-in-out,\n<\/span><\/span><mark class='shcb-loc'><span>    display   <span class=\"hljs-built_in\">var<\/span>(--duration) ease-in-out allow-discrete;\n<\/span><\/mark><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  &amp;&#91;open] {\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">\/* Post-Entry (Normal) State *\/<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">translate<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">0<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">scale<\/span>: <span class=\"hljs-number\">1<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">filter<\/span>: <span class=\"hljs-built_in\">blur<\/span>(<span class=\"hljs-number\">0<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">\/* Pre-Entry State *\/<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    @starting-style {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attribute\">translate<\/span>: <span class=\"hljs-number\">0<\/span> <span class=\"hljs-number\">8vh<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attribute\">scale<\/span>: <span class=\"hljs-number\">1.15<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attribute\">filter<\/span>: <span class=\"hljs-built_in\">blur<\/span>(<span class=\"hljs-number\">8px<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>    }\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-comment\">\/* Exiting State *\/<\/span>\n<\/span><\/span><span class='shcb-loc'><span>  &amp;<span class=\"hljs-selector-pseudo\">:not(<\/span><span class=\"hljs-selector-attr\">&#91;open]<\/span>) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">translate<\/span>: <span class=\"hljs-number\">0<\/span> -<span class=\"hljs-number\">8vh<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">scale<\/span>: <span class=\"hljs-number\">1.15<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">filter<\/span>: <span class=\"hljs-built_in\">blur<\/span>(<span class=\"hljs-number\">8px<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/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<p>Check it out:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_xxoPzEZ\" src=\"\/\/codepen.io\/anon\/embed\/xxoPzEZ?height=450&amp;theme-id=47434&amp;slug-hash=xxoPzEZ&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed xxoPzEZ\" title=\"CodePen Embed xxoPzEZ\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>And a video in case you&#8217;re in a browser that doesn&#8217;t support it yet:<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='500' height='427' src='https:\/\/videopress.com\/embed\/puie9YCG?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent=\"true\" allow='clipboard-write'><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1725245713'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<p>Note that not only does it <em>have<\/em> entry and exit animations, but those states are <em>different<\/em> \u2014&nbsp;which is very cool! Emphasizing that, here&#8217;s one where I move the dialog along an <code>offset-path<\/code> so the exit is really a continuation of the path:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_rNErmmz\" src=\"\/\/codepen.io\/anon\/embed\/rNErmmz?height=450&amp;theme-id=47434&amp;slug-hash=rNErmmz&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed rNErmmz\" title=\"CodePen Embed rNErmmz\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Usage with Popovers<\/h2>\n\n\n\n<p>This isn&#8217;t exclusively for dialogs, you can make it work with whatever. But naturally open-closable things make the most sense. Like native popovers! Nils Riedemann has a nice demo here:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_jOjLjYw\" src=\"\/\/codepen.io\/anon\/embed\/jOjLjYw?height=450&amp;theme-id=47434&amp;slug-hash=jOjLjYw&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed jOjLjYw\" title=\"CodePen Embed jOjLjYw\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Now that we&#8217;re starting to see better support for @starting-style and the allow-discrete keyword, we&#8217;ve got a pretty straightforward way for defining *different* entry and exit states.<\/p>\n","protected":false},"author":1,"featured_media":3678,"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":[229,100,7,98,120],"class_list":["post-3559","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-starting-style","tag-animation","tag-css","tag-dialog","tag-popover"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/08\/exit-thumb.jpg?fit=1390%2C751&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3559","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\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=3559"}],"version-history":[{"count":3,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3559\/revisions"}],"predecessor-version":[{"id":3860,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3559\/revisions\/3860"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/3678"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=3559"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=3559"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=3559"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}