{"id":4812,"date":"2024-12-20T12:00:57","date_gmt":"2024-12-20T17:00:57","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=4812"},"modified":"2024-12-20T17:13:51","modified_gmt":"2024-12-20T22:13:51","slug":"scroll-driven-fixed","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/scroll-driven-fixed\/","title":{"rendered":"Scroll-Driven &amp; Fixed"},"content":{"rendered":"\n<p>Scroll-driven animations is a good name. They are&#8230; animations&#8230; that are&#8230; scroll-driven. As you scroll you can make something happen. The most basic kind, where a <code>@keyframe<\/code> is ran 0% to 100% as the element is scrolled 0% to 100% is particularly easy to wrap your mind around. <\/p>\n\n\n\n<p>I also think it&#8217;s fun to mess with the expectations of scrolling. <\/p>\n\n\n\n<p class=\"has-small-font-size\">In very light, fun-only, non-crucial ways. Not in ways that would hurt the access of content.<\/p>\n\n\n\n<p>Like what if we made an element that definitely scrolled:<\/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-class\">.scrolling-element<\/span> {\n  <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">100<\/span>dvh;\n  <span class=\"hljs-comment\">\/* ... make something inside it taller than it is ... *\/<\/span>\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>But then all the content within it was <code>position: fixed;<\/code> so it didn&#8217;t move normally when the element was scrolled. <\/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-class\">.scrolling-element<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">100<\/span>dvh;\n<\/span><\/span><span class='shcb-loc'><span>  &gt; * {\n<\/span><\/span><mark class='shcb-loc'><span>    <span class=\"hljs-attribute\">position<\/span>: fixed;\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-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>Instead, we could have the elements react the scroll position however we wanted. <\/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 shcb-code-table\"><span class='shcb-loc'><span><span class=\"hljs-selector-class\">.scrolling-element<\/span> {\n<\/span><\/span><mark class='shcb-loc'><span>  <span class=\"hljs-attribute\">scroll-timeline-name<\/span>: --my-scroller;\n<\/span><\/mark><mark class='shcb-loc'><span>  <span class=\"hljs-attribute\">scroll-timeline-axis<\/span>: block;\n<\/span><\/mark><span class='shcb-loc'><span>  \n<\/span><\/span><span class='shcb-loc'><span>  &gt; * {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">position<\/span>: fixed;\n<\/span><\/span><mark class='shcb-loc'><span>    <span class=\"hljs-attribute\">animation<\/span>: doSomethingCool linear;\n<\/span><\/mark><mark class='shcb-loc'><span>    <span class=\"hljs-attribute\">animation-timeline<\/span>: --my-scroller;\n<\/span><\/mark><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-keyword\">@keyframes<\/span> doSomethingCool {\n<\/span><\/span><span class='shcb-loc'><span>  100% {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attribute\">rotate<\/span>: <span class=\"hljs-number\">2turn<\/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-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>Here&#8217;s that basic setup:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_JoPNEjB\" src=\"\/\/codepen.io\/anon\/embed\/JoPNEjB?height=450&amp;theme-id=47434&amp;slug-hash=JoPNEjB&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed JoPNEjB\" title=\"CodePen Embed JoPNEjB\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/baseline-status@1.0.4\/baseline-status.min.js\" type=\"module\"><\/script>\n\n<baseline-status featureId=\"scroll-driven-animations\"><\/baseline-status>\n\n\n\n<p>I bet you could imagine that this is the same exact trick for a &#8220;scroll position indicator&#8221; bit of UI. Position that <code>&lt;div&gt;<\/code> as like a 2px tall bar and have the <code>scaleX<\/code> transform go from 0 to 100% and donezo.<\/p>\n\n\n\n<p>I&#8217;ll use the same spirit here to have a whole grid of cells use that &#8220;scale to zero&#8221; animation to reveal a hidden picture.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_zxOqqpx\" src=\"\/\/codepen.io\/anon\/embed\/zxOqqpx?height=450&amp;theme-id=47434&amp;slug-hash=zxOqqpx&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed zxOqqpx\" title=\"CodePen Embed zxOqqpx\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>I think that hidden picture thing is fun! I&#8217;m imagining a game where you have to guess the picture by scrolling down <em>as little as possible<\/em>. Like &#8220;name that tune&#8221; only &#8220;name that movie still&#8221; or whatever.<\/p>\n\n\n\n<p>In this next one I took the idea a bit further and create randomized positions for each of the grid cells to &#8220;fly off&#8221; to (in SCSS). <\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_YPKqqaV\" src=\"\/\/codepen.io\/anon\/embed\/YPKqqaV?height=450&amp;theme-id=47434&amp;slug-hash=YPKqqaV&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed YPKqqaV\" title=\"CodePen Embed YPKqqaV\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>I find that extraordinary that that kind of interaction can be done in HTML and CSS these days.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s quite fun to have an element react to another element scrolling in an unexpected way! <\/p>\n","protected":false},"author":1,"featured_media":4864,"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-4812","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\/12\/you-win.png?fit=1636%2C720&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4812","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=4812"}],"version-history":[{"count":6,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4812\/revisions"}],"predecessor-version":[{"id":4867,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/4812\/revisions\/4867"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/4864"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=4812"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=4812"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=4812"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}