Welcome to WebmasterWorld Guest from 54.81.71.68

Forum Moderators: open

Creating a sliding carousel

     
4:42 am on Mar 13, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 775
votes: 69


I'm using jQuery and building my own little carousel. I know, I know, there are a million of them already available, but I need something I can modify for my own purposes easily... and, since I'm still relatively new to jQuery, it's fun to learn.

What I want is for the user to click the > button, then the existing image will appear to slide from right to left while the next image slides in from the right. And if they click the < button then the opposite will happen; the existing image will appear to slide from left to right while the next image slides in from the left.

I'm not quite sure how to accomplish that animation, though. What I've done so far is use a combination of transition: width .9s ease and $('#slider-' + n).css('width', '0') to shrink the original image and grow the new one in it's place, but this has more of a shuffled-cards effect instead of a slide effect.

Can you guys suggest how I might achieve the desired effect?

Here's what I have:

// Javascript
var x, dir;
var n = 0;

// this is actually defined in PHP
var end = 4;

function changeMain(n, dir) {
if (dir == 'next') x = n + 1;
else x = n - 1;

if (x < 0) x = end;
if (x > end) x = 0;

$('#slider-' + n).css('width', '0');
$('#slider-' + x).css('width', '294px');

return x;
}

// HTML
<div style="position: relative; overflow: hidden; width: 294px; height: 220px; background:#000">
<div id="slider-0"
style="float: left; overflow: hidden; width: 294px;
-webkit-transition: width .9s ease;
transition: width .9s ease"
onMouseOver="this.style.cursor= 'pointer';"
onClick="#">
<img src="https://www.example.com/photos/1128599_0.jpg" style="width: 294px; height: auto; border: 0">
</div>

<div id="slider-1"
style="float: left; overflow: hidden; width: 294px;
-webkit-transition: width .9s ease;
transition: width .9s ease"
onMouseOver="this.style.cursor= 'pointer';"
onClick="#">
<img src="https://www.example.com/photos/1128599_1.jpg" style="width: 294px; height: auto; border: 0">
</div>
<div style="clear: both"></div>

<div style="position: absolute; height: 50%; margin: auto; top: 0; bottom: 0; left: 0"
onClick="changeMain(n--)">
<
</div>

<div class="abs" style="height: 50%; margin: auto; top: 0; bottom: 0; right: 0"
onClick="changeMain(n++)">
>
</div>
</div>
2:38 am on Mar 15, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 775
votes: 69


Well, I have an update on this, but I still need help.

I can get the slide effect I want using jQuery UI, but I'm still a little lost... the first image slides to the left out of viewport like I want, but how do I get the second image to slide IN? The only options to toggle('slide') seem to be which direction to slide and speed.

// I don't know if I really need the CSS, but it was in the example
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

// Javascript
var x, dir;
var n = 0;

// this is actually defined in PHP
var end = 4;

function changeMain(n, dir) {
if (dir == 'next') x = n + 1;
else x = n - 1;

if (x < 0) x = end;
if (x > end) x = 0;

$('#slider-' + n).toggle('slide');

//// Eliminating these:
// $('#slider-' + n).css('width', '0');
// $('#slider-' + x).css('width', '294px');

return x;
}

// HTML
<div style="position: relative; overflow: hidden; width: 294px; height: 220px; background:#000">
<div id="slider-0"
style="float: left; overflow: hidden; width: 294px" // eliminating transition: width .9s ease
onMouseOver="this.style.cursor= 'pointer';"
onClick="#">
<img src="https://www.example.com/photos/1128599_0.jpg" style="width: 294px; height: auto; border: 0">
</div>

<div id="slider-1"
style="float: left; overflow: hidden; width: 294px"
onMouseOver="this.style.cursor= 'pointer';"
onClick="#">
<img src="https://www.example.com/photos/1128599_1.jpg" style="width: 294px; height: auto; border: 0">
</div>
<div style="clear: both"></div>

<div style="position: absolute; height: 50%; margin: auto; top: 0; bottom: 0; left: 0"
onClick="changeMain(n--)">
<
</div>

<div class="abs" style="height: 50%; margin: auto; top: 0; bottom: 0; right: 0"
onClick="changeMain(n++)">
>
</div>
</div>
3:21 am on Mar 15, 2018 (gmt 0)

Moderator from US 

WebmasterWorld Administrator keyplyr is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:Sept 26, 2001
posts:11761
votes: 738


Ask NickNMS. He installed a carousel a few weeks ago.
1:18 pm on Mar 15, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member Top Contributors Of The Month

joined:Apr 1, 2016
posts:1917
votes: 496


