A boring title. What else could I have called it? Anything else would probably be too dramatic. I’ve built a new slider! With working animation! Arguably already too dramatic.
I am so tired. And of course there is brain fog. Once I can make some money I might get my brain scanned as I think real confirmation would put me off drinking for good but without proof I continue. I don’t know what it is I think. I know it never does me any good but I suppose I tell myself that the effects of alcohol exacerbate something else. And that may be true. But it’ll have to wait because two hundred quid is a lot for a brain scan and my drinking, whilst unimaginably foolish, is vaguely under control. Even if day to day life is a pain.
However! I’ve been building a new website. It’s based on another one that has a simple slider and I felt uneasy about using an existing chunk of code for something as simple as this. That and when it’s your own site, well, when it’s my own site, I want it to be fully my own. This is boring but it’s probably good for my mind.
Anyway. A previous slider I’d tried which sits in a modal on my website had all the animations and arrows and stuff working, but it had a major flaw and this was that when it animated, it was attempting to animate each image and the one before and after it individually. I don’t know if there was a quick fix or if a different method of doing it altogether might have sorted it out but I have found a solution anyway and I’m rather pleased with what I have. For some reason, I can’t learn because I can’t think and I can’t code a website because it’s too boring to grip my mind, but I have discovered that I can write badly written code to try and create something reusable. So I thought I’d write about it here.
It was inspired by a slider someone else had written about but theirs only went forwards. It worked and avoided the animation bug I’d found in my own by using a flexbox div. The flexbox div was in a container that had overflow hidden on it and the elements, or slides, had their shrink property set to 0. So if you add slides with a width of 100%, say two, then the slider will display the first one added, but it leaves you to add more to the right which the user cannot see.
So the idea is this: someone hits a next arrow, then you shift the entire flexbox div to the left, so you add a class that tells it to animation the transition property. At this point you see the second slide and the first one is now hidden to the left. As soon as that transition is finished, which you can detect with transitionend — something that didn’t have great support when I started freelancing, things have changed somewhat — you turn off the transition by removing the class, you shift the slider back to the right and then reorder your slides so that the user doesn’t notice.
That’s how the initial version I saw worked. I liked it but I wanted a slider to go backwards. So I’ve done the same thing but initially always having a slide to the left, which will either be the last one when it first gets started, or the one previous to the current one, and there is always a slide to the right as well.
As a next step I’ve also set up the code to allow you to choose the number of slides you want to have and as a step on top of that you can also choose how many slides you want to have on the screen at any one time.
The code isn’t particularly good and needs cleaning up and for loops could be neater and all that but I’ll share some of it. Before I do though I’ll add in some thoughts for further development. I want to make it
Here’s the HTML:
I’ve just noticed I was working on what I thought was a copy of my original working version one but it was actually that one. For God’s sake use GIT and don’t code with a foggy head.
Also soemthing new to me were modules outside of the context of React or Vue. Does main.js need to be a module? I’ve no idea, but slider is one and is exported. So looking at the constructor. I’ve used an old fashioned constructor function. Maybe I’ll use the class keyword later, but I believe it still uses constructor functions under the hood. It’s not particularly pretty but I feel like communicating like this is like breathing so do humour me:
There are some tidies to be done here. Boringly I’ll go over this as it helps my head:
- noOfSlides will be removable as I’ll be able to count the passed-in number of slide divs but it can stay for now.
- slider I’m not sure if I’m using, but I plan to have this as a pointer set up on construction rather than reaching into the DOM each time I need to access it because DOM access is expensive and it’s just better practice.
- noOfSlidesToShow could possibly do with a better name but will be passed in in future. It can stay as it is for now.
- slides represents the DOM elements that are the slides.
- prevButton and nextButton. These can remain. They’re pointers to the arrow controls.
- currentSlide can go. For now anyway, I don’t think I need it. The flexbox stuff takes care of ordering and I reorder the array of slides as necessary anyway.
- previousSlide can go.
- displayedSlide can go.
This leaves us with:
Not bad. Now we’re down to 229 lines. I can lower this by removing comments and logs leaving…132 lines. Not bad. Almost 100 lines less.
I think that calls for lunch.
Right! So this is the first thing that happens externally:
The render method is the first thing that gets called and it looks like this:
The slider’s assigned to a variable, that’s as simple as it gets.
Next we iterate over the slides. Can’t get hold of the length of an array here since the array’s not been set up. It’s just setting up a div with a paragraph in it with the text “Item n” in it and then it’s stashed away into an array called slides.
Next we set up the slides that are before the current one so if you are showing two of them it will run from zero to 1. If I sound like a coding novice at this point it’s because I’ve lost my grasp of what the hell I was doing.
The thing is, when you pass in an array of slides — or in this case generate them within your render method — they’re not going to be in the correct order for the sliding method using the flexbox and offscreen elements that we’re using here. So if you imagine we have one slide showing on screen at once, the first slide you pass will be the one you want to initially see, but this means it should be placed at position two, because position one will be for the offscreen element. In this case you’d have the last element on the left in case the user hits the previous button. You can see that if you have one slide to show at a time, then on the first iteration it will set the first slide to be, imagining slides to initially be what was passed in, we set the first slide in the array to be the last. This is because we target slides[i] where i will be zero and we get the last one by offsetting from the end by the number of slides we’re showing minus i, because we need to do this for each item before the current one. It works even if it has blown my head off — it’s not complicated but it looks a bit peculiar. Maybe there’s a prettier way.
So we have one slide set to the start and it’ll be given an order of 1. Next we set up the slides that will include the current one and any after. When setting each slide we grab it using i minus the number of slides to show because…because…well. For example. Let’s say you have one slide to show on each slide. If that makes sense. One item to show at a time. Then i will start at 1 so you need to subtract two to get to item zero which will be your current slide. If you’re showing two slides then you’ll want to go back two to get to zero.
Have I overcomplicated this? It works but certainly it confused me. Though I was rather foggy when I wrote it and I still am which is probably why I’m writing this…
Anyway, with that done we add the slides to the DOM. To the flexbox to be more precise and each one already has its order set. After this it’s just a case of adding the buttons to the DOM. Maybe the most interesting part is the last line that then shifts the flexbox container to the left by its own width. This gets the right slides on the screen, and off it, so if you have two slides per screen, you’d have two to the left, two visible and two to the right.
Another interesting line — tell a lie, none of this is interesting — but an important line is the call to the instance method events.
As you can see here, all this does is call a method prev or next depending on which button you’ve pressed, and of course adds the relevant event listeners.
Let’s look at the prevButton’s click.
At this point I feel it right to point out that all of this code is mine. I was inspired I tell no lie, but just because I don’t always understand my code does not mean it’s not mine. My brain capacity is limited. So shush.
As soon as the previous button is clicked the transition is added using a class. This just says animate everything over a second. Then the entire container is shifted, and animated, to it’s natural position which means everything will shift to the right. What we want is to shift everything to the right to reveal the previous slide.
There’s an event here and this is the sneaky part. If you currently shift everything from left to right a slide’s width then you’re left with nothing more to shif into if you were to hit previous again. So we need to reconfigure everything. The event is for after a transition has finished, so after that initial shifting animation, the animation is switched off, we shift the flexbox back to being 100% back, and then we reorder the slides. It’s sneaky but it works. I will have to stare at my code for a bit, but this reorders the slides array to be in the correct order and sets the ordering to be as it should be.
Similarly for the next button:
This one has to shift to the left by 200% since the slider naturally sits at -100% and we want to go the left by a slide’s width.
I like this. I like it because it’s my own. I’d have no issue using someone else’s on a client site but I think it’s good to write your own and having done it before the animation was something I wanted to sort out.
I expect there are some optimisations and code reduction I could do, but I’m not too fussed — it’s pretty short now. I will try and make it user friendly with the suggested updates, however, and also get a working copy online to link to in due course.