Tuesday, November 28, 2017

Hidden Carousels

I came across an issue while working on a freelance project where my client wanted to create some collapsed drawers that would expand when you clicked on on the Call To Action (CTA) button. This wasn’t very difficult and was some straightforward JavaScript until I hid the expandable content by setting display: none in the CSS.

Normally, this isn’t an issue with most content, but in my case the content was mainly comprised of carousels. Here’s the thing about carousels: They need some time to figure out what their dimensions are when the page is loading. But if you set display: none, then the content is taken out of the flow of the DOM. So when the user attempts to expand the hidden content, they’re shown a garbled mess for more than a few seconds until the carousel renders itself properly.

So how can we fix this issue?

First, we’re going to want to set the CSS of the content as so:

.hiddenContent {
    position: absolute;
    top: -3000px;
}

This takes our carousel out of the flow of the document and puts it really far up the page so that it doesn’t get shown to the user.

Next, in our JavaScript, we’re going to need to do two things:

  1. Update the CSS of our content so it’s in the correct position.
  2. Set a boolean that will change the display of the hidden content to display: none when the CTA is clicked. This will allow us to use jQuery’s toggleSlider function without having to write our own.

So here’s a basic toggle function that will slide our hidden content out with the CTA is clicked:

slideContent = function() {
    $('cta-btn').on('click', function() {
        $('.hiddenContent').slideToggle(800);
    });
};

Now let’s add our flag that will run when the CTA button is clicked along with the CSS fix for the position.

slideContent = function() {
    var reset = true;
    if(reset) {
        $('.hiddenContent').css({
            'position': 'relative',
            'top': 'initial'
        });
    }

    $('cta-btn').on('click', function() {
        $('.hiddenContent').slideToggle(800);
    });
};

One thing to note here: We’re setting this boolean flag so that this will only run one time after the CTA button is clicked. We don’t need (nor want) to keep updating the CSS after the first click.

So if you were to try and expand your hidden content right now, you’ll probably find it’s somewhat buggy. This is because jQuery’s slideToggle works by changing the display property of an element. Since we’re not changing the display of our content, the initial value is set to block (or whatever property you’re using).

This means that slideToggle is actually attempting to collapse your already collapsed content!

We need to go back and add one more line to our JavaScript.

slideContent = function() {
    var reset = true;
    if(reset) {
        $('.hiddenContent').css({
            'position': 'relative',
            'top': 'initial',
            'display': 'none'
        });
    }

    $('cta-btn').on('click', function() {
        $('.hiddenContent').slideToggle(800);
    });
};

By adding display: none to our one-time reset code, slideToggle now correctly expands the collapsed content.

Now you might be thinking, “Why are we changing the display to none? Wasn’t that the big problem from the start?!”

Well, yes and no. The issue wasn’t setting display: none, it was the carousel needed time to render properly. Since we’re not initially setting display: none on our carousels when the page loads and instead just moving them out of sight, they’re able to load properly in the background. After this, we can safely set display: none because they’re fully rendered. In fact, we have to, otherwise slideToggle won’t even work properly.

So there you have it. I don’t know if this is the best way to get around this issue with carousels, but it’s a fairly simple one that worked for me. Here’s the CSS and JavaScript all together:

CSS

.hiddenContent {
    position: absolute;
    top: -3000px;
}

JavaScript

slideContent = function() {
    var reset = true;
    if(reset) {
        $('.hiddenContent').css({
            'position': 'relative',
            'top': 'initial',
            'display': 'none'
        });
    }

    $('cta-btn').on('click', function() {
        $('.hiddenContent').slideToggle(800);
    });
};

Hope this helped!