Animate the width of a div element with CSS from the center

I'm working on a cool menu animation as a little experiment. Here's what I've got so far:

HTML

<div class="menu">
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
</div>

SCSS

div.menu {
  width: 24px;
  height: 24px;
  position: relative;
  margin: 48px;
  cursor: pointer;

  div.bar {
    display: block;
    width: 100%;
    height: 2px;
    background-color: #444;
    position: absolute;
    transition: all 0.25s ease-in-out;

    &:nth-child(1) {
    }

    &:nth-child(2) {
     top: 11px;
    }

    &:nth-child(3) {
     top: 11px;
    }

    &:nth-child(4) {
     bottom: 0;
    }
  }

  &.active {

    div.bar {
      &:nth-child(1) {
        width: 0;
    }

    &:nth-child(2) {
      transform: rotate(-45deg);
    }

    &:nth-child(3) {
     transform: rotate(45deg);
    }

    &:nth-child(4) {
     width: 0;
    }
    }
  }
}

JAVASCRIPT

var menu = document.querySelector('.menu');

menu.addEventListener('click', function(){
    menu.classList.toggle('active');
  });

You can see the demo of this in action here: https://codepen.io/mikehdesign/pen/eWJKKN

Right now, when the menu is active, the top and bottom div.bar reduce their width to 0 towards the left. I'd like them to reduce their width towards the center instead. I've tried adjusting margins but couldn't figure it out. If anyone has any suggestions or a different approach, please let me know. Thanks!

- Mike

Answer №1

To achieve this effect, you can utilize the CSS property transform-origin:

In relation to your specific dimensions, you would adjust the values by 12px upwards and downwards (using plus and minus), as shown in the code snippet below:

&.active {
  div.bar {
    &:nth-child(1) {
      transform-origin: 12px 12px;
      transform: scale(0);
    }

    &:nth-child(2) {
      transform: rotate(-45deg);
    }

    &:nth-child(3) {
      transform: rotate(45deg);
    }

    &:nth-child(4) {
      transform-origin: 12px -12px;
      transform: scale(0);
    }
  }
}

You can view the implementation here: JsFiddle Link

Answer №2

If I were to break down the transform animation using pseudo elements, I would do it as follows: Check out this Demo (without scripts)

Here's what the HTML looks like (note that there are only three bars):

<input type="checkbox" id="toggle-menu" hidden>
<label for="toggle-menu" class="menu">
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
</label>

And here's the SCSS code:

// We use a two-step transition approach
// since translate and rotation can't be animated individually yet.
// The idea is to split up the animation using pseudo elements.

// Variables to control transition time and delay
$transition-time: 300ms;
$transition-delay: 300ms;

.menu {
    width: 24px;
    height: 24px;
    position: relative;
    cursor: pointer;
    display: block;
}
.bar {
    height: 2px;
    position: absolute;
    top: 50%;
    width:100%;

    // Entering the 'hamburger' state
    // 1) Add a delay on bars to synchronize with :after elements
    // 2) :after elements have no delay
    transition: $transition-time $transition-delay; // 1

    &:after { 
        content:''; 
        display: table; 
        background: black; 
        position: inherit; 
        width: inherit; 
        height: inherit;
        transition: $transition-time; // 2
    }

    // Transform the bars into hamburger 
    &:nth-child(1){ transform: translateY(-8px); }
    &:nth-child(3){ transform: translateY(8px);}    
}

