Create an infinite horizontal scroll animation

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
have you ever needed an infinite scroller with some tags or other texts like this or maybe you needed it to have images instead right now I have faces here it could be logos for companies scrolling by or something like that and of course we can set this all up to be really easy to control as well with some data attributes so we can do a data Direction and just switch that over to the right and it's going to go the other way and if we don't like how fast they're going we come in with a data speed and we could say that this is actually going to be slow and slow it right down or we can even do fast and speed things up and build in some other customizations as well but just before we dive into all of that I just want to let you know that my name is Kevin and here at my channel I help people fall madly deeply in love with CSS even though today we're also going to be getting into the wonderful world of JavaScript as well now this is a type of effect that can actually be kind of problematic to implement properly so in this tutorial we're not only going to look at how we can set things up and make it customizable like we saw but we're also going to make this progressively enhanced when it comes to the motion as well because some people in their system preferences will opt out of having a lot lot of motion and these sideways things are some of the things that can actually cause the most problems with that so we're going to look at how we can start it off disabled so that way if somebody has opted out of having a lot of motion on a page they're not going to get any and then for people who have not opted out they're going to get the full experience all right so let's dive right into it you can see I do not have very much setup yet we have this tag list here it does not look too fancy I'll look at the CSS I have for that but none of what I've done right now applies to anything and what I'm going to do here is I'm going to come in with a scroller and it could be a horizontal scroll or infinite scroller call it whatever you would like but we want to have something like that that's our scroller right here and the one other thing I'm going to do the tag list here as I mentioned I have a little bit of styling on it is just to give these a visual style to it so it's it's a list so I'm turning off my list styling and all of that but the the magic of this is going to happen with we're going to have a old call it scroller inner um you could you know name that whatever you want but the idea with this is it could work on a UL that has Li's in it this pattern could work with images if you have logos we're going to change this to have images after as well or have a second one with images it doesn't necessarily have to be a list it could be other things in here so I do want a scroller and an inner scroller of some sort that's the really important part here and in this case the UL can also act as our inner scroller so coming back into here let's just scroll on down and we can add that in dot scroller and the important thing here is we do need it to have a maximum width so I'm going to do a Max width of 600 pixels because I don't want it to be too wide and that won't change anything yet but it this will be a very important step along the way uh because then we're going to go on our scroller inner and I'm going to throw a display Flex on here because I want the elements to go next to one another not nothing too complicated uh let's also add a gap in here because it's good to have a gap and let's put an outline over on this outline of three pixels solid lime just so we can see uh where it's going and you can see we actually already have a little bit of overflow and that's fine we sort of need to lean into that overflow a little bit um at one point one of the things we will have to do though for this to actually work is to eventually hide that overflow so one thing I am going to do on this is to do a padding block which is my padding top and bottom of uh to Ram it could be you know we could probably get away with one it's a theory we have shadows on these cards right now I want to make sure we don't lose things like that the left and the right aren't going to matter but the top and the bottom giving a little bit of padding for this is going to help us out and we'll sort of explore that a little bit but the first thing that's important here is while we want this to eventually be moving I sort of want to progressively enhance that's it and so what happens if somebody has prefers reduced motion off if I do you know we come on here and I said we want an overflow of hidden if I do that now we're going to have hidden content and you know what let's just make this a bit smaller or pretend we have more there's stuff that's missing so we don't really want things to disappear if a user has prefers reduce motion off and this type of thing where you have moving stuff it can you know when you're scrolling down and something's moving this way it can be really disorientating to people which is why they enable prefers reduced motion so for me this type of thing is really one of those types of animations that really benefits from progressively enhancing and adding that animation in if somebody hasn't opted out of having reduced animations so my idea here is actually let's not put the Overflow hidden on let's leave it there and here we're going to come in with a flex wrap of rap and so if there's not enough room the stuff wraps around and all of the content is still there and still visible on the page so we don't lose anything we're going to need some js to actually animate this because one thing I know we could probably come in and throw in I don't even know if this would work anymore can we do this let's find out don't do this please please um so right if we could sort of do something like that but it's not much of an infinite one because it's going to go over and then Loop over but we have those empty areas so even the Marquee in this case the good old the good old Marquis old cannot help us with the type of thing or but one we want where the H you know it just looks like it's infinitely looping around in a circle for this to work we're going to need JavaScript so because we're going to need JavaScript everything else from this point on because this is sort of my base stage everything else is going to be added sort of via JavaScript um so let's come and take a look at my Javascript file where we currently don't have anything so we're going to start off by looking for all the scrollers on the page I only have one right now but potentially you could have multiple ones and we are going to have multiple on the page eventually so we'll do our scrollers is equal to a document dot query selector all and we'll look for anything called scroller so anything that has that class on it we will be selecting to to be doing stuff with and so what do we want to do so let's say if and this is where the the progressive enhancement is going to come in we're going to use a media query here and and I actually have this one off screen because I'm going to muck it up if I don't copy paste it so window match media so you can check for media queries within JavaScript here um and so we're doing match media which is looking for the media query and then it's weird because you have to open and close parentheses and then inside of there you'll have your uh our quotes and then we're going to have another set of parentheses and you need this one inside the quote so you definitely you have to have the outer one and the inner one here for this to work properly and we're going to say prefers reduce motion reduced but I'm saying if we're not right so if window match media is not prefers reduced motion and then to actually check to see if this is true or not because when you do it you'll get a matches and the matches can be true or false so if this is false we can keep going um right so if it's false what we want to do is let's just say add animation and we can add our animations in with a add animation function so what's that going to be we can say function add animation in then come up with what it's actually going to do and the very first thing we want it to do is add in a data attribute so let's get our scrollers so scrollers for each and for each scroller nice and simple we want to do something and what I'm going to do is we're going to say scroller and we're going to do set attribute and so we're going to say that the attribute data animated is going to be equal to true and so if I hit save on this let's just go take a look at our page and see what that's given us we can do an inspect on here and if I come let's just move some stuff around and see I've grammarly installed there but we have this scroller and you can see the data animated of true there make this a little bit bigger so you can see it easier so is there data animated of true in Chrome with the dev tools open I'm going to do a control shift p if you're on a Mac it would be command shift p and I'm going to do emulate reduced and you can see here emulate CSS prefers reduced motion reduce I'm going to select that and I'm going to refresh my page and there's my scroller and that data attributes not being added to it let's do it again command shift p emulate prefers reduced motion and now it's already doing that so now we're going to say Do not emulate it we're going to turn that back off I'm going to refresh my page and the data animated equals true is on there so if the person has not opted for reduced motion then we're going to add the data animated true and that means that we can now add all of our animations into all of our fancy stuff awesome so now with that done we're gonna have a little bit more JavaScript in here eventually but for now let's come back to here and what we're going to say is on our scroller so scroller that has a data animated is equal to true we can now say that this actually has an overflow of hidden and we could use nesting for this I'm not going to do it with nesting and actually I'm going to move I'm going to leave the default Styles there and then we'll come down to these ones here so we have that then what we can say is that uh we'll copy you paste it and then copy you because if we have the data animated true our scroll inner so right so we want to select that scroll enter if the scroller is data animated true and I guess you know you could drop that off if you wanted to I'm also doing it like this instead of just like this assuming that you might be adding this to other things as well so you know if this is the only thing I guess you could get away with getting rid of the class selector but I'm assuming that you might have different scrollers in this case you don't necessarily need it because we're specifically targeting the inner but I just find it more consistent if we keep it um so our scroller inner now we'll do a flex wrap of no wrap which is the fun CSS property that doesn't have a hyphen in it uh right and that's actually been listed as a mistake by the w3c um but there we go now we can see that we've Now hidden away some of our stuff there and it's it's vanished uh which is the start that we actually want to have here now another thing we can do just this effect let's make this a bit wider again here uh 600 and the reason I want to do that just you can see we're still cutting off at the UI ux but this type of effect basically every time I've ever seen it done gets faded out on the left and the right side so we only want this to happen when we have the Overflow of hidden and actually we sort of need this to happen for the effect to really work anyway which is probably why we see the feed off um what we're going to do is we're going to add a mask here and for the mask it's going to be a linear gradient and you haven't used masks before they're super powerful and you can do really great things with them you can do it with images which is why we can do it with a linear gradient and if you want more info on masks I've done like three or four videos I'll put a playlist to um them down below including one that covered the first video in the playlist will be the absolute basics of how they work uh so the linear gradient on there we'll start with Trent's parent and let's just go to White and it's basically it's all based on the opacity of the different things on here and that's not going to work because here we probably need to have a web kit for uh yeah we did so we need the webkit mask for chromium browsers but all the other ones can just use mask um and then it works there so with that in place and it's like one of the few places we still need to prefix things um and it's funny that it's only with chrome but there we go um so the transparent is uh the area that's actually going to be faded out and just any like I could put red here if you want to save a character it's going to work as well we just need something that doesn't have opacity on it you know in FFF whatever you want a color that has a hundred percent um Alpha value and then you get it coming up now obviously we need this to be a little bit different so we're going to say 90 degrees so it's going that direction I want to keep it close to the edge here so what I'm going to do and actually let's just break this down a little bit to make it a bit easier to see on the screen because this is going to get kind of long I renewed transparent to white but my white is going to start at like 20 percent so if I do that you can see it fades and then once we get to 20 I'm at my solid white and then we have it going all the way across but we need it on the other side here too you could do this with the second gradient to do the other side but I don't really see the point since we already have a gradient so I'm just going to do um white and this one will go to 80 percent and then we'll do transparent at the other side so that one oh there we go it broke it down for us so we do 90 degrees then we're doing transparent up to White starting at twenty percent all the way to 80 and then we fade back off to transparent and that means I'm just going to copy this and do this as the regular mask for all my other browsers and that's probably going to get prettier to being on a single line but there we go uh it's working and we do need the webkit version and the mask one if you're using something like Auto prefixer with post CSS then you could probably get away with just using your mask and that sort of sets the stage for what we want to do now what we need them moving across so let's come in and add an animation so we can say at keyframes and we'll call it scroll and we can just do two so that means it's the end of the animation meaning the beginning will start wherever we're starting at by default and we want to transform it and we're going to start with doing a transform of a translate and I'm just going to say 100 just so we can see how this is going to work and the problem this causes but this sort of sets the stage for everything so then on my scroller I don't want it on the outside scroller I want the outside scroller to stay where it was so let's put that outline on there again outline five pixel solid lime except I think we can't see that let's put a border Maybe there we go I can sort of see the border the outline was outside of the Hidden area but we can see like we want to keep this there and we want the content inside of it to move if I added the animation to the scroller itself the whole scroller would move which we don't want and that's why it's important to have the scroller itself which is has the Overflow hidden and then the content inside of there that will sort of scroll by and get hidden because it's overflowed and masked away uh so what we'll do is on this scroller we can add an animation of scroll and I like setting it at like a really long period of time because I find if not it moves way too fast uh so 40 maybe for now we'll just do 20 seconds uh the other thing that's really important here is that it's linear so the speed is always the same because if it starts speeding up and slowing down once we get the loop working it would look really really strange so linear is really important to have on there and the other thing we do want is when it gets to the end of the animation it's always going to reset that's a good thing but once it resets back to the start we want it to start again so we want an infinite on there as well so it just means the animation is always running and you know now we're stuck with this big empty spot right because everything is scrolled on away and then it starts on over again that's sort of annoying but it does that but it that's okay it's going to work out perfectly fine with how we're going to set this up uh the first thing though is I actually want it to go the other way so let's do a translate negative 100 we'll see how we can get it to go in both directions though um but if we do it with a translate of negative 100 it moves the other way which just makes it a little bit easier to deal with at the beginning though we will still end up with this blank area at the end and this is where we have two choices and the first one is not what we're going to do but we could just come in here I could take all of this and duplicate it and then it's going to work sort of um let's just for now we'll do it this way and then I'll show you the better solution in a second but we'll do class of test on here and we'll come here and we'll say that test has a background that is red and the reason I want to do that is because we're going to see my first HTML went off and that wasn't working at first because I had to throw an important on here because I had a higher specificity selector you can see this HTML is coming here and basically so this is the second one this is the duplicate and when that one lines up with where the first one originally was that's when I want the animation to start over so this translate of negative 100 I actually want it to be around negative 50. and that's because I only wanted to move about halfway across right because we have duplicated content so if I move it halfway across it should be lining up with where it originally was ideally but we're going to see that's not going to work right now it's still going to cause a jump um and that's because this 50 isn't the number that we'd expect it to be and the reason for that is let's look at our Dev tools because this left me a little bit confused at the very beginning if I look at this tag list right here it has a width of 600. even though there's this stuff inside of it has we have the no wrap and the stuff is is coming out of it the reason it has a width of 600 is because it has the width of the parent that we set to have a Max width of 600 and the content inside is just overflowing out the side so the width of the scroller and the inner scroller are both 600 so the other thing we need to do to fix this is on the inner scroller right here the other thing we're going to do is we're going to say that the width on this width is going to be fit content we could also do this as a Max content and that should also give us the same result and now you can actually see that the width of it is a lot bigger than it was before and this is actually what we want it to be we want this much bigger width by doing this the width is matching the content that is inside of it now and it's now this is overflowing outside of the original scroller so the inner scroller overflows out the side but it means everything's going to line up a lot better and here my translate negative 50 let's hit a Refresh on there my live server um I'm using Veet right now and it's having some issues when I update my CSS but we should see and I don't want to speed it up because things move too fast so it gives me a chance to talk a bit but we should see it's roughly going to be when this resets which should be any second now uh it will go but notice how it jumped Just a Touch it took me a while to figure this one out too but because we have the gap on here it's actually the positioning of the second one is moved over a little bit more than what we thought it would be right so the first one at the very beginning let's turn off this animation for a second and see I have to refresh anyway that's okay old school manually refreshing stuff isn't that bad um if I take a look in here and I take a look at the parent the eight right that HTML this first one is flush with the left side of the parent but then as we go through and we get to that second HTML there's a gap between these two so to compensate for that Gap that we have on the second one but not on the first one we can come in and actually put a calc here so we can say calc select all of that and then do a minus and you'd expect one because our Gap is one but because this is 50 we're going to do a 0.5 REM which is half of our Gap and that could definitely be something you use a custom property for instead of setting it up this way just because then you know if you changed your Gap this number would also change and we're going to use custom properties for a few things to make it more customizable but just so you know those two numbers have to be related to one another this one's half of your Gap is and now we should see when it gets to that point the entire thing see how it just changed colors because it was perfectly aligned so in the animation restarts and everything just jumps back to where it was everything's perfectly aligned with where it needs to be but right now we have a terrible solution because we have to double our content which we never want to have to do um it just makes everything really awkward it's more work uh it's just not ideal so what we're going to do and we're using JavaScript anyway so we might as well set it up where the HTML makes sense and then we use JavaScript to set it up to actually work by duplicating the content for us and so let's jump back on over to our JavaScript so we can get started on this part here and what we want to do is we're mostly we'll make that bigger um just so we can javascript's always long lines uh we want to be focused on here where we're working on each individual scroller and we're going to need two different things here so we're going to say we want to get our we'll call it our inner scroller or we called it scroll or inner right so we'll say scroller inner so we have the same name is our scroller dot query selector and we want to get the dot scroller inner and the other thing we want to do is we want to get all of the content inside each one of those so here we can say that our const scroller uh we'll just say scroller content I could do scroll or inner content but it gets a little bit long so scroller enter and what we can actually say here is children but we don't want to do this uh well we sort of need to do this but if we do that let's console log that actually because this is going to give us an HTML collection which is updated live so uh if the Dom is updated that collection is updated um which can cause some problems so let's just take a quick look here and scroll content and if I go and look at my console scroll content is not defined scroller content would help uh and you can see it says HTML collection right there and then we get all of the lis as I mentioned this can cause a problem though because the HTML collection will be updated if the Dom is updated so if we duplicate the content that is inside of our inner scroller then there's more children that get added in and it duplicates that content which then gets duplicated which causes an infinite Loop uh and one way we can prevent that is instead by doing an array from and if we do an array from this is basically copy making a copy in that initial state that will won't get changed later on so now if we come take a look at it instead of it being before we saw it was an HTML collection so now we just have a standard array with seven different things in it that won't get changed even if the Dom is updated and that's exactly what we want because now we're going to duplicate them all so let's get rid of this and we're going to say there's different ways we could Loop over this but scroller content we can just do it for each if you want to do a different type of loop here there's no problem and we can say for each or we'll say each item that's in there so for each item we want to do something so we're going to do a function and just use the arrow function there we're going to say and I'm using const here for all of these even though we're obviously having more of them but it's limited to each time this runs so for each one this const is there if you'd rather use let or don't use VAR but if you'd rather use let you could but the cons to work fine here for these just in case you're wondering because it's sort of it's redone each time this is running so here we have const and we're going to say duplicated item is equal to and then we can say item and we can actually just clone it so clone node and in here we just say true and let's do a console log of that so we can see duplicated item and if we come and take a look now in here in our console we get each of those items coming and each one of them is the Li and this is good because we want it you know now I'm doing it as lies as I mentioned after we can have it as images we can have it as divs we can have it as whatever we want so it's taking that entire node and duplicating it we're not just getting the text or anything like that and then what we want to do and this is a really important step because we want to make the screen reader friendly as well so we can say that our duplicated content before we add it into the Dom because right now it doesn't exist anywhere we've duplicated them all in JavaScript world we haven't done anything with them yet but before we do anything we're going to take it and we're going to do set attribute and are and this is kind of weird with JavaScript sometimes I find that we can like do stuff to an item that doesn't exist outside of the JavaScript yet like we've duplicated this item it exists only here it's not on the page but we can still add classes to it or set attributes to it uh and other stuff so I always found that was kind of interesting that we can do that but we're going to say that we are not data we're going to say an aria hidden is going to be true and by doing that it just means or we'll see it in the Dom in a second um but yeah we just want to make sure that this content from a screen reader perspective the second the duplicated content doesn't show up in a screen reader because then it would read it all twice which would be really annoying um but then for we can go back to our scroller content so remember that's are the scroller or no not the scroller content we want the scroller inner we can go back to that scroller inner which is always we're doing this for each individual scroller so our scroller enter and then we can just do append uh child and what's the child we want to append we want it to be our duplicated item so now if I take a look you'll see it's even moving faster because we have more stuff in there and if we come and take a look in our Dev tools we will see that we have the UL and in the UL HTML CSS all the way down to UI ux and then we get this second set that all has the area hidden of true on there so we've duplicated our content and again there's other ways we could Loop through and get it if you'd rather do it a better way or if you have a better way leave a comment down below if you have a way that you'd prefer to do that let me know about it because I'm always trying to improve myself as well but I think that does the job and it gets it all there and you can see that this is actually working really well and we don't even notice when it Loops so that's really awesome you just it just keeps going and it works and it's that's what it is though of course this is a little bit limited because right now it can only work in One Direction and you might want it going the other way or you might want to be able to have different ones that have different speeds on them or you know there's lots of different stuff we might want to do here so let's look at how we can do that and so what we're going to do is we're going to come up to here and you have my animation May scroll this linear infinite so let's start here actually on the timing and let's just come in with a VAR of Animation uh speed or duration we'll say duration and what I'll do is I'm just going to put 40 seconds here is the default so that will be like if we don't declare one it's just going to run at 40 seconds that we could actually make a default or something but now this is going to work and if we want to change it we just have to worry about changing this and I'll show you why I like like this in a minute and the other thing we're going to add here is let's just put these on different lines prettier might not like this and change it when I save but the other thing that we're going to do here is have a bar of the animation Direction and the default for this one will be forwards and so if I hit save on that everything should continue working because we're moving forwards but what we can do now is we can come here and we could say that if we have a scroller and in in this case we're going to say that if it has a data direction is equal to the right we could do a an animation direction is going to be equal to reverse and let's just come over to here and I'll show you why I like doing with this approach so I'm going to copy the entire scroller bring it down and then I'm going to say data direction is equal to right and now we have one moving left and the other one moving right and they both work and that's great and the reason I like the reason it's easier to have the default one going this way is just because the way we have things set up where things naturally line up on the left side whereas if we want it to go toward the right then you have to do the easiest way to do it is using the reverse Direction so I mean if we want we could also have a data direction direction is equal to left and we could be explicit about it just so it you know if somebody's coming into a system like this it could be handy so here we could say forwards and so the direction is to my left and you can see it's working great and the reason I like doing this with custom properties is because this is actually the animation is actually getting set on the scroller inner and it's kind of more convenient to me to be putting these modifier data attributes and again I'm doing them as data attributes because you wouldn't want to accidentally set a direction to left and right which we could do with a class especially if you need to manipulate it with JavaScript becomes much easier to set an attribute than it is to like remove a class and add a new class in just that attributes for this type of thing make sense to me um but yeah then because it's a custom property I just have to worry about setting it on the parent where the scroller is so it makes sense that this is controlling everything even though it's sort of applying the style down onto this one so for that um the custom properties make sense and it's also why I put this underscore here it's just to say that it's like locally scoped to this it's not something coming from my root I think it was Leia veru though I might be mixing people up but that first introduced that idea of these private properties for CSS custom properties um so the other one that we could do is our speed now what I'm going to do is I'm actually going to comment these out because I find if there's too many things moving on the screen it makes me a little bit dizzy especially if they're moving in opposite directions and I've already prepped some of these off screen just to do it with images as well um I have this one also going to the right but I think for now we'll leave them both going the same direction and just do it with the speeds but we can mix and match as much as you want but again I just use pravatar because it's really easy if you want this to be logos or anything else you could throw whatever it is you want at this basically um and what we'll do is you can see here I have a data speed fast and a data speed slow so I could come in and we could let's just duplicate these two and then we could take this one and this one and make these data speed do a slow and a fast and then this would be my animation duration right for that one and that one so here just to slow down a little bit because I did that really fast we have the scroller data speed slow and then the data speed fast and I'm changing the animation duration and maybe for the fast one it's 20 seconds and for the slow one it's 120 seconds and so you can see that we change the speed that way and you probably would have consistent speeds on all of them if you're doing something like this but it is also something that you could come in technically and do and say style is equal to and say that my uh animation duration duration is actually going to be I don't know 500 seconds and it's gonna barely be moving so you could come in with some presets and you could you know presets that you decide based on what you're using for different speeds and then if somebody needed something that little inline style could be a way to custom set it up it'd be really nice if we could get data attributes to be used for things like this and just plug that in here sadly at this moment in time we can't do that though it is something that's on the table for be possible with CSS eventually but yeah let's go back I'm not going to put the or this actually I mix them up sorry guys this one should be by fast and this one should be my slow that would make a lot more sense um so yeah I'm not going to turn or we'll turn the other ones on really fast but I find with the motion in different directions and stuff it makes me feel a little bit awkward but you can see there it is you can throw basically any content at this I believe it should work fine um and let's just cover that up for a second and just to say if you enjoyed this video that you might also enjoy this one and that is right here as well and with that I would really like to thank my enablers of awesome who are Johnny Tim Simon Michael James and Andrew as well as all my other patrons for their monthly support and of course until next time don't forget to make your report on the internet just a little bit more awesome
Info
Channel: Kevin Powell
Views: 184,222
Rating: undefined out of 5
Keywords: Kevin Powell, css, front-end, frontend, html, web development, infinite scroll, infinite scroll css, infinite horizontal scrolling, scrolling animation, css scroll animation
Id: iLmBy-HKIAw
Channel Id: undefined
Length: 32min 0sec (1920 seconds)
Published: Thu Sep 28 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.