fix(modal): improve card modal background transition from portrait to landscape (#30551)

Issue number: resolves internal

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

Currently, if you have multiple card modals open in portrait view and
then transition to landscape, the background will not be transformed
properly and will not cover the entire screen as expected.


https://github.com/user-attachments/assets/bb2c7015-adb6-4c3b-8bc5-13360275fcf4


## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

Now, we're correctly targeting the right element and will transform it
as expected. This allows a more consistent UX for these transitions.



https://github.com/user-attachments/assets/fff72387-d78b-4df4-a234-d89b54f694c4



## Does this introduce a breaking change?

- [ ] Yes
- [X] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/docs/CONTRIBUTING.md#footer
for more information.
-->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

[Relevant (broken) screen (main
branch)](https://ionic-framework-git-main-ionic1.vercel.app/src/components/modal/test/card?ionic:mode=ios)

[Relevant (fixed) screen (this
branch)](https://ionic-framework-git-fix-modal-landscape-background-ionic1.vercel.app/src/components/modal/test/card?ionic:mode=ios)
This commit is contained in:
Shane
2025-07-15 12:00:31 -07:00
committed by GitHub
parent 3f730ab1d7
commit d37b9b8e46
2 changed files with 9 additions and 19 deletions

View File

@ -72,22 +72,22 @@ export const portraitToLandscapeTransition = (
// need to care about layering and modal-specific styles. // need to care about layering and modal-specific styles.
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE; const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const fromTransform = `translateY(-10px) scale(${toPresentingScale})`; const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
const toTransform = `translateY(-10px) scale(${toPresentingScale})`; const toTransform = `translateY(0px) scale(1)`;
presentingAnimation presentingAnimation
.addElement(presentingElRoot.querySelector('.modal-wrapper')!) .addElement(presentingEl)
.afterStyles({ .afterStyles({
transform: toTransform, transform: toTransform,
}) })
.fromTo('transform', fromTransform, toTransform) .fromTo('transform', fromTransform, toTransform)
.fromTo('filter', 'contrast(0.85)', 'contrast(0.85)'); // Keep same contrast for card .fromTo('filter', 'contrast(0.85)', 'contrast(1)');
const shadowAnimation = createAnimation() const shadowAnimation = createAnimation()
.addElement(presentingElRoot.querySelector('.modal-shadow')!) .addElement(presentingElRoot.querySelector('.modal-shadow')!)
.afterStyles({ .afterStyles({
transform: toTransform, transform: toTransform,
opacity: '0',
}) })
.fromTo('opacity', '0', '0') // Shadow stays hidden in landscape for card modals
.fromTo('transform', fromTransform, toTransform); .fromTo('transform', fromTransform, toTransform);
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]); baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
@ -148,17 +148,8 @@ export const landscapeToPortraitTransition = (
presentingAnimation presentingAnimation
.addElement(presentingEl) .addElement(presentingEl)
.beforeStyles({
transform: 'translateY(0px) scale(1)',
'transform-origin': 'top center',
overflow: 'hidden',
})
.afterStyles({ .afterStyles({
transform: toTransform, transform: toTransform,
'border-radius': '10px 10px 0 0',
filter: 'contrast(0.85)',
overflow: 'hidden',
'transform-origin': 'top center',
}) })
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black')) .beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
.keyframes([ .keyframes([
@ -173,22 +164,21 @@ export const landscapeToPortraitTransition = (
// to handle layering and modal-specific styles. // to handle layering and modal-specific styles.
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE; const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const fromTransform = `translateY(-10px) scale(${toPresentingScale})`; const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
const toTransform = `translateY(-10px) scale(${toPresentingScale})`; const toTransform = `translateY(0) scale(1)`;
presentingAnimation presentingAnimation
.addElement(presentingElRoot.querySelector('.modal-wrapper')!) .addElement(presentingEl)
.afterStyles({ .afterStyles({
transform: toTransform, transform: toTransform,
}) })
.fromTo('transform', fromTransform, toTransform) .fromTo('transform', fromTransform, toTransform);
.fromTo('filter', 'contrast(0.85)', 'contrast(0.85)'); // Keep same contrast for card
const shadowAnimation = createAnimation() const shadowAnimation = createAnimation()
.addElement(presentingElRoot.querySelector('.modal-shadow')!) .addElement(presentingElRoot.querySelector('.modal-shadow')!)
.afterStyles({ .afterStyles({
transform: toTransform, transform: toTransform,
opacity: '0',
}) })
.fromTo('opacity', '0', '0') // Shadow stays hidden
.fromTo('transform', fromTransform, toTransform); .fromTo('transform', fromTransform, toTransform);
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]); baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);

View File

@ -1122,7 +1122,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
wrapperEl.style.opacity = '1'; wrapperEl.style.opacity = '1';
} }
if (presentingElement) { if (presentingElement?.tagName === 'ION-MODAL') {
const isPortrait = window.innerWidth < 768; const isPortrait = window.innerWidth < 768;
if (isPortrait) { if (isPortrait) {