{"id":2134,"date":"2024-05-10T06:50:18","date_gmt":"2024-05-10T12:50:18","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=2134"},"modified":"2024-05-10T06:50:20","modified_gmt":"2024-05-10T12:50:20","slug":"using-css-scroll-driven-animations-for-section-based-scroll-progress-indicators","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/using-css-scroll-driven-animations-for-section-based-scroll-progress-indicators\/","title":{"rendered":"Using CSS Scroll-Driven Animations for Section-Based Scroll Progress Indicators"},"content":{"rendered":"\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/CSS_scroll-driven_animations\">Scroll-Driven Animations<\/a>&nbsp;allow you to control animations based on the scroll progress of any particular element (often the whole document), or, a particular element\u2019s visibility progress within the document. These are&nbsp;<code>view()<\/code>&nbsp;and&nbsp;<code>scroll()<\/code>&nbsp;animations, respectively. Both useful! It can be useful to apply the animation directly to the element itself, for instance, a&nbsp;<code>&lt;section&gt;<\/code>&nbsp;sliding into place as it enters the viewport. That kind of thing is cool and useful, but have you thought about extending the effects of these animations beyond the elements triggering them?<\/p>\n\n\n\n<p>In CSS, the scroll-driven animations are effectuated using a couple of&nbsp;<code>animation-timeline<\/code>&nbsp;functions:&nbsp;<code>scroll()<\/code>&nbsp;and&nbsp;<code>view()<\/code>. You can learn more about them&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-timeline\">here<\/a>.<\/p>\n\n\n\n<p>In this article, we\u2019ll use a&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-timeline\/view\"><code>view()<\/code><\/a>&nbsp;animation, combined with a CSS custom property declared with&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/@property\"><code>@property<\/code><\/a>&nbsp;to create a \u201ccurrently-viewing\u201d and section-based progress indicator for each&nbsp;<code>section<\/code>&nbsp;of a page. This kind of thing can be useful, for example, for a long documentation page so a user can see where they are in it, and how far through their current section they are. Kind of like a reading-progress bar, but smarter, as it is aware of individual page sections.<\/p>\n\n\n\n<p>Here\u2019s a demo:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_wvZbmXO\" src=\"\/\/codepen.io\/anon\/embed\/wvZbmXO?height=450&amp;theme-id=47434&amp;slug-hash=wvZbmXO&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed wvZbmXO\" title=\"CodePen Embed wvZbmXO\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>The&nbsp;<code>view()<\/code>&nbsp;timeline will end up keeping track of each section\u2019s position throughout scrolling, and&nbsp;<code>@property<\/code>&nbsp;helps pass down an animate-able result of each section\u2019s scroll progress to its indicator element.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The HTML Foundation<\/h2>\n\n\n\n<p>To get started, let\u2019s begin by laying down the HTML elements. We\u2019re going to need:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Page\u00a0<code>&lt;section><\/code>s<\/li>\n\n\n\n<li>Scroll progress indicator bars<\/li>\n<\/ol>\n\n\n\n<p>Here are both:<\/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\">id<\/span>=<span class=\"hljs-string\">\"one\"<\/span>&gt;<\/span>\n    Section number one\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>First<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"two\"<\/span>&gt;<\/span>\n    Second section\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>Second<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"three\"<\/span>&gt;<\/span>\n    Third section\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>Third<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"four\"<\/span>&gt;<\/span>\n    Final section\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>Fourth<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/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>The&nbsp;<code>&lt;span&gt;<\/code>s above are the indicator elements, soon to be moved to the top-right corner of the viewport where they will remain fixed as a user scrolls through the page.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The CSS for the Sections and Indicators<\/h2>\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\">section<\/span> {\n    <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">400px<\/span>;\n    <span class=\"hljs-attribute\">aspect-ratio<\/span>: <span class=\"hljs-number\">1<\/span> \/ <span class=\"hljs-number\">2<\/span>;\n    <span class=\"hljs-comment\">\/* ... *\/<\/span>\n}\n<span class=\"hljs-selector-tag\">span<\/span> {\n    <span class=\"hljs-attribute\">position<\/span>: fixed;\n    <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">1<\/span>lh;\n    <span class=\"hljs-attribute\">line-height<\/span>: <span class=\"hljs-number\">40px<\/span>;\n    <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100px<\/span>;\n    <span class=\"hljs-attribute\">right<\/span>: <span class=\"hljs-number\">60px<\/span>;\n    <span class=\"hljs-attribute\">--t<\/span>: <span class=\"hljs-number\">60px<\/span>; <span class=\"hljs-comment\">\/* top variable *\/<\/span>\n    <span class=\"hljs-attribute\">--h<\/span>: <span class=\"hljs-built_in\">calc<\/span>(<span class=\"hljs-number\">1<\/span>lh + <span class=\"hljs-number\">10px<\/span>); <span class=\"hljs-comment\">\/* for the gap between spans *\/<\/span>\n    <span class=\"hljs-attribute\">section<\/span>:<span class=\"hljs-built_in\">nth-of-type<\/span>(<span class=\"hljs-number\">1<\/span>) &amp;{\n        top: <span class=\"hljs-built_in\">var<\/span>(--t);\n    }\n    <span class=\"hljs-selector-tag\">section<\/span><span class=\"hljs-selector-pseudo\">:nth-of-type(2)<\/span> &amp;{\n        <span class=\"hljs-attribute\">top<\/span>: <span class=\"hljs-built_in\">calc<\/span>(var(--t) + <span class=\"hljs-built_in\">var<\/span>(--h));\n    }\n    <span class=\"hljs-selector-tag\">section<\/span><span class=\"hljs-selector-pseudo\">:nth-of-type(3)<\/span> &amp;{\n        <span class=\"hljs-attribute\">top<\/span>: <span class=\"hljs-built_in\">calc<\/span>(var(--t) + <span class=\"hljs-number\">2<\/span> * <span class=\"hljs-built_in\">var<\/span>(--h));\n    }\n    <span class=\"hljs-selector-tag\">section<\/span><span class=\"hljs-selector-pseudo\">:nth-of-type(4)<\/span> &amp;{\n        <span class=\"hljs-attribute\">top<\/span>: <span class=\"hljs-built_in\">calc<\/span>(var(--t) + <span class=\"hljs-number\">3<\/span> * <span class=\"hljs-built_in\">var<\/span>(--h));\n    }\n    &amp;<span class=\"hljs-selector-pseudo\">::before<\/span> { <span class=\"hljs-comment\">\/* the blue bar *\/<\/span>\n        <span class=\"hljs-attribute\">display<\/span>: block;\n        <span class=\"hljs-attribute\">position<\/span>: absolute;\n        <span class=\"hljs-attribute\">content<\/span>: <span class=\"hljs-string\">''<\/span>;\n        <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">4px<\/span>;\n        <span class=\"hljs-attribute\">height<\/span>: inherit;\n        <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-built_in\">rgb<\/span>(<span class=\"hljs-number\">55<\/span>,<span class=\"hljs-number\">126<\/span>,<span class=\"hljs-number\">245<\/span>);\n        <span class=\"hljs-comment\">\/* ... *\/<\/span>\n    }\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<p>The\u00a0<code>span<\/code>s are given\u00a0<code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/position#fixed\">position: fixed<\/a><\/code>, and a\u00a0<code>right<\/code>\u00a0value, to fix them to the side of the screen. The\u00a0<code>top<\/code>\u00a0value of each\u00a0<code>span<\/code>\u00a0is measured (using\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/calc\"><code>calc()<\/code><\/a>) based on their height and the gap in-between them. You may want to consider logical property alternatives to these values if it\u2019s reasonable the page you\u2019re working on could be translated.<\/p>\n\n\n\n<p>A pseudo-element on the span is used as the actual progress indicator bar, a darker blue line that grows\/shrinks on each indicator box.<\/p>\n\n\n\n<p>Here\u2019s a demo of that (with no animations yet, we\u2019ll get there!)<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_zYXgpbE\" src=\"\/\/codepen.io\/anon\/embed\/zYXgpbE?height=450&amp;theme-id=47434&amp;slug-hash=zYXgpbE&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed zYXgpbE\" title=\"CodePen Embed zYXgpbE\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Let\u2019s proceed to the fun part \u2014 the animation!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Scroll-Driven Animation<\/h2>\n\n\n\n<p>We\u2019ll show the scroll progress of each section by animating the&nbsp;<code>height<\/code>&nbsp;of each bar indicator as the user scrolls through it. Well, perhaps not the&nbsp;<code>height<\/code>, the CSS property itself, but the visual height. We\u2019ll actually use&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/transform-function\/scaleY\"><code>scaleY()<\/code><\/a>&nbsp;on the bar, as that\u2019s generally considered more performant to animate. This&nbsp;<code>scaleY()<\/code>&nbsp;function takes a&nbsp;<code>number<\/code>&nbsp;data type value, hence our need to declare that with&nbsp;<code>@property<\/code>. So, let\u2019s register a custom property that takes a number value and set up a&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/@keyframes\"><code>@keyframes<\/code><\/a>&nbsp;animation that actually does the work:<\/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> --n {\n    <span class=\"hljs-selector-tag\">syntax<\/span>: \"&lt;<span class=\"hljs-selector-tag\">number<\/span>&gt;\";\n    <span class=\"hljs-selector-tag\">inherits<\/span>: <span class=\"hljs-selector-tag\">true<\/span>;\n    <span class=\"hljs-selector-tag\">initial-value<\/span>: 0;\n}\n<span class=\"hljs-keyword\">@keyframes<\/span> slide {\n    <span class=\"hljs-selector-tag\">from<\/span> { <span class=\"hljs-attribute\">--n<\/span>: <span class=\"hljs-number\">0<\/span>; }\n    <span class=\"hljs-selector-tag\">to<\/span> { <span class=\"hljs-attribute\">--n<\/span>: <span class=\"hljs-number\">1<\/span>; }\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<p>It\u2019s important that the&nbsp;<code>inherits<\/code>&nbsp;attribute is&nbsp;<code>true<\/code>&nbsp;when declaring the custom property. This ensures the value is accessible by the&nbsp;<code>spans<\/code>&nbsp;even though the&nbsp;<code>animation-<\/code>&nbsp;properties are added to the&nbsp;<code>sections<\/code>. The span&nbsp;<em>inherits<\/em>&nbsp;the value, as it were.<\/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\">section<\/span> {\n    <span class=\"hljs-attribute\">animation-timeline<\/span>: <span class=\"hljs-built_in\">view<\/span>(block <span class=\"hljs-number\">98%<\/span> <span class=\"hljs-number\">2%<\/span>);\n    <span class=\"hljs-attribute\">animation-name<\/span>: slide;\n    <span class=\"hljs-attribute\">animation-fill-mode<\/span>: both;\n    <span class=\"hljs-comment\">\/* remaining code from the 1st css snippet goes here *\/<\/span>\n}\n<span class=\"hljs-selector-tag\">span<\/span> {\n    <span class=\"hljs-comment\">\/* remaining code from the 1st css snippet goes here *\/<\/span>\n    &amp;::before { <span class=\"hljs-comment\">\/* the blue bar *\/<\/span>\n        <span class=\"hljs-comment\">\/* remaining code from the 1st css snippet goes here *\/<\/span>\n        <span class=\"hljs-attribute\">transform<\/span>: <span class=\"hljs-built_in\">scaleY<\/span>(var(--n)); <span class=\"hljs-comment\">\/* animation takes place here *\/<\/span>\n        <span class=\"hljs-attribute\">transform-origin<\/span>: top;\n    }\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<p>I prefer the scroll progress be measured against a (conceptual) horizontal line that\u2019s close to the bottom of the screen. Each time a section passes through this line, its animation timeline moves forward or backward based on the scrolling direction (up or down). The area I\u2019d chosen for this is 2% from the bottom of the screen. Here\u2019s the breakdown of the\u00a0<code>view()<\/code>\u00a0function\u2019s values.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><code>block<\/code>\u00a0\u2014 the area is defined across the block axis. The block axis is the vertical axis for left to right text direction<\/li>\n\n\n\n<li><code>98%<\/code>\u00a0\u2014 the area being defined begins at 98% from the top of the screen (or 98% from the start of the block axis)<\/li>\n\n\n\n<li><code>2%<\/code>\u00a0\u2014 the area ends at 2% from the bottom of the screen (or 2% from the end of the block axis)<\/li>\n<\/ol>\n\n\n\n<p>Since I wanted the defined area to be a line, I didn\u2019t leave any space between the beginning and end of the area. You can, however, broaden the area if you wish. For instance,&nbsp;<code>70% 20%<\/code>&nbsp;gives you a 10% long area on the screen for the scroll progress to be measured against. Or you can even move the area to the top of the screen.&nbsp;<code>0 100%<\/code>&nbsp;will assign the very top of the viewport as the marker to help track the scroll progress.<\/p>\n\n\n\n<p>The progress timeline then moves along the keyframe animation that we named&nbsp;<code>slide<\/code>, updating the custom variable&nbsp;<code>--n<\/code>&nbsp;with a corresponding value between 0 and 1. We\u2019re using 0 and 1 here because 0 means \u201cscale this bar all the way down to 0% tall\u201d and 1 means \u201cscale this bar all the way up to 100% tall\u201d.<\/p>\n\n\n\n<p>The&nbsp;<code>transform-origin: top<\/code>&nbsp;sets up the scaling to take place from the top of the bar element, meaning the bar will look like it \u201cgrows\u201d from top to bottom which mimics how scrolling happens.<\/p>\n\n\n\n<p>Here\u2019s the final outcome:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_wvZbmXO\" src=\"\/\/codepen.io\/anon\/embed\/wvZbmXO?height=450&amp;theme-id=47434&amp;slug-hash=wvZbmXO&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed wvZbmXO\" title=\"CodePen Embed wvZbmXO\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">A Variation<\/h2>\n\n\n\n<p>If you prefer that there be no bar for the first section initially, at least until after you\u2019ve scrolled down a bit, limit the first&nbsp;<code>section<\/code>&#8216;s&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-range\">animation range<\/a>&nbsp;to a desirable potion. This might feel better to you (and\/or users) because if they haven\u2019t scrolled&nbsp;<em>at all<\/em>&nbsp;it might be weird to visually show a section as partially complete. Here\u2019s that aleration:<\/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\">section<\/span><span class=\"hljs-selector-pseudo\">:nth-of-type(1)<\/span> {\n  <span class=\"hljs-attribute\">animation-range<\/span>: contain <span class=\"hljs-number\">70%<\/span>;\n}<\/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>The animation won\u2019t begin until the 70% mark of the first section crosses the area on the screen defined by&nbsp;<code>view()<\/code>. The effect is observed when the viewport is shorter than the first section. Adjust as needed.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_LYvoojP\" src=\"\/\/codepen.io\/anon\/embed\/LYvoojP?height=450&amp;theme-id=47434&amp;slug-hash=LYvoojP&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed LYvoojP\" title=\"CodePen Embed LYvoojP\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>That\u2019s it! Hopefully the article gives you an idea on how we can cascade the scroll position value and animation progress beyond a directly-assigned element, allowing us to build more dynamic scroll-based designs with just CSS. Knowing that you can pass a custom property value down to other elements, you might think about how&nbsp;<a href=\"https:\/\/developer.chrome.com\/docs\/css-ui\/style-queries\">style queries<\/a>&nbsp;could play into that idea \ud83e\udd14.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A scroll progress indicator is a pretty straightforward thing to build with a scroll()-style scroll-driven animation. But here, we&#8217;ll build indicators for each section of a page using the view() style.<\/p>\n","protected":false},"author":20,"featured_media":2136,"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,57],"class_list":["post-2134","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-css","tag-scroll-driven-animations"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/05\/image.png?fit=1792%2C1024&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2134","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=2134"}],"version-history":[{"count":2,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2134\/revisions"}],"predecessor-version":[{"id":2138,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2134\/revisions\/2138"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/2136"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=2134"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=2134"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=2134"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}