Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fake width animation with CSS transform?

I'm trying to animate the width of a side menu, so that the menu "collapses", but I'm running into a few constraints:

  • I want the menu to still show the leftmost 20px when collapsed, so you can see an "affordance" of the menu.
  • I want to avoid animating the width of the menu because I want to avoid content reflow. (I've managed to circumvent this by having a full width container inside the menu, so that the inside content just overflows, instead of reflowing to the size of the menu).
  • I want to use a CSS transform, so that the transition is GPU accelerated and performant, and interpolation is smooth (and also to avoid costly reflows).

This is the initial state of the menu:

Menu is the gray container on the left

This is the final state I wish to achieve:

The caveat of using transform: translateX(-Npx) is that the remaining affordance of the menu is the rightmost, not the 'dots' I show on the left side. I wish I could have a mask on top of the menubar that I could move over the menu, to hide its contents, but I believe that doesn't exist in CSS.

Do you have any ideas on how to fake this width animation, ideally using a CSS transform?

Thanks a lot!

Update: I've created this fiddle with what I have: https://jsfiddle.net/o437cpcc/1/ (The problem is, the final application of the menu has potentially hundreds of items, more text, making the width transition extremely laggy.)

This other fiddle is the approach with transforms, which when tested with hundreds of DOM nodes inside is much more performant, since it triggers no reflow and the animation is GPU accelerated: https://jsfiddle.net/vr1hnwd6/1/ . (The problem is, the dots also move because the whole box is translated).

like image 736
abmirayo Avatar asked Nov 01 '25 05:11

abmirayo


1 Answers

One posibility is to animate the inner ul in the opposite way.

Begin with a translation of the opposite sign, and end with a zero translation

html, body {
    margin:0;
    padding:0;
    height:100%;
}

#menubar {
    width: 400px;
    -webkit-transform: translateX(-370px);
            transform: translateX(-370px);    
    background-color: #DDDDDD;
    height:100%;
    overflow:hidden;
    -webkit-transition: 1500ms -webkit-transform;
            transition: 1500ms transform;
}

#menubar:hover, #menubar:hover ul  {
    -webkit-transform: translateX(0);
            transform: translateX(0);
}

ul {
    -webkit-transform: translateX(370px);
            transform: translateX(370px);    
    -webkit-transition: 1500ms -webkit-transform;
            transition: 1500ms transform;
    width: 400px;
    margin:0;
    padding:0;
    list-style-type: none;
}

ul li {
    width: 100%;
    box-sizing: border-box;
    padding: 25px 10px;
    background-color: #C6C6C6;
    font-family: sans-serif;
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -webkit-align-items: center;
        -ms-flex-align: center;
            align-items: center;
    margin-bottom:3px;
    cursor:pointer;
}

ul li:hover {
    background-color: #D6D6D6;
}

ul li .dot {
    width:10px;
    height:10px;
    border-radius:10px;
    background-color: teal;
}

ul li .title {
    margin-left:15px;
}
<div id="menubar">
    <ul>
        <li><div class="dot"></div><div class="title">Item example</div></li>
        <li><div class="dot"></div><div class="title">Item example</div></li>
        <li><div class="dot"></div><div class="title">Item example</div></li>
        <li><div class="dot"></div><div class="title">Item example</div></li>
        <li><div class="dot"></div><div class="title">Item example</div></li>
        
    </ul>
</div>
like image 167
vals Avatar answered Nov 02 '25 20:11

vals