Search code examples
angularinternet-exploreranimationangular-animations

Why is an *ngFor loop breaking my sidebar animation in Internet Explorer?


I have an animation which works well in Chrome but not in IE. I expect to slide a panel in from outside the browser window into view and then once the exit button or <div> which covers the rest of the page is clicked, the panel will animate off the screen and out of view. However, the actual result is that the whole page is transformed and not the specific element.

View demonstrations below:

Chrome (works fine; animation is smooth): Chrome Demonstration

IE (bug; entire page is moved): IE Demonstration

EDIT

So I have found the reason why this is happening and it is because of an *ngFor when rendering HTML inside of the container. If I remove the ngFor completely and all other property bindings, the animation runs as expected (as demonstrated in the Chrome GIF).

I didn't add this code to the question initially because I wouldn't have thought that some *ngFor logic would break the CSS.

So my question is, why is the *ngFor breaking the animation and how do I fix it?

Code:

side-bar-component.ts:

animations: [
    trigger('animateInOutTrigger', [
      transition(':enter', [
        style({ transform: 'translateX(0%)' }),
        animate('0.3s', style({ transform: 'translateX(-100%)' }))
      ]),
      transition(':leave', [
        animate('0.3s', style({ transform: 'translateX(0%)' }))
      ])
    ]),
    trigger('fadeScrim', [
      transition(':enter', [
        style({ transform: 'opacity: 0' }),
        animate('0.3s', style({ opacity: '1' }))
      ]),
      transition(':leave', [
        animate('0.3s', style({ opacity: '0' }))
      ]),
    ]),

side-bar-component.html:

<div id="btn-scrim" *ngIf="windowWidth >= 768 && open" class="scrim" (click)="onCloseSideBar()" @fadeScrim></div>
<div *ngIf="windowWidth >= 768 && open" class="sidebar-wrapper">
  <div @animateInOutTrigger class="container">
    <div class="header">
      <span class="text">Claim Details</span>
      <span id="btn-close-sidebar-desktop" (click)="onCloseSideBar()">X</span>
    </div>
    <div class="claims claims-padding">
        <hr-claim-detail [id]="'claim-scroller-' + element.claim_id" *ngFor="let element of group.data" [element]="element (update)="updateAndClose()" [windowWidth]="windowWidth" [token]="token [logConfig]="logConfig">
        </hr-claim-detail>
  </div>
</div>

side-bar-component.scss:

.sidebar-wrapper {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  right: 0;
  transform: translateX(100%);
  z-index: 2;
}

.container {
  height: 100%;
  position: absolute;
  top: 0;
  box-sizing: border-box;
  background-color: white;
  box-shadow: 0 8px 10px -5px rgba(0, 0, 0, 0.2), 0 6px 30px 5px rgba(0, 0, 0, 0.12), 0 16px 24px 2px rgba(0, 0, 0, 0.14);
  z-index: 2;
  display: flex;
  flex-direction: column;
  transform: translateX(-100%);
}

.scrim {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, .32);
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
}

.header {
  height: 56px;
  background-color: #333333;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  color: white;
  position: relative;
  z-index: 2;
}

.text {
  font-size: 16px;
  font-weight: 500;
}

.claims {
  height: 100%;
  overflow-y: scroll;
  -ms-overflow-style: none;
  box-sizing: border-box;
  flex: 1;
}

.claims-padding {
  padding-bottom: 25vh;
}

STACKBLITZ RECREATION: https://stackblitz.com/edit/angular-ven7eu

I've tried:

  • Using state to control the transition instead of using :enter and :leave
  • Performing the same functionality without the Angular animations library and purely with CSS conditional classes

Other information:

  • Angular Core 8.0.0
  • Angular Animations 8.0.0 (I've tried downgrading to older versions and upgrading to latest minor and patch versions)

Solution

  • The problem was fixed by using fixed positioning and then programmatically setting the margin-top equal to getBoundingClientRect().top of the main content container.

    I still do not understand why using absolute positioning in this scenario won't work.