// When toggle-menu checkbox is checked, transform to 'X'
[id="toggle-menu"]:checked ~ .menu {
    .bar {
        // Entering the 'X' state
        // 1) Remove transform to animate bars to center
        // 2) Switch transition direction for bars and :after elements
        transform: none;  // 1  
        transition: $transition-time; // 2
        &:after { transition: $transition-time $transition-delay } // 2

        // Rotate the top and bottom :after elements
        &:nth-child(1):after{ transform: rotate(-45deg); }
        &:nth-child(3):after{ transform: rotate(45deg);}         

        // Hide the middle :after by scaling to zero
        // (when all bars are at the center)
        &:nth-child(2):after{ transform: scale(0); }        
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to reach the array file

Having trouble accessing the elements of the file array const p_page = postP.new_pages; const p_page_o = postP.new_pages_order; const p_page_o_len = p_page_o.length; if (p_page_o_len > 0) { for (let i = 0; i < p_page_o_len; i++) { c ...

Change the position of a div by clicking a button using JavaScript

I have a div with an image that I want to move by clicking on a button within the same div. The reason for this is that clicking on the image itself allows it to move inside the div, but I want another element to control the movement of the entire div. He ...

Utilizing $scope in $compile in Angular: A Comprehensive Guide

Attempting to utilize my scope within a compile... I aim for a scenario where upon clicking a button, a div is generated containing the round number. main.controller('fightController', function($scope, $http, Services, $compile) { $scope.d ...

Need help resolving the issue of "Type Property '' does not exist on type 'IntrinsicAttributes & Function'? Let's find a solution together

Looking at my parent component below: import FilterComponent from 'filter/filterComponent' const handleReload = useCallback( (event: MouseEvent) => { event.preventDefault(); // implement logic here }, [Reload, Fetch ...

Why is my <a> element not functioning properly?

I'm encountering a small issue with my first HTML website. The hyperlinks in the "about me" section are not clickable, yet those in the drop down menu are functioning properly. Any thoughts on why this might be happening? If you'd like to take a ...

Using Highstock for Dynamic Data Visualization in Web Applications

Looking to create a chart using data from a MySQL database that includes timestamps and temperature readings. The timestamp format is '2015-06-11 22:45:59' and the temperature is an integer value. Unsure if the conversion of the timestamp to Java ...

"Uncovering a memory leakage issue within a recursive polling function in JavaScript

Current issue in need of resolution: My team and I are currently working on a large application that was initially released around two years ago. We are in the process of adding a new "always-on" status screen to the application, which will be the default ...

Fixing Firefox Bug: How to Eliminate Non-Numeric Characters from "Number" Input Fields

Completing this task seems straightforward. I need to eliminate any non-numeric characters from an input field specified as type "number" in Firefox when a key is pressed. The code snippet provided: $("#field").on("keyup", function() { regex = /[\& ...

How do I extract a specific property from an array of objects and assign it to a new array in Typescript 2?

I've got this TypeScript 2 "model" that looks like this: export class MyModel { myProperty1: string; myProperty2: string; ... } In addition to the model, I have another class defined as follows: // Imports excluded for brevity @Component . ...

Debugging on the server side of Meteor application is crucial for

I am attempting to debug a Meteor app on Windows using node-inspector. I am following these steps: First, install node-inspector by running: npm install -g node-inspector Next, start Meteor in debug mode by running: NODE_OPTIONS='--debug' meteo ...

As the week progresses, the cells corresponding to each weekday will automatically highlight, from Monday through Sunday. If today is Tuesday, the Tuesday cell will be highlighted accordingly. Please refer

Take a look at the image provided in the link below. I need the library hours to be automatically highlighted each day. https://i.sstatic.net/LvqhR.png ...

Grid Alignment Centered - Inner Grid aligned to the left - Zero Javascript or Media Queries Allowed

[UPDATE] Looking for a solution that doesn't involve javascript or media queries as the user should be able to change the container size. [/UPDATE] In need of creating a grid layout for items. The container's width is flexible. The grid must ...

Should tokens be sent via POST request or stored in a cookie?

I have a single-page Node.js Facebook Canvas App. Whenever a user interacts with the app, it triggers an AJAX POST request to my Node.js HTTPS server, which then returns the result. Now, I am looking for a way to send a user token that I generate from the ...

What steps can I take to modify this HTML code so that my Tumblr background does not repeat and covers the entire page?

body { color: #1a1a1a; font-family: Arial, Helvetica, sans-serif; font-size: 12px; line-height: 19px; background: url('http://www.totallylayouts.com/backgrounds/hipster/triangle_in_the_woods.jpg') no-repeat top left scroll; Even after attemp ...

Button-click scrolling is our featured feature!

One interesting feature on my website is a button (within a div-element) located in the bottom-right corner. I am now looking to enhance this by adding a jQuery function that enables the user to scroll down the page incrementally simply by clicking and hol ...

Exploring methods to trace the factory's property that is receiving updates from another factory within AngularJS

Hey there, I'm new to Angularjs and I have a bunch of factories in my application. The situation is, let's say we have obj1 in factoryA. Whenever I console.log(obj1), it displays numerous properties associated with it. This object is being update ...

struggling to locate the file index (I've attempted numerous solutions from various forums with no success...)

Apologies for asking a question that may have been asked numerous times before, but I'm encountering some issues and need your help... Thank you in advance! Here is the HTML form I am working with: <form action="action/actionindex.php" method="po ...

Updating the URL-path in the Angular file-upload module: A step-by-step guide

When working on my project, I came across a helpful module that I use from https://github.com/nervgh/angular-file-upload. It functions well when the URL is set during initialization. However, I encountered an issue when trying to change the URL after the ...

Bootstrap 4 Landing Page Creation

I recently had a landing page created for me with a clean and simple design. However, I have noticed that the Banner Photo is taking up too much space on the page, causing users to scroll in order to view the entire content. Is there a way to adjust the ...

Verification of Phone Numbers (Global)

I am attempting to create a validation check for mobile numbers, similar to the one implemented by Gmail. Check out Gmail's signup page here However, there is significant variation in phone number formats across different countries, making it challe ...