Skip to content

Commit 674615e

Browse files
committed
fix: further animation transition improvements
1 parent 960fe30 commit 674615e

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-2
lines changed

.changeset/slow-beds-shave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: further animation transition improvements

packages/svelte/src/internal/client/each.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,7 @@ export function destroy_each_item_block(
735735
controlled = false
736736
) {
737737
const transitions = block.s;
738+
const dom = block.d;
738739

739740
if (apply_transitions && transitions !== null) {
740741
// We might have pending key transitions, if so remove them first
@@ -750,10 +751,13 @@ export function destroy_each_item_block(
750751
if (transition_block !== null) {
751752
transition_block.push(block);
752753
}
754+
if (dom !== null) {
755+
// @ts-ignore
756+
dom.__animate = false;
757+
}
753758
return;
754759
}
755760
}
756-
const dom = block.d;
757761
if (!controlled && dom !== null) {
758762
remove(dom);
759763
}

packages/svelte/src/internal/client/transitions.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,8 @@ function create_transition(dom, init, direction, effect) {
369369
},
370370
// out
371371
o() {
372+
// @ts-ignore
373+
const has_keyed_transition = dom.__animate === true;
372374
const needs_reverse = direction === 'both' && curr_direction !== 'out';
373375
curr_direction = 'out';
374376
if (animation === null || cancelled) {
@@ -385,6 +387,29 @@ function create_transition(dom, init, direction, effect) {
385387
/** @type {Animation | TickAnimation} */ (animation).play();
386388
}
387389
}
390+
// If we're outroing an element that has an animation, then we need to fix
391+
// its position to ensure it behaves nicely without causing layout shift.
392+
if (has_keyed_transition) {
393+
const style = getComputedStyle(dom);
394+
const position = style.position;
395+
396+
if (position !== 'absolute' && position !== 'fixed') {
397+
const { width, height } = style;
398+
const a = dom.getBoundingClientRect();
399+
dom.style.position = 'absolute';
400+
401+
dom.style.width = width;
402+
dom.style.height = height;
403+
const b = dom.getBoundingClientRect();
404+
if (a.left !== b.left || a.top !== b.top) {
405+
const style = getComputedStyle(dom);
406+
const transform = style.transform === 'none' ? '' : style.transform;
407+
dom.style.transform = `${transform} translate(${a.left - b.left}px, ${
408+
a.top - b.top
409+
}px)`;
410+
}
411+
}
412+
}
388413
},
389414
// cancel
390415
c() {
@@ -432,10 +457,16 @@ function is_transition_block(block) {
432457
export function bind_transition(dom, get_transition_fn, props_fn, direction, global) {
433458
const transition_effect = /** @type {import('./types.js').EffectSignal} */ (current_effect);
434459
const block = current_block;
460+
const is_keyed_transition = direction === 'key';
435461

436462
let can_show_intro_on_mount = true;
437463
let can_apply_lazy_transitions = false;
438464

465+
if (is_keyed_transition) {
466+
// @ts-ignore
467+
dom.__animate = true;
468+
}
469+
439470
/** @type {import('./types.js').Block | null} */
440471
let transition_block = block;
441472
while (transition_block !== null) {
@@ -479,7 +510,7 @@ export function bind_transition(dom, get_transition_fn, props_fn, direction, glo
479510
const init = (from) =>
480511
untrack(() => {
481512
const props = props_fn === null ? {} : props_fn();
482-
return direction === 'key'
513+
return is_keyed_transition
483514
? /** @type {import('./types.js').AnimateFn<any>} */ (transition_fn)(
484515
dom,
485516
{ from: /** @type {DOMRect} */ (from), to: dom.getBoundingClientRect() },

0 commit comments

Comments
 (0)