Lance
Lance

Reputation: 193

Animate two elements from a vertical alignment to horizontal alignment

I have a page with a label directly above a textbox, and this is all centered vertically within the page. After the input is verified I would like to shrink the elements and slide them to the top of the page, while simultaneously "rotating" them to be next to one another, with the label on the left and the textbox on the right. So essentially I want to go from this in the middle of the screen and large:

                Label
               Textbox

to this at the top of the screen and back to a regular size:

           Label: Textbox

I just can't seem to figure out the best way to handle it.

To be clear here, I'm wanting to animate this. To go from the top example to the bottom of the example in fluid motion.

Here is a fiddle of what I'm beginning with: http://jsfiddle.net/xpvt214o/280404/

Here is a fiddle of what I'm wanting to end with: http://jsfiddle.net/xpvt214o/280396/

The motion to get from fiddle 1 to fiddle 2 needs to be animated. That's what I'm struggling with.

Upvotes: 1

Views: 708

Answers (3)

Ivan
Ivan

Reputation: 40708

Note: I have seen the result you wanted to achieve: smoothly translate the two elements from inline to inline-block. I've found a way to do this. As it is a completely different approach from my initial solution, I have decided to post another answer.


Setup

You can achieve the desired result with plain CSS but there are a couple of things to take care of.

  • we will position the main container .parent with absolute

    .parent { 
      position: absolute;
    
      /* dimensions */
      width:  35%
      height: 20%;
    
      /* centered horizontally */
      margin: 0 auto; 
      left: 0;
      right: 0;
    
      /* centered vertically */ 
      bottom: 0; 
      top: 45%; 
    }
    
  • to change the layout .parent will get the class .parentMod which will overwrite some of .parent's initial properties:

    .parentMod {
      top: 10px;
      height: 12%;
    }
    
  • both sub elements are too positioned with absolute their vertical position inside .parent have to be set (with percentages to ensure the layout is responsive):

    .parent > div:nth-child(1) {
      left: calc(50% - 125px);
    }
    .parent > div:nth-child(2) {
      left: calc(50% - 10px);
    }
    
  • then we can set their position when the layout has changed:

    • both sub elements will have the same vertical position:

      .parentMod > div:nth-child(1), 
      .parentMod > div:nth-child(2) {
        top: 0px;
        left: 0px;
        right: 0px;
        width: 100%;
      }
      
    • the second sub element will have a vertical offset (it will be positioned below the first sub element):

      .parentMod > div:nth-child(2) {
        top: 35px;
      }
      

Demo

Overall the result will look like:

const changeLayout = () => {
  document.querySelector('.parent').classList.toggle('parentMod');
};
.parent {
  position: absolute;
  margin: 0 auto;
  bottom: 0;
  right: 0;
  top: 45%;
  left: 0;
  width: 35%;
  height: 20%;
  font-size: 40px;
  transition: all 2s ease;
}

.parent > div {
  text-align: center;
  width: 130px;
  margin: 0px;
  position: absolute;
  top: 10px;
  transition: all 2s;
}

.parent > div:nth-child(1) {
  left: calc(50% - 125px);
}
.parent > div:nth-child(2) {
  left: calc(50% - 10px);
}

.parentMod {
  top: 10px;
  height: 12%;
}
.parentMod > div:nth-child(1), 
.parentMod > div:nth-child(2) {
  top: 0px;
  left: 0px;
  right: 0px;
  width: 100%;
}

.parentMod > div:nth-child(2) {
  top: 35px;
}
<div class="parent">
  <div>Label</div>
  <div>Textbox</div>
</div>

<button onclick="changeLayout()">Switch Layout</button>

Upvotes: 1

arborvitae
arborvitae

Reputation: 21

You can try positioning them absolutely and using flex-box on the parent to center-align them.

It's not a very flexible solution, but it gets the job done!

HTML

<div class="container">
  <span id="one">Label</span>
  <span id="two">Textbox</span>
</div>

CSS

.container {
  position: relative;
  width: 200px;
  height:200px;
  display: flex;
  flex-flow: column;
  align-items: center;
}
#one, #two {
  font-size: 1em;
  display: block;
  height:1em;
  text-align: center;
  margin: 0;
  transition: all 500ms ease;
}
#one {
  position: absolute;
}
#two {
  position:absolute;
  margin-top:1em;
}
.container:hover #one,
.container:hover #two {
  font-size: .75em
}

.container:hover #one{
  margin-left: -10px;
}
.container:hover #two{
  margin-top: 0;
  margin-left:30px
}

Upvotes: 0

Ivan
Ivan

Reputation: 40708

Initial response

  1. You can use vertical-align: middle and text-align: center to vertically and horizontally center your content. In the example: .parent1

  2. To have both div next to each other on the same horizontal level use display: inline-block. In the example: .parent2

.parent1, .parent2 {
  vertical-align: middle;
  text-align: center;
}

.parent1 {
  font-size: 30px;
}
.parent2 {
  font-size: 20px;
}

.parent2 > div {
  display: inline-block;
}

.parent2 > div:nth-child(2):before {
  content: ': ';
}
<div class="parent1">
  <div>Label</div>
  <div>Textbox</div>
</div>

<br /><hr />

<div class="parent2">
  <div>Label</div>
  <div>Textbox</div>
</div>


With animation

Bonus if you wish to animate it:

You will need transition to set the animation type and duration. Then prepare two CSS classes:

  • a default one called .parent positionning the item in the center of the screen

    .parent {
      position: absolute;
      left: 25%;
      top: calc(50% - 47px);
      width: 50%;
      vertical-align: middle;
      text-align: center;
      font-size: 40px;
      transition: all 0.5s ease;
    }
    
  • another one that will be toggled and which overwriting the position of the element to the top of the screen.

    .parentMod {
      top: 0px;
    }  
    

I have added an event listener attached to the button so you can see the animation by toggling the state with a mouse click:

const changeLayout = () => {
  document.querySelector('.parent').classList.toggle('parentMod');
};
.container {
  height: 200px;
}

.parent {
  position: absolute;
  left: 25%;
  top: calc(50% - 47px);
  width: 50%;
  vertical-align: middle;
  text-align: center;
  font-size: 40px;
  transition: all 0.5s ease;
}

.parentMod>div {
  font-size: 20px;
  display: inline-block;
}

.parentMod {
  top: 0px;
}

.parentMod>div:nth-child(2):before {
  content: ': ';
}
<div class="parent">
  <div>Label</div>
  <div>Textbox</div>
</div>

<button onclick="changeLayout()">Switch Layout</button>

Upvotes: 2

Related Questions