{"id":4128,"date":"2024-10-09T08:27:37","date_gmt":"2024-10-09T13:27:37","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=4128"},"modified":"2024-10-11T09:51:23","modified_gmt":"2024-10-11T14:51:23","slug":"css-fan-out-with-grid-and-property","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/css-fan-out-with-grid-and-property\/","title":{"rendered":"CSS Fan Out with Grid and @property"},"content":{"rendered":"\n<p class=\"has-drop-cap\">A &#8220;fan out&#8221; is an expanding animation where a group of items appear one after another, next to each other, as though they were spread out from a stack. There\u2019s usually a subtle bounciness in the reveal.<\/p>\n\n\n\n<p>The effect is customarily achieved by timing and positioning each of the items individually with very specific hard set values. That can be an awful lot of work though. We can make things a bit easier if we let the items\u2019 parent container do this for us. Here\u2019s a result of doing it this way:&nbsp;<\/p>\n\n\n\n<p class=\"learn-more\"><strong>UPDATE<\/strong>: This article has been updated to now include the animation of the grid items\u2019 <code>height<\/code>, to produce an overall smoother transition effect. The previous version of this article didn\u2019t cover that.\u00a0<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_xxvRrYQ\" src=\"\/\/codepen.io\/anon\/embed\/xxvRrYQ?height=650&amp;theme-id=47434&amp;slug-hash=xxvRrYQ&amp;default-tab=result\" height=\"650\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed xxvRrYQ\" title=\"CodePen Embed xxvRrYQ\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>For HTML, there\u2019s a group of items (plus an empty one \u2014 I will explain later why it\u2019s there), bookended by two radio controls to prompt the opening and closing of the items respectively.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"items-container\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"items\"<\/span>&gt;<\/span><span class=\"hljs-comment\">&lt;!--empty--&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"items close\"<\/span>&gt;<\/span>\n    Close the messages<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"radio\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"radio\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"items\"<\/span>&gt;<\/span>Alert from Project X<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"items\"<\/span>&gt;<\/span><span class=\"hljs-symbol\">&amp;#x1F429;<\/span> Willow's appointment at <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">i<\/span>&gt;<\/span>Scrubby's<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">i<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"items\"<\/span>&gt;<\/span>Message from (-_-)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"items\"<\/span>&gt;<\/span>NYT Feed: <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">u<\/span>&gt;<\/span>Weather In... (Read more)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">u<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"items\"<\/span>&gt;<\/span>6 more items to check in your vacation list!<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"items open\"<\/span>&gt;<\/span>\n    Show the messages<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"radio\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"radio\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We need a grid container for this to work, so let\u2019s turn the <code>&lt;section&gt;<\/code>, the items\u2019 container element, into one.&nbsp;You could use a list or anything you feel is semantically appropriate.<\/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-class\">.items-container<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: grid; \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<p>Now create an <em>Integer<\/em> CSS custom property with a value same as the number of items inside the container (including the open and close controls, and the empty item). This is key to implement the revealing and hiding of the items, sequentially, from within the grid container\u2019s style rule.<\/p>\n\n\n\n<p>Also, register another CSS custom property of data type <em>length<\/em> that\u2019ll be used to animate each item\u2019s height during the opening and closing of the control, for a smoother execution of the overall action.\u00a0<\/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-keyword\">@property<\/span> --int {\n  <span class=\"hljs-selector-tag\">syntax<\/span>: \"&lt;<span class=\"hljs-selector-tag\">integer<\/span>&gt;\";\n  <span class=\"hljs-selector-tag\">inherits<\/span>: <span class=\"hljs-selector-tag\">false<\/span>;\n  <span class=\"hljs-selector-tag\">initial-value<\/span>: 7;\n}\n\n<span class=\"hljs-keyword\">@property<\/span> --hgt {\n  <span class=\"hljs-selector-tag\">syntax<\/span>: \"&lt;<span class=\"hljs-selector-tag\">length<\/span>&gt;\";\n  <span class=\"hljs-selector-tag\">inherits<\/span>: <span class=\"hljs-selector-tag\">false<\/span>;\n  <span class=\"hljs-selector-tag\">initial-value<\/span>: 0<span class=\"hljs-selector-tag\">px<\/span>;\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<p>Use the now created <code>--int<\/code> and <code>--hgt<\/code> properties to add that many grid rows of zero height in the grid container.\u00a0<\/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 shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-selector-class\">.items-container<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">display<\/span>: grid; \n<\/span><\/span><mark class='shcb-loc'><span>  <span class=\"hljs-attribute\">grid-template-rows<\/span>: <span class=\"hljs-built_in\">repeat<\/span>(calc(var(--int)), <span class=\"hljs-built_in\">var<\/span>(--hgt));  \n<\/span><\/mark><span class='shcb-loc'><span>}\n<\/span><\/span><\/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<p>When directly adding <code>--int<\/code> to <code>repeat()<\/code> it was producing a blotchy animation in Safari for me, so I fed it through <code>calc()<\/code> and the animation executed well (we\u2019ll look into the animation in a moment). However, <code>calc()<\/code> computation kept leaving out one item in the iteration, because of how it computed the value 0. Hence, I added the empty item to compensate the exclusion.&nbsp;<\/p>\n\n\n\n<p>If Safari did not give me a blotchy result, I would\u2019ve not needed an empty item, <code>--int<\/code>\u2019s <code>initial-value<\/code> would\u2019ve been 6, and <code>grid-template-rows<\/code>\u2019s value would\u2019ve been just <code>repeat(var(--int), 0px)<\/code>. In fact, with this set up, I got good animation results both in Firefox and Chrome.&nbsp;<\/p>\n\n\n\n<p>In the end though, I went with the one that uses <code>calc()<\/code>, which provided the desired result in all the major browsers.&nbsp;<\/p>\n\n\n\n<p>Let\u2019s get to animation now:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table\"><mark class='shcb-loc'><span>@keyframes open { to { --int: <span class=\"hljs-number\">0<\/span>; --hgt:<span class=\"hljs-number\">60<\/span>px;} }\n<\/span><\/mark><mark class='shcb-loc'><span>@keyframes close { to { --int: <span class=\"hljs-number\">6<\/span>; --hgt:<span class=\"hljs-number\">0<\/span>px;} } \n<\/span><\/mark><span class='shcb-loc'><span>.item-container {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attr\">display<\/span>: grid; \n<\/span><\/span><span class='shcb-loc'><span>  grid-template-rows: repeat(calc(<span class=\"hljs-keyword\">var<\/span>(--int)), <span class=\"hljs-keyword\">var<\/span>(--hgt)); \n<\/span><\/span><span class='shcb-loc'><span>  &amp;:has(.open :checked) {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-comment\">\/* open action *\/<\/span>\n<\/span><\/span><mark class='shcb-loc'><span>    <span class=\"hljs-attr\">animation<\/span>: open <span class=\"hljs-number\">.3<\/span>s ease-<span class=\"hljs-keyword\">in<\/span>-out forwards;\n<\/span><\/mark><mark class='shcb-loc'><span>    .open { <span class=\"hljs-attr\">display<\/span>: none; }\n<\/span><\/mark><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>  &amp;:has(.close :checked) {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-comment\">\/* close action *\/<\/span>\n<\/span><\/span><mark class='shcb-loc'><span>    --int: <span class=\"hljs-number\">0<\/span>;\n<\/span><\/mark><mark class='shcb-loc'><span>    --hgt: <span class=\"hljs-number\">60<\/span>px;\n<\/span><\/mark><mark class='shcb-loc'><span>    animation: close <span class=\"hljs-number\">.3<\/span>s ease-<span class=\"hljs-keyword\">in<\/span>-out forwards;\n<\/span><\/mark><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-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>When the input is in the <code>checked<\/code> state, the <code>open<\/code> keyframe animation is executed, and the control itself is hidden with <code>display: none<\/code>.&nbsp;<\/p>\n\n\n\n<p>The <code>open<\/code> class changes <code>--int<\/code>\u2019s value from its <code>initial-value<\/code>, 7, to the one set within the <code>@keyframes<\/code> rule (<code>0<\/code>), over a set period (<code>.3s<\/code>). This decrement removes the zero height from each of the grid row, one by one, thus sequentially revealing all the items in <code>.3s<\/code> or <code>300ms<\/code>.\u00a0Simultaneously, <code>--hgt<\/code>\u2019s value is increased to 60px from its initial 0px value. This expands each item\u2019s height as it appears on the screen.\u00a0<\/p>\n\n\n\n<p>When the input to <em>hide<\/em> all the items is in the <code>checked<\/code> state, the <code>close<\/code> keyframe animation is executed, setting <code>--int<\/code>\u2019s value to 0 and <code>--hgt<\/code>\u2019s value to 60px.<\/p>\n\n\n\n<p>The <code>close<\/code> class changes the now <code>0<\/code> value of <code>--int<\/code> to the value declared in its rule: <code>7<\/code>. This increment sets a zero height to each of the grid row, one by one, thus <em>sequentially hiding<\/em> all the items.\u00a0Simultaneously, <code>--hgt<\/code>\u2019s value is decreased to 0px. This shrinks each item\u2019s height as it disappears from the screen.\u00a0<\/p>\n\n\n\n<p>To perform the close action, instead of making a unique close animation, I tried using the open animation with <code>animation-direction: reverse<\/code>. Unfortunately, the result was jerky. So I kept unique animations for the open and close actions separately.<\/p>\n\n\n\n<p>Additionally, to polish the UI, I\u2019m adding transition animations to the row gaps and text colors as well. The row gaps set <code>cubic-bezier()<\/code> animation timing function to create a low-key springy effect.&nbsp;<\/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 shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-selector-class\">.scroll-container<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">display<\/span>: grid; \n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">grid-template-rows<\/span>: <span class=\"hljs-built_in\">repeat<\/span>(calc(var(--int)), <span class=\"hljs-number\">0px<\/span>); <span class=\"hljs-comment\">\/* serves the open and close actions *\/<\/span>\n<\/span><\/span><mark class='shcb-loc'><span>  <span class=\"hljs-attribute\">transition<\/span>: row-gap .<span class=\"hljs-number\">3s<\/span> .<span class=\"hljs-number\">1s<\/span> <span class=\"hljs-built_in\">cubic-bezier<\/span>(.<span class=\"hljs-number\">8<\/span>, .<span class=\"hljs-number\">5<\/span>, .<span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">1.4<\/span>);\n<\/span><\/mark><span class='shcb-loc'><span>  &amp;:has(<span class=\"hljs-attribute\">.open <\/span>:checked) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">\/* open action *\/<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    animation: open .<span class=\"hljs-number\">3s<\/span> ease-in-out forwards;\n<\/span><\/span><span class='shcb-loc'><span>    .open { <span class=\"hljs-attribute\">display<\/span>: none; }\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">\/* styling *\/<\/span>\n<\/span><\/span><mark class='shcb-loc'><span>    <span class=\"hljs-selector-tag\">row-gap<\/span>: 10<span class=\"hljs-selector-tag\">px<\/span>;\n<\/span><\/mark><mark class='shcb-loc'><span>    <span class=\"hljs-selector-class\">.items<\/span> { <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-built_in\">rgb<\/span>(<span class=\"hljs-number\">113<\/span> <span class=\"hljs-number\">124<\/span> <span class=\"hljs-number\">158<\/span>); <span class=\"hljs-attribute\">transition<\/span>: color .<span class=\"hljs-number\">3s<\/span> .<span class=\"hljs-number\">1s<\/span>;}\n<\/span><\/mark><mark class='shcb-loc'><span>    <span class=\"hljs-selector-class\">.close<\/span> { <span class=\"hljs-attribute\">color<\/span>: black }\n<\/span><\/mark><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>  &amp;<span class=\"hljs-selector-pseudo\">:has(.close<\/span> <span class=\"hljs-selector-pseudo\">:checked)<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">\/* close action *\/<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">--int<\/span>: <span class=\"hljs-number\">0<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">animation<\/span>: close .<span class=\"hljs-number\">3s<\/span> ease-in-out forwards;\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-comment\">\/* styling *\/<\/span>\n<\/span><\/span><mark class='shcb-loc'><span>    <span class=\"hljs-attribute\">row-gap<\/span>: <span class=\"hljs-number\">0<\/span>;\n<\/span><\/mark><mark class='shcb-loc'><span>    .items { <span class=\"hljs-attribute\">color<\/span>: transparent; <span class=\"hljs-attribute\">transition<\/span>: color .<span class=\"hljs-number\">2s<\/span>;}\n<\/span><\/mark><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-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<p>When expanded, the row <code>gap<\/code>s go up to <code>10px<\/code> and the text color comes in. When shrinking, the row <code>gap<\/code>s go down to <code>0<\/code> and the text color fades out to transparent. With that, the example is complete! Here\u2019s the Pen once more:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_xxvRrYQ\" src=\"\/\/codepen.io\/anon\/embed\/xxvRrYQ?height=650&amp;theme-id=47434&amp;slug-hash=xxvRrYQ&amp;default-tab=result\" height=\"650\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed xxvRrYQ\" title=\"CodePen Embed xxvRrYQ\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p class=\"learn-more\"><strong>Note<\/strong>: You can try this method with any grid compositions \u2014 rows, columns, or both.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Further Reading<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/grid-template-rows\" target=\"_blank\" rel=\"noreferrer noopener\">grid-template-rows<\/a> \u2014 MDN Web Docs<\/li>\n\n\n\n<li><a href=\"https:\/\/web.dev\/blog\/at-property-baseline\" target=\"_blank\" rel=\"noreferrer noopener\">@property: Next-gen CSS variables now with universal browser support<\/a> \u2014 web.dev<\/li>\n\n\n\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/easing-function\" target=\"_blank\" rel=\"noreferrer noopener\">CSS easing function<\/a> \u2014 MDN Web Docs&nbsp;<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>A &#8220;fan out&#8221; animation involves sequentially revealing items from a stack with a bouncy effect. By using CSS grid, we save quite a bit of fiddly positioning work. <\/p>\n","protected":false},"author":20,"featured_media":4150,"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":[134,100,7,180,123],"class_list":["post-4128","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-property","tag-animation","tag-css","tag-custom-properties","tag-grid"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/10\/pexels-photo-246990.jpeg?fit=1880%2C1258&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4128","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\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=4128"}],"version-history":[{"count":15,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4128\/revisions"}],"predecessor-version":[{"id":4178,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4128\/revisions\/4178"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/4150"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=4128"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=4128"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=4128"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}