Skip to content

Commit d14311f

Browse files
fix(segment-view): scroll to correct content when height is not set (#30547)
Issue number: resolves #30543 --------- ## What is the current behavior? On desktop Safari and Android the segment view is not switching to the right segment content when the height is dynamically set or read in as 0. This can be reproduced in the following StackBlitz on Android: https://6dhropnr-aheyyprl.stackblitz.io/ ## What is the new behavior? - Sets `min-height` to `1px` on `ion-segment-content` so that it continues to work with a dynamically set height - Adds an e2e test for Safari to verify the correct content is displayed when it contains a dynamically loaded image ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information Dev build: `8.6.2-dev.11752524287.1d61cd78` [Preview](https://ionic-framework-git-fw-6586-ionic1.vercel.app/src/components/segment-view/test/dynamic-height) --------- Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
1 parent 68ad860 commit d14311f

File tree

3 files changed

+166
-0
lines changed

3 files changed

+166
-0
lines changed

core/src/components/segment-content/segment-content.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99

1010
width: 100%;
1111

12+
// Workaround for a Safari/WebKit bug where flexbox children with dynamic
13+
// height (e.g., height: fit-content) are not included in the scrollable area
14+
// when using horizontal scrolling. This is needed to make the segment view
15+
// scroll to the correct content.
16+
min-height: 1px;
17+
1218
overflow-y: scroll;
1319

1420
/* Hide scrollbar in Firefox */
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<!DOCTYPE html>
2+
<html lang="en" dir="ltr">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Segment View - Dynamic Height</title>
6+
<meta
7+
name="viewport"
8+
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
9+
/>
10+
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
11+
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
12+
<script src="../../../../../scripts/testing/scripts.js"></script>
13+
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
14+
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
15+
16+
<style>
17+
ion-segment-content {
18+
display: flex;
19+
align-items: center;
20+
justify-content: center;
21+
height: fit-content;
22+
}
23+
24+
ion-segment-content:nth-of-type(1) {
25+
background: lightpink;
26+
}
27+
ion-segment-content:nth-of-type(2) {
28+
background: lightblue;
29+
}
30+
ion-segment-content:nth-of-type(3) {
31+
background: lightgreen;
32+
}
33+
</style>
34+
</head>
35+
36+
<body>
37+
<ion-app>
38+
<ion-header>
39+
<ion-toolbar>
40+
<ion-title>Segment View - Dynamic Height</ion-title>
41+
</ion-toolbar>
42+
</ion-header>
43+
44+
<ion-content>
45+
<ion-segment>
46+
<ion-segment-button value="first" content-id="first">
47+
<ion-label>First</ion-label>
48+
</ion-segment-button>
49+
<ion-segment-button value="second" content-id="second">
50+
<ion-label>Second</ion-label>
51+
</ion-segment-button>
52+
<ion-segment-button value="third" content-id="third">
53+
<ion-label>Third</ion-label>
54+
</ion-segment-button>
55+
</ion-segment>
56+
<ion-segment-view>
57+
<ion-segment-content id="first">
58+
Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora
59+
quaeritis. Summus brains sit, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris.
60+
Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus comedat
61+
cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The voodoo
62+
sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum defunctis
63+
go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv
64+
</ion-segment-content>
65+
<ion-segment-content id="second">
66+
<ion-input value="" label="Email"></ion-input>
67+
</ion-segment-content>
68+
<ion-segment-content id="third">
69+
<ion-img class="img-part" src="https://picsum.photos/200/300"></ion-img>
70+
</ion-segment-content>
71+
</ion-segment-view>
72+
</ion-content>
73+
</ion-app>
74+
</body>
75+
</html>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { expect } from '@playwright/test';
2+
import { configs, test } from '@utils/test/playwright';
3+
4+
/**
5+
* This behavior does not vary across modes/directions
6+
*/
7+
configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
8+
test.describe(title('segment-view: dynamic height'), () => {
9+
test('should show the third content when clicking the third button', async ({ page, skip }) => {
10+
// Skip this test on Chrome and Firefox
11+
skip.browser('firefox', 'Original issue only happens on Safari.');
12+
skip.browser('chromium', 'Original issue only happens on Safari.');
13+
14+
await page.setContent(
15+
`
16+
<style>
17+
ion-segment-content {
18+
display: flex;
19+
align-items: center;
20+
justify-content: center;
21+
height: fit-content;
22+
}
23+
</style>
24+
25+
<ion-segment>
26+
<ion-segment-button value="first" content-id="first">
27+
<ion-label>First</ion-label>
28+
</ion-segment-button>
29+
<ion-segment-button value="second" content-id="second">
30+
<ion-label>Second</ion-label>
31+
</ion-segment-button>
32+
<ion-segment-button value="third" content-id="third">
33+
<ion-label>Third</ion-label>
34+
</ion-segment-button>
35+
</ion-segment>
36+
<ion-segment-view>
37+
<ion-segment-content id="first">
38+
Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora
39+
quaeritis. Summus brains sit, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum
40+
mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil vultus
41+
comedat cerebella viventium. Qui animated corpse, cricket bat max brucks terribilem incessu zomby. The
42+
voodoo sacerdos flesh eater, suscitat mortuos comedere carnem virus. Zonbi tattered for solum oculi eorum
43+
defunctis go lum cerebro. Nescio brains an Undead zombies. Sicut malus putrid voodoo horror. Nigh tofth eliv
44+
</ion-segment-content>
45+
<ion-segment-content id="second">
46+
<ion-input value="" label="Email"></ion-input>
47+
</ion-segment-content>
48+
<ion-segment-content id="third">
49+
<ion-img class="img-part" src="https://picsum.photos/200/300"></ion-img>
50+
</ion-segment-content>
51+
</ion-segment-view>
52+
`,
53+
config
54+
);
55+
56+
// Click the third button
57+
await page.locator('ion-segment-button[value="third"]').click();
58+
59+
// Wait for the content to be scrolled
60+
await page.waitForChanges();
61+
62+
// Wait for the image to load and be visible
63+
const imgLocator = page.locator('ion-segment-content#third ion-img');
64+
await imgLocator.waitFor({ state: 'visible', timeout: 10000 });
65+
66+
// Wait for any layout adjustments
67+
await page.waitForChanges();
68+
69+
// Check that the third content is visible
70+
const segmentView = page.locator('ion-segment-view');
71+
const thirdContent = page.locator('ion-segment-content#third');
72+
73+
const viewBox = await segmentView.boundingBox();
74+
const contentBox = await thirdContent.boundingBox();
75+
76+
if (!viewBox || !contentBox) throw new Error('Bounding box not found');
77+
78+
// Allow a small tolerance to account for subpixel rendering,
79+
// scrollbars, or layout rounding differences
80+
const tolerance = 10;
81+
expect(contentBox.x).toBeGreaterThanOrEqual(viewBox.x);
82+
expect(contentBox.x + contentBox.width).toBeLessThanOrEqual(viewBox.x + viewBox.width + tolerance);
83+
});
84+
});
85+
});

0 commit comments

Comments
 (0)