国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Table of Contents
Generate keyframes using JavaScript
Step 1: Calculate the start and end states
Step 2: Generate keyframes
Step 3: Enable CSS animation
Build expandable parts
Performance check
Final consideration
Home Web Front-end CSS Tutorial Performant Expandable Animations: Building Keyframes on the Fly

Performant Expandable Animations: Building Keyframes on the Fly

Apr 08, 2025 am 10:51 AM

Performant Expandable Animations: Building Keyframes on the Fly

CSS animation technology is becoming increasingly mature, providing developers with more powerful tools. CSS animation in particular has become the basis for solving most animation use cases. However, some animations require more fine-grained processing.

As we all know, animations should be run in the synthesis layer (I will not repeat it here, if you are interested, please refer to the relevant literature). This means that the animation's transformation or opacity attributes do not touch the publishing layout or draw layer. Attributes such as animation height and width will trigger these layers, forcing the browser to recalculate the style, which needs to be avoided.

In addition, even if you want to implement real 60 FPS animations, you may also need to use JavaScript, such as using FLIP technology to achieve smoother animations!

However, the problem with using transform properties for expandable animation is that the scaling function is not exactly the same as the animation height/width properties. It will have a skew effect on the content, as all elements will be stretched (scaled up) or squeezed (scaled down).

So my common solution (probably still, the reason will be explained in detail later) is Method 3 in Brandon Smith article. This approach still makes a transition to height, but uses JavaScript to calculate the content size and forces the transition using requestAnimationFrame. In OutSystems, we actually use this method to build an animation for OutSystems UI accordion mode.

Generate keyframes using JavaScript

Recently, I stumbled upon another great article by Paul Lewis, detailing a new solution for unfolding and folding animations, which prompted me to write this article and promote this technology.

In his words, the main idea is to generate dynamic keyframes and gradually...

[…] From 0 to 100, and calculate the scaling value required for the element and its content. These values ??can then be simplified to a string and injected into the page as a style element.

There are three main steps to achieve this.

Step 1: Calculate the start and end states

We need to calculate the correct scaling value for both states. This means we use getBoundingClientRect() on the element that will be proxyed as the starting state and divide it by the value of the end state. It should look like:

 function calculateStartScale () {
  const start= startElement.getBoundingClientRect();
  const end= endElement.getBoundingClientRect();
  return {
    x: start.width / end.width,
    y: start.height / end.height
  };
}

Step 2: Generate keyframes

Now we need to run a for loop using the required number of frames as length. (To ensure smooth animation, it should not be less than 60 frames.) Then, in each iteration, we use the easing function to calculate the correct easing value:

 function ease (v, pow=4) {
  return 1 - Math.pow(1 - v, pow);
}

let easedStep = ease(i/frame);

Using this value, we will use the following mathematical formula to get the scaling of the element in the current step:

 const xScale = x (1 - x) * easedStep;
const yScale = y (1 - y) * easedStep;

Then we add the steps to the animation string:

 animation = `${step}% {
  transform: scale(${xScale}, ${yScale});
}`;

To avoid the content being stretched/tilted we should animate it inversely, using the reverse value:

 const invXScale = 1 / xScale;
const invYScale = 1 / yScale;

inverseAnimation = `${step}% {
  transform: scale(${invXScale}, ${invYScale});
}`;

Finally, we can return the completed animations, or inject them directly into the newly created style tag.

Step 3: Enable CSS animation

In terms of CSS, we need to enable animation on the correct elements:

 .element--expanded {
  animation-name: animation;
  animation-duration: 300ms;
  animation-timing-function: step-end;
}

.element-contents--expanded {
  animation-name: inverseAnimation;
  animation-duration: 300ms;
  animation-timing-function: step-end;
}

You can view the menu examples in the Paul Lewis article (contributed by Chris) on Codepen.

Build expandable parts

Having mastered these basic concepts, I wanted to check if this technique can be applied to different use cases, such as expandable parts.

In this case, we only need to animate the height, especially in the function that calculates the scaling. We get the Y value from the section title as the collapsed state and get the entire section to represent the expanded state:

 _calculateScales () {
      var collapsed = this._sectionItemTitle.getBoundingClientRect();
      var expanded = this._section.getBoundingClientRect();

      // create css variable with collapsed height, to apply on the wrapper
      this._sectionWrapper.style.setProperty('--title-height', collapsed.height 'px');

      this._collapsed = {
        y: collapsed.height / expanded.height
      }
    }

