{"id":330,"date":"2024-01-04T15:16:33","date_gmt":"2024-01-04T15:16:33","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=330"},"modified":"2024-01-04T15:16:33","modified_gmt":"2024-01-04T15:16:33","slug":"background-size-zooming-with-scroll-driven-animations","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/background-size-zooming-with-scroll-driven-animations\/","title":{"rendered":"Background Size Zooming with Scroll Driven Animations"},"content":{"rendered":"\n<p>I&#8217;ve seen all the excitement about <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-timeline\">scroll-driven animations<\/a>. I&#8217;m excited too. Animations that use scroll position as a timeline rather than a time-based duration is just a clever idea. It&#8217;s something that websites have been using probably-too-much JavaScript for for a long time and it&#8217;s nice to see that kind of thing move to CSS where it belongs. <\/p>\n\n\n\n<p>But I haven&#8217;t gotten a chance to play with it directly very much yet. So here I go!<\/p>\n\n\n\n<p>This all got started because I got a nice email from a reader who had a very specific effect in mind they were trying to replicate on their own website. Somewhat inspired by <a href=\"https:\/\/www.chungiyoo.com\/\">Chung-Yun Yoo&#8217;s website<\/a>, the idea is: <strong>images that zoom in (or out) as you scroll.<\/strong> They don&#8217;t change dimensions themselves, they just change how much of the image you can see in the space they already occupy. This doesn&#8217;t require too much trickery \u2014 you just set the <code>width<\/code>, <code>height<\/code>, and <code>background-size<\/code> and you can affect how much of an <code>&lt;img&gt;<\/code> you can see. Changing that <code>background-size<\/code> has the zooming affect.<\/p>\n\n\n\n<p>This is what we&#8217;re after (video):<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video autoplay controls loop muted src=\"https:\/\/assets.codepen.io\/3\/scroll-zoom.mp4\" playsinline><\/video><\/figure>\n\n\n\n<p>The trick is changing the <code>background-size<\/code> on scroll. This is normally something you&#8217;d use JavaScript for, like <code>scroll<\/code> event listeners on the document and\/or <code>IntersectionObserver<\/code> stuff. But now, we can express what we want in Scroll-Driven Animations. <\/p>\n\n\n\n<p>Bramus Van Damme has lots of good resources on Scroll-Driven Animations like <a href=\"https:\/\/developer.chrome.com\/docs\/css-ui\/scroll-driven-animations\">this article<\/a> and the site <a href=\"https:\/\/scroll-driven-animations.style\/\">scroll-driven-animations.style<\/a>. The tool I found most helpful when trying to figure this out was this <a href=\"https:\/\/scroll-driven-animations.style\/tools\/view-timeline\/progress\/\">View Progress Timeline<\/a> tool. In this tool, you can see how a green box has an animation run <em>only during the time when it&#8217;s visible at all in the viewport<\/em>. I was very pleased to have that click for me, as before I saw this I thought that the timelines needed to be the entire scroll-length of the element. Good job, API!<\/p>\n\n\n\n<figure class=\"wp-block-video\"><video controls muted src=\"https:\/\/assets.codepen.io\/3\/scroll-driven.mp4\" playsinline><\/video><\/figure>\n\n\n\n<p>Note the <code>cover<\/code> keyword there that is helping us achieve that effect. It&#8217;s definitely worth a play with the other values to see what they do. Honestly I can imagine they are <em>all<\/em> useful in certain situations. Seeing the generated code, I was able to see that our image effect is quite simple to scaffold:<\/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\">.img<\/span> {\n  <span class=\"hljs-attribute\">animation-range<\/span>: cover <span class=\"hljs-number\">0%<\/span> cover <span class=\"hljs-number\">100%<\/span>;\n  <span class=\"hljs-attribute\">animation<\/span>: the-animation linear;\n  <span class=\"hljs-attribute\">animation-timeline<\/span>: <span class=\"hljs-built_in\">view<\/span>();\n  <span class=\"hljs-attribute\">animation-iteration-count<\/span>: <span class=\"hljs-number\">1<\/span>;\n}\n\n<span class=\"hljs-keyword\">@keyframes<\/span> the-animation {\n  <span class=\"hljs-selector-tag\">from<\/span> {\n    <span class=\"hljs-comment\">\/* whatever *\/<\/span>\n  }\n  <span class=\"hljs-selector-tag\">to<\/span> {\n    <span class=\"hljs-comment\">\/* whatever *\/<\/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>In our case, we can flesh out the animation with just some <code>background-size<\/code> changes and we&#8217;re good! Here&#8217;s a basic demo you can scroll up and down:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_KKEwBox\" src=\"\/\/codepen.io\/anon\/embed\/KKEwBox?height=450&amp;theme-id=47434&amp;slug-hash=KKEwBox&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed KKEwBox\" title=\"CodePen Embed KKEwBox\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p class=\"learn-more\">As I write, scroll-driven animations are available in Chrome &#8216;n&#8217; friends, flagged in Firefox, and not yet available in Safari. There is <a href=\"https:\/\/github.com\/flackr\/scroll-timeline\">a polyfill<\/a>, which that demo above loads, so it should work across all three.<\/p>\n\n\n\n<p>Those are the basics that achieve what I had in mind. Now here&#8217;s a Pen that uses the same animation across multiple elements, but sets where the animate to via CSS Custom Property. <\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_MWxaxVQ\/1dbc568d8f8404b5c9ba2fe6388bca0d\" src=\"\/\/codepen.io\/anon\/embed\/MWxaxVQ\/1dbc568d8f8404b5c9ba2fe6388bca0d?height=550&amp;theme-id=47434&amp;slug-hash=MWxaxVQ\/1dbc568d8f8404b5c9ba2fe6388bca0d&amp;default-tab=result\" height=\"550\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed MWxaxVQ\/1dbc568d8f8404b5c9ba2fe6388bca0d\" title=\"CodePen Embed MWxaxVQ\/1dbc568d8f8404b5c9ba2fe6388bca0d\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Funnnnn.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve seen all the excitement about scroll-driven animations. I&#8217;m excited too. Animations that use scroll position as a timeline rather than a time-based duration is just a clever idea. It&#8217;s something that websites have been using probably-too-much JavaScript for for a long time and it&#8217;s nice to see that kind of thing move to CSS [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":355,"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-330","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\/01\/scroll-thumb.jpg?fit=1000%2C500&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/330","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=330"}],"version-history":[{"count":11,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/330\/revisions"}],"predecessor-version":[{"id":356,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/330\/revisions\/356"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/355"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=330"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=330"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=330"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}