问题
I'm building basic navigation for a website, and the graphical/animated functionality that I would like is this:
1: When in the 'HOME' state, the site logo/icon is large and centered and above the rest of the navigation/page links.
2: When on any other page than home, the logo/icon is smaller, and sits proportionally in a horizontal flexbox with the other elements.
3: There is a smooth transition between these two states.
I've implemented this already as you can see below, but the transition is jittery when page is full sized. I am new to both CSS and Angular, so forgive my ignorance in advance.
My question:
Is there a better way to implement a into/out-of flexbox animation than i've provided here, and/or is there a CSS animation optimization that I am missing to smooth this transition further?
The end product will all have a similar background color, but I have chosen bright colors in this illustration to show what the divs are doing in the background.
Note: I've tried using 'will-change' to no real effect, and I'm aware that I can do this without using angular, but there are features beyond this simple animation that will utilize angular down the road.
Here is a fiddle for it too: https://jsfiddle.net/willcthomson/f6wk4Lpq/
/* angular */
function mainCtrl($scope) {
$scope.ng_div_home = 'div_home_scale_up';
$scope.ng_div_logo = 'div_logo_scale_up';
$scope.ng_div_logo_upper_container = 'div_logo_upper_container_scale_up';
$scope.ng_logo = '';
$scope.ng_ISHOME = true;
$scope.f_scale = function()
{
if(!$scope.ng_ISHOME)
{
$scope.ng_div_home = "div_home_scale_down";
$scope.ng_div_logo = "div_logo_scale_down";
$scope.ng_div_logo_upper_container = 'div_logo_upper_container_scale_down';
}
else
{
$scope.ng_div_home = "div_home_scale_up";
$scope.ng_div_logo = "div_logo_scale_up";
$scope.ng_div_logo_upper_container = 'div_logo_upper_container_scale_up';
}
console.log("ishome is:"+$scope.ng_ISHOME);
};
}
/* css */
html{
position: relative;
min-height: 100%;
background-color: #222222;
}
body{
background-color: #00000000;
}
/*a container that sits on top of the nav bar and grows vertically to make room fo the expanding logo-icon*/
.div_logo_upper_container
{
/* background-color: #111111; */
background-color: magenta;
width: 80%;
margin: auto;
transition: height .5s linear;
margin-top: 5vw;
}
/*a flex container to hold nav elements*/
.nav_container
{
/* background-color: #111111; */
background-color: yellow;
width: 80%;
margin: auto;
display: flex;
align-items: stretch;
align-items: flex-end;
}
/*a div that scales forcing the other flex elements respond */
.div_home
{
background-color: #00000000;
background-color: cyan;
margin: auto;
transition: .5s linear;
will-change: transform, width, flex,;
}
/*a div that holds the logo, and does the actual scaling and movement*/
.div_logo
{
padding: 3px;
margin: 3px;
margin-left: 2vw;
transition: .5s linear;
will-change: width;
}
.img_logo
{
max-width:100%;
max-height: 100%;
min-width: 8%;
min-height: 8%;
will-change:width;
will-change:height;
}
/*expands the home container amongst the other flex elements to make room for incoming logo*/
.div_home_scale_down
{
width: 10vw;
flex: .5 1 40px;
}
/*shrinks the home container to allow flex elements to expand into the created gap*/
.div_home_scale_up
{
width: 3px;
transform: translate(25vw,-10vh);
align-self: center;
}
/*expands the logo container*/
.div_logo_scale_up
{
width: 30vw;
margin-top: 5vh;
}
/*shrinks the logo container*/
.div_logo_scale_down
{
margin: 1vh;
width: 10vw;
position: static;
}
/*expands the area above the nav container to contain the larger icon*/
.div_logo_upper_container_scale_up
{
height: 10vh;
}
/*shrinks the upper container as the icon files in with other elements */
.div_logo_upper_container_scale_down
{
height: 1px;
}
.nav_items
{
flex: 1 1 10px;
margin-bottom: 2vh;
font-family: verdana;
font-size: 30px;
color:grey;
text-align: center;
margin: 3px;
transition: font-size, color, transform, .5s linear;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!--html-->
<div ng-app>
<div ng-controller="mainCtrl">
<div class="div_logo_upper_container" ng_class="ng_div_logo_upper_container"></div>
<div class="nav_container">
<div class = "div_home" ng-class="ng_div_home">
<div class = "div_logo" ng-class="ng_div_logo" ng-click="ng_ISHOME=true;f_scale();">
<img class = "img_logo" src="https://avatars1.githubusercontent.com/u/579414?s=200&v=4" >
</div>
</div>
<div class = "nav_items">
<p ng-click="ng_ISHOME=false;f_scale();">Two</p>
</div>
<div class = "nav_items">
<p ng-click="ng_ISHOME=false;f_scale();">Three</p>
</div>
<div class = "nav_items">
<p ng-click="ng_ISHOME=false;f_scale();">Four</p>
</div>
</div> <!-- end nav_container -->
</div> <!-- end ctrl -->
</div> <!-- end app -->
asdf
回答1:
The animation is "jittery" because you are animating too many properties at once and they affect more than Paint and Composite layers.
If you find the above statement vague, please refer to these two articles:
- Rendering Performance from Google
- High Performance Animations.
The generally accepted solution for this type of animations is to have one element in DOM for each of the two animation states. They should both be positioned (any position
value other than static
will do). You'll use transform
to animate the starting state element towards the position and size of the target state element. By getting .getBoundingClientRect() on each, you can determine the required transforms needed to make the exact transition).
By far, the biggest advantage of this method is that the element being animated remains at the same position in document flow and, by not being resized or moved, it doesn't trigger reflow on subsequent DOM elements or parents. Only its rendered projection is moved.
Once the animation ends, you toggle both elements's visibility
and remove the transform
s from the one you just animated (now hidden - you want to set animation-duration:0s;
for this change), in order to reset the rendered projection back to its normal place in DOM.
来源:https://stackoverflow.com/questions/53126745/css-transition-item-in-and-out-of-flexbox-smooth-animation