Since we want the expanded part to have absolute positioning (to avoid it taking up space in the collapsed state), we set a CSS variable for it using the collapsed height and apply it to the wrapper. This will be the only element with relative positioning.

Next is the function to create the keyframe: _createEaseAnimations() . This is not much different from what is explained above. For this use case, we actually need to create four animations:

  1. Expand the animation of the wrapper
  2. Reverse expansion animation of content
  3. Animation of fold wrapper
  4. Reverse folding animation of content

We follow the same approach as before, running a for loop of 60 length (to get a smooth 60 FPS animation) and creating the keyframe percentage based on the easing step. Then we push it to the final animation string:

 outerAnimation.push(`
  ${percentage}% {
    transform: scaleY(${yScale});
  }`);

innerAnimation.push(`
  ${percentage}% {
    transform: scaleY(${invScaleY});
  }`);

We first create a style tag to save the finished animation. Since this is built as a constructor, to be able to easily add multiple patterns, we want all of these generated animations to be in the same stylesheet. So first, we verify that the element exists. If it does not exist, we create it and add a meaningful class name. Otherwise, you end up getting a stylesheet for each expandable section, which is not ideal.

 var sectionEase = document.querySelector('.section-animations');
 if (!sectionEase) {
  sectionEase = document.createElement('style');
  sectionEase.classList.add('section-animations');
 }

Speaking of this, you might already be thinking, "Well, if we have multiple expandable parts, do they still use the animation of the same name, and their contents may have the wrong value?"

You are absolutely right! So to prevent this, we also generate dynamic animation names. Very cool, right?

When doing querySelectorAll('.section') query to add a unique element to the name, we use the index passed to the constructor:

 var sectionExpandAnimationName = "sectionExpandAnimation" index;
var sectionExpandContentsAnimationName = "sectionExpandContentsAnimation" index;

We then use this name to set the CSS variable in the currently expandable section. Since this variable is only within this range, we just need to set the animation as a new variable in CSS and each pattern will get its respective animation-name value.

 .section.is--expanded {
  animation-name: var(--sectionExpandAnimation);
}

.is--expanded .section-item {
  animation-name: var(--sectionExpandContentsAnimation);
}

.section.is--collapsed {
  animation-name: var(--sectionCollapseAnimation);
}

.is--collapsed .section-item {
  animation-name: var(--sectionCollapseContentsAnimation);
}

The rest of the script is related to adding event listeners, functions that toggle collapse/expand states, and some helper function improvements.

About HTML and CSS: Additional work is required to make the expandable function work properly. We need an extra wrapper as a relative element that does not perform animation. Expandable child elements have absolute positions so they do not take up space when collapsed.

Remember that since we need to do reverse animation, we make it scale full size to avoid tilting effects in the content.

 .section-item-wrapper {
  min-height: var(--title-height);
  position: relative;
}

.section {
  animation-duration: 300ms;
  animation-timing-function: step-end;
  contains: content;
  left: 0;
  position: absolute;
  top: 0;
  transform-origin: top left;
  will-change: transform;
}

.section-item {
  animation-duration: 300ms;
  animation-timing-function: step-end;
  contains: content;
  transform-origin: top left;
  will-change: transform;  
}

I want to emphasize the importance of animation-timing-function property. It should be set to linear or step-end to avoid easing between each keyframe.

The will-change property—as you probably know—will enable GPU acceleration for transform animations for a smoother experience. Using the contains property, with a value of contents , will help the browser process elements independently of the rest of the DOM tree, limiting the area where it recalculates the layout, style, draw, and size attributes.

We use visibility and opacity to hide content and prevent screen readers from accessing it when collapsed.

 .section-item-content {
  opacity: 1;
  transition: opacity 500ms ease;
}

.is--collapsed .section-item-content {
  opacity: 0;
  visibility: hidden;
}

Finally, we have the part that can be expanded! Here is the complete code and demonstration for you to view:

Performance check

Whenever we deal with animations, performance should be kept in mind. So let's use developer tools to check if all this work is worth it in terms of performance. Using the Performance tab (I'm using Chrome DevTools), we can analyze FPS and CPU usage during animation.

The result is very good!

Checking the value in more detail using the FPS measurement tool, we can see that it always reaches the mark of 60 FPS, even for abuse.

Final consideration

So, what is the final conclusion? Does this replace all other methods? Is this the "Holy Grail" solution?

In my opinion, no.

But...this doesn't matter! It's just another solution on the list. And, like any other approach, it should be analyzed whether it is the best way to target a use case.

This technology has its advantages. As Paul Lewis said, this does require a lot of work to prepare. However, on the other hand, we only need to do it once when the page is loading. During the interaction, we simply switch classes (in some cases, for accessibility, and also switch properties).

However, this puts some limitations on the element's UI. As you can see in expandable partial elements, reverse scaling makes it more reliable for absolute and off-canvas elements, such as floating actions or menus. Since it uses overflow: hidden , it is difficult to style the border.

Nevertheless, I think this approach has great potential. Please tell me what you think!

The above is the detailed content of Performant Expandable Animations: Building Keyframes on the Fly. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What is 'render-blocking CSS'? What is 'render-blocking CSS'? Jun 24, 2025 am 12:42 AM

CSS blocks page rendering because browsers view inline and external CSS as key resources by default, especially with imported stylesheets, header large amounts of inline CSS, and unoptimized media query styles. 1. Extract critical CSS and embed it into HTML; 2. Delay loading non-critical CSS through JavaScript; 3. Use media attributes to optimize loading such as print styles; 4. Compress and merge CSS to reduce requests. It is recommended to use tools to extract key CSS, combine rel="preload" asynchronous loading, and use media delayed loading reasonably to avoid excessive splitting and complex script control.

External vs. Internal CSS: What's the Best Approach? External vs. Internal CSS: What's the Best Approach? Jun 20, 2025 am 12:45 AM

ThebestapproachforCSSdependsontheproject'sspecificneeds.Forlargerprojects,externalCSSisbetterduetomaintainabilityandreusability;forsmallerprojectsorsingle-pageapplications,internalCSSmightbemoresuitable.It'scrucialtobalanceprojectsize,performanceneed

Does my CSS must be on lower case? Does my CSS must be on lower case? Jun 19, 2025 am 12:29 AM

No,CSSdoesnothavetobeinlowercase.However,usinglowercaseisrecommendedfor:1)Consistencyandreadability,2)Avoidingerrorsinrelatedtechnologies,3)Potentialperformancebenefits,and4)Improvedcollaborationwithinteams.

CSS Case Sensitivity: Understanding What Matters CSS Case Sensitivity: Understanding What Matters Jun 20, 2025 am 12:09 AM

CSSismostlycase-insensitive,butURLsandfontfamilynamesarecase-sensitive.1)Propertiesandvalueslikecolor:red;arenotcase-sensitive.2)URLsmustmatchtheserver'scase,e.g.,/images/Logo.png.3)Fontfamilynameslike'OpenSans'mustbeexact.

What is Autoprefixer and how does it work? What is Autoprefixer and how does it work? Jul 02, 2025 am 01:15 AM

Autoprefixer is a tool that automatically adds vendor prefixes to CSS attributes based on the target browser scope. 1. It solves the problem of manually maintaining prefixes with errors; 2. Work through the PostCSS plug-in form, parse CSS, analyze attributes that need to be prefixed, and generate code according to configuration; 3. The usage steps include installing plug-ins, setting browserslist, and enabling them in the build process; 4. Notes include not manually adding prefixes, keeping configuration updates, prefixes not all attributes, and it is recommended to use them with the preprocessor.

What are CSS counters? What are CSS counters? Jun 19, 2025 am 12:34 AM

CSScounterscanautomaticallynumbersectionsandlists.1)Usecounter-resettoinitialize,counter-incrementtoincrease,andcounter()orcounters()todisplayvalues.2)CombinewithJavaScriptfordynamiccontenttoensureaccurateupdates.

CSS: When Does Case Matter (and When Doesn't)? CSS: When Does Case Matter (and When Doesn't)? Jun 19, 2025 am 12:27 AM

In CSS, selector and attribute names are case-sensitive, while values, named colors, URLs, and custom attributes are case-sensitive. 1. The selector and attribute names are case-insensitive, such as background-color and background-Color are the same. 2. The hexadecimal color in the value is case-sensitive, but the named color is case-sensitive, such as red and Red is invalid. 3. URLs are case sensitive and may cause file loading problems. 4. Custom properties (variables) are case sensitive, and you need to pay attention to the consistency of case when using them.

What is the conic-gradient() function? What is the conic-gradient() function? Jul 01, 2025 am 01:16 AM

Theconic-gradient()functioninCSScreatescirculargradientsthatrotatecolorstopsaroundacentralpoint.1.Itisidealforpiecharts,progressindicators,colorwheels,anddecorativebackgrounds.2.Itworksbydefiningcolorstopsatspecificangles,optionallystartingfromadefin

See all articles