DEV Community

Cover image for Forcing CSS animation on dynamic containers with Javascript
Jefferson Osagie Iyobosa
Jefferson Osagie Iyobosa

Posted on • Originally published at developer.mozilla.org

Forcing CSS animation on dynamic containers with Javascript

Hey there! Recently i made a post about how to make content containers toggle heights or widths with transitions, this is an update to the post.

Most times when we try to build things like accordions, collapsible Navbars or anything that toggles heights or widths, we often find out that the animation never works when we try to set the heights or widths to auto. So instead of smoothly stretching back and forth, it just snaps. Yuk!
As an alternative sometimes, we instead use fixed values. But then using fixed values has its setback as it would truncate overflowing contents if the container is dynamic.

Alt Text

Well, the reason behind the animation issue is very well explained here by w3: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#Specifications
So let's skip all these reasons it shouldn't work and lets see how to fix it!
We begin by adding some HTML to populate the container:

//The button element would be used as our toggle 
<div class="navigation">
   <button class="knob">Toggle Height</button>
   <div class="content">
    <p>
       Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

    </p>
   </div>
</div>

Then a little styling

.navigation{
        max-width: 300px;
        font-family: poppins;
        padding: 15px;
        border-radius: 50px;
        transition: .5s;
    }
    .navigation .knob{
        width: 100%;
        border: none;
        background: -webkit-linear-gradient(left, #5efce8, #736efe);
        color: #fff;
        font-size: 16px;
        font-weight: 600;
        padding: 20px;
        text-align: center;
        box-shadow: 3px 5px 3px rgba(0,0,0,.09) ;
        transition: .5s;
    }
    .navigation .content{
        overflow: hidden;
        transition: .5s ease-out;
        background: #fff;
        box-shadow: 0px 20px 20px rgba(0,0,0,.05);
    }
    .navigation .content p{
        overflow: hidden;
        color: #555;
        background: #fff;
        margin: 20px 0px;
        box-sizing: border-box;
        padding: 20px;
    }


Then we add the JavaScript

 //Get the elements
    let knob = document.querySelector(".knob");
    let content = knob.nextElementSibling;
    // Get the full height of the container
    let defaultHeight = content.scrollHeight;

    knob.addEventListener("click", () => {
        // Check if the current height of the container is same as it's original height
        (content.style.height == defaultHeight + "px") ? 

        // If the condition above is true, set the height to zero (toggle close)
        content.style.height = "0px" : 

        // Else make the height stretch to its full height ( toggle open) 
        content.style.height = defaultHeight  + "px";
    })

And voila! That's all. With that little code, we have a fully functional toggling dynamic container. The same principle used here is applied to widths:
So instead of scrollHeight, we use scrollWidth.

 //Get the elements
    let knob = document.querySelector(".knob");
    let content = knob.nextElementSibling;
    // Get the full width of the container
    let defaultWidth = content.scrollWidth;

    knob.addEventListener("click", ()=>{
        // Check if the current width of the container is same as its original width
        (content.style.width == defaultWidth + "px") ? 
        // If the condition above is true, set the width to zero (toggle close)
        content.style.width= "0px" : 
        // Else make the width stretch to its full width ( toggle open) 
        content.style.width = defaultWidth  + "px";
    })

Alt Text
-final

I hope this helps you get over that snapping heights and widths. Feel free to ask questions if you find any part of this foggy :)

Top comments (2)

Collapse
 
codelitically_incorrect profile image
codelitically_incorrect

It's a beautiful thing to see w3c-style native code.

Collapse
 
frontend_io profile image
Jefferson Osagie Iyobosa

Thanks. Wanted to keep things simple.