I don't know if I can be much help. Keyplyr is correct I have implemented carousels on my newly updated website, but I used the amp-carousel. It works great so far as I can tell. Also, I am not using it a slide show slider but rather as means to allow users to swipe through content horizontally on mobile. I was inspired by Google's use of this pattern in the mobile serps. Note, I use the amp-carousel on a page that can be amp, but also isn't amp (it's complicated) the point is that you can use the feature on non-amp pages.

As for coding your own carousel, that is quite a big undertaking as there are many use/edge cases to code for eg: different screen sizes, different image/content sizes and how you handle all the possible permutation and combinations of these.

Now regarding jQuery UI, I have no experience with it but I believe that you can download a non-minified version that is more readable. I suggest taking the time to scan through the code to understand how it works. My guess is that the css you commented out is important, they may be animating the width of the image making it appears as though the image is moving to the left, instead the image is simply going to a width of 0,y while the next image expands its width, or they may do this while the image is out of the viewport (I am speculating here).

I'm sorry I can't help more.
4:24 pm on Mar 15, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 775
votes: 69


I appreciate you looking anyway, Nick :-)

What I have is a Classifieds section, so the width is going to be predefined and the height is auto. Then I'm trying to set it so that they can click left or right, OR swipe left or right... and they can click to open it to 100% with a predefined max-width, where they can again click or swipe left or right.

That's a lot, I know, and that's why I'm trying to build my own instead of using an OOB that doesn't give me those options... and I figure that by time I reverse engineer an OOB and figure out how to modify it, I could have just built my own :-P

I have it pretty much working except that I can't get the slide effect just right. The second script I posted slides the first image to the left, but leaves a black box in it's wake. Then, then the image is finally gone (eg, width = 0) the second one just pops in instead of sliding. So I feel like I'm on the right path, I'm just stuck.
4:38 pm on Mar 15, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member Top Contributors Of The Month

joined:Apr 1, 2016
posts:1917
votes: 496


Why don't you place the 4 images in-line in a div. Then show the div in a viewport, eg: div of smaller size with the overflow hidden and then move the div with the 4 images across the view port from right to left such that each image crosses the view port. Once at its end position (far left) just move it quickly back to its initial position (far right). To be clear, move the div with the four images not each image individually.
6:09 am on Mar 16, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 775
votes: 69


That's an interesting thought, Nick. I tried to play around with that, and in doing so I accidentally stumbled across my problem...

Inside of the overflow: hidden div, my images aren't inline! I can't figure out why, but I found that if I increased the width of the container to 600px (room for 2 images with a little left over) then everything worked fine, but if I took it down to 500 then the second image was wrapping.

So I'm gonna play with this tomorrow (Friday), and hopefully I can get it fixed :-) If so then I'll post the final code for posterity.
12:20 am on Mar 19, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 775
votes: 69


Alrighty, guys and gals, I have it working pretty well now! One of the big kinks was that the images were wrapping in the child container instead of staying inline, and I couldn't see that until I removed the parent container for testing. That caused the new image to "pop" in instead of slide. So the solution was to make the width of the child container equal to the sum of the widths of all of the images; it's behind the parent container, anyway, so it doesn't really matter.

Another kink was when I was sliding to the left (or swiping to the right), it would still "pop" because it was waiting for the last image to be "moved" to the front. I worked around this by changing the order of the array, then using margins to move everything over by one image width. Meaning, where my initial layout looked like:

[0] 1 2 3
(with "0" being shown in the viewport by default)

I changed it to:

3 [0] 1 2

So it looks the same to the end user, but the "3" is already in place to be shown when the user slides to the left instead of sliding and then waiting for it to move.

The Javascript I posted in the first post of this thread would have probably been tweaked to work around it just fine, too, but I thought that this solution was cleaner.

I'm gonna lay out the code here, in the hopes that I can benefit someone else in the future.

Here's the PHP stuff, but there's no reason you couldn't manually define each of these variables throughout if you don't use PHP:
// I'm defining the images in an array. In my case I actually loaded them
// from MySQL
$img = array(
'image_0.jpg',
'image_1.jpg',
'image_3.jpg'
);

// Behind the viewport, all of the images are going to float inline so the width
// of the child container is the sum of all image widths combined. So I'm calculating
// the width, or you could just use a number that's always going to be larger.
//
// In my case, the width of each image is 294px so I'm multiplying by 294
$container_width = (count($img) * 294) . 'px';

// Moving the last image to the front of the array
array_unshift($img, array_pop($img));



Here's the Javascript and jQuery stuff:
<script src="//code.jquery.com/jquery-2.2.4.min.js"></script>

// Optional, I use this for the mobile swipe options
<script src="//code.jquery.com/mobile/1.2.1/jquery.mobile-1.2.1.min.js"></script>

<script>
// These are all defined when you call the function, but I'll explain them here for you
//
// the name of the container that surrounds the image carousel
var slideID;

// the direction we're going with the slide: "back" or "next"
var slideDirection;

// the width of the images being scrolled
var imgWidth;

// when they're going "back". This will most likely be the negative value of
// imgWidth, so it's optional; leave it off and the default is - imgWidth
var negImgWidth;

// in milliseconds, so 1000 is 1 second; default for the script is 900, so this
// is optional, too
var slideSpeed;

function slideImg(slideID, slideDirection, imgWidth, negImgWidth, slideSpeed) {

// so you can leave the '#' off when you call the function
slideID = '#' + slideID;

// set defaults
if (imgWidth && !negImgWidth) negImgWidth = '-' + imgWidth;
if (!slideSpeed) slideSpeed = 900;

// when they click the left button
if (slideDirection == 'back') {
$(slideID + ' ul').animate({ marginLeft: imgWidth }, slideSpeed, function() {

// takes the image on the left and moves it to the far right
$(this).find('li:first').before($(this).find('li:last'));
$(this).css({ marginLeft: 0 });
})
}

// when they click the right button
else {
$(slideID + ' ul').animate({ marginLeft: negImgWidth }, slideSpeed, function() {

// takes the image on the right and moves it to the far left
$(this).find('li:last').after($(this).find('li:first'));
$(this).css({ marginLeft: 0 });
})
}
}

// Mobile options, slide when the user swipes; I'm just leaving my
// defined ID of "carousel" here
$(function() {
$('#carousel').on('swipeleft', function() {
slideImg('carousel', 'next', 294)
});

$('#carousel').on('swiperight', function() {
slideImg('carousel', 'back', 294)
});
});

</script>



And the HTML (mixed with PHP), where you print the actual carousel:
// I'm still gonna put comments in the HTML as if it were PHP or Javascript, just 
// remember to take them out when you use it

echo <<<EOF
// this is the ID that becomes "slideID" in the Javascript
<div id="carousel" style="overflow: hidden">

// I use position relative so that I can overlay the < > button later
<div style="position: relative;

// the left margin is -300 because the width of my image is 294px, + 4px padding on
// left and right, plus 2px padding on left and right of the <li> later
margin-left: -300px; padding: 4px;

// remember, this DIV is going to be the sum of the width of all the images combined
width: $container_width;

// the height of my images; change this to whatever your height is
height: 220px">
<ul style="list-style: none; margin: 0; padding: 0">

EOF;

foreach ($img as $key) {
echo <<<EOF
<li style="float: left; padding: 0 2px">
<img src="$key" style="width: 294px; height: auto; border: 0">
</li>


EOF;
}

echo <<<EOF
</ul>


EOF;

// Here is where I create the < and > buttons; the left is based on the width of the
// first image that's hidden on the left side of the carousel
if ($img[1]) {
echo <<<EOF
<div style="position: absolute; height: 50%; margin: auto; top: 0; bottom: 0; left: 267px"
onClick="slideImg('carousel', 'back', 294)">
<
</div>

<div style="position: absolute; height: 50%; margin: auto; top: 0; bottom: 0; left: 544px"
onClick="slideImg('carousel', 'next', 294)">
>
</div>

EOF;
}

echo <<<EOF
</div>

EOF;
7:50 pm on Mar 20, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 775
votes: 69


Since we've gotten this far, I'm going to take it a smidge farther.

I have this, which works fine:
$(slideID + ' ul').animate({ marginLeft: imgWidth }, slideSpeed, function() {
$(this).find('li:first').before($(this).find('li:last'));
$(this).css({ marginLeft: 0 });
})


It moves marginLeft relative to the current position. So if I send, say, 300] then the first click will move it to marginLeft: 300px, the second will go to marginLeft: 600px, and so on.

I'm setting up thumbnails, though, so the user can click the thumb and go straight to the photo in the carousel. I also like it to animate, so I'm running the same function (just faster) and trying to specify the photo.

The only method I can think of to do this is:

onClick="$('#carousel ul').css({ marginLeft: 0 });
slideImg('carousel', 'next', false, -600, 300);">


In theory, this SHOULD move the UL list all the way to margin-left: 0, then slide left until it gets to the specified photo, right? In this case, if each photo is 300px in width then this should take me to the second one... -600px.

But it's not working like I expected. The first click it goes where I want, but then after that it seems to be all over the map. And what's really weird is if I keep clicking the same thumbnail, it keeps advancing once to the left (which makes no sense, because it shouldn't even be getting the imgWidth=300).

Thoughts?
 

Join The Conversation

Moderators and Top Contributors

Hot Threads This Week

Featured Threads

Free SEO Tools

Hire Expert Members