Skip to content

Commit eb41b55

Browse files
fix(fab-button): position is correct with custom sizes (#28195)
Issue number: resolves #22564 --------- <!-- 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. --> Changing the size of the FAB button causes it to be positioned incorrectly. This was happening because we set position values based on the assumption that the default FAB button would always be 56px x 56px. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - FAB and FAB List positioning is now computed based on intrinsic size ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> Dev build: `7.4.1-dev.11695395641.14897417` --------- Co-authored-by: ionitron <[email protected]>
1 parent 355d95d commit eb41b55

13 files changed

+360
-13
lines changed

core/src/components/fab-button/fab-button.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@
199199
// --------------------------------------------------
200200

201201
:host(.fab-button-small) {
202-
@include margin(($fab-size - $fab-small-size) * 0.5);
202+
@include margin($fab-button-small-margin);
203203

204204
width: #{$fab-small-size};
205205
height: #{$fab-small-size};

core/src/components/fab-button/fab-button.vars.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ $fab-small-size: 40px !default;
1111

1212
/// @prop - Border radius of the FAB button
1313
$fab-border-radius: 50% !default;
14+
15+
/// @prop - Margin applied to the small FAB button
16+
$fab-button-small-margin: 8px !default;

core/src/components/fab-list/fab-list.scss

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// --------------------------------------------------
55

66
:host {
7-
@include margin($fab-size + $fab-list-margin, 0);
7+
@include margin(calc(100% + #{$fab-list-margin}), 0);
88

99
display: none;
1010
position: absolute;
@@ -13,8 +13,15 @@
1313
flex-direction: column;
1414
align-items: center;
1515

16-
min-width: $fab-size;
17-
min-height: $fab-size;
16+
/**
17+
* The list should be centered relative to the parent
18+
* FAB button. We set minimum dimensions so the
19+
* FAB list can be centered relative to the small FAB button.
20+
* However, the small FAB button adds start/end margin, so we need
21+
* to account for that in the FAB list dimensions.
22+
*/
23+
min-width: $fab-small-size + ($fab-button-small-margin * 2);
24+
min-height: $fab-small-size + ($fab-button-small-margin * 2);
1825
}
1926

2027
:host(.fab-list-active) {
@@ -59,14 +66,14 @@
5966
}
6067

6168
:host(.fab-list-side-start) {
62-
@include margin(0, $fab-size + $fab-list-margin);
69+
@include margin(0, calc(100% + #{$fab-list-margin}));
6370
@include position-horizontal(null, 0);
6471

6572
flex-direction: row-reverse;
6673
}
6774

6875
:host(.fab-list-side-end) {
69-
@include margin(0, $fab-size + $fab-list-margin);
76+
@include margin(0, calc(100% + #{$fab-list-margin}));
7077
@include position(null, null, null, 0);
7178

7279
flex-direction: row;

core/src/components/fab/fab.scss

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
@import "./fab.vars";
2+
@import "../fab-list/fab-list.vars";
23

34
// Floating Action Button Container
45
// --------------------------------------------------
56

67
:host {
78
position: absolute;
89

10+
width: fit-content;
11+
height: fit-content;
12+
913
z-index: $z-index-fixed-content;
1014
}
1115

@@ -14,8 +18,8 @@
1418
// --------------------------------------------------
1519

1620
:host(.fab-horizontal-center) {
17-
@include position(null, null, null, 50%);
18-
@include margin-horizontal(-$fab-size * 0.5, null);
21+
@include position(null, 0px, null, 0px);
22+
@include margin(null, auto);
1923
}
2024

2125
:host(.fab-horizontal-start) {
@@ -38,22 +42,93 @@
3842
top: $fab-content-margin;
3943
}
4044

45+
/**
46+
* Reset the top value since edge
47+
* styles use margin-top.
48+
*/
4149
:host(.fab-vertical-top.fab-edge) {
42-
top: -$fab-size * 0.5;
50+
top: 0;
51+
}
52+
53+
/**
54+
* We need to adjust the parent FAB button up by half
55+
* its height so that half of it sits on the header. As a result,
56+
* we target the slotted ion-fab-button instead of targeting the host.
57+
*/
58+
:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-button) {
59+
margin-top: -50%;
60+
}
61+
62+
/**
63+
* The small FAB button adds top and bottom margin. We need to account for
64+
* that margin when we adjust the FAB button for edge styles since we
65+
* are overriding the margin-top value below.
66+
*/
67+
:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-button.fab-button-small) {
68+
margin-top: calc((-100% + $fab-button-small-margin * 2) / 2);
69+
}
70+
71+
/**
72+
* Since we are adjusting the FAB button we also need
73+
* to adjust the sibling ion-fab-list otherwise there will be
74+
* a gap between the parent FAB button and the associated list.
75+
*/
76+
:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-list.fab-list-side-start),
77+
:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-list.fab-list-side-end) {
78+
@include margin(-50%, null, null, null);
4379
}
4480

81+
:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-list.fab-list-side-top),
82+
:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-list.fab-list-side-bottom) {
83+
@include margin(calc(50% + #{$fab-list-margin}) null, null, null);
84+
}
4585

4686
:host(.fab-vertical-bottom) {
4787
bottom: $fab-content-margin;
4888
}
4989

90+
/**
91+
* Reset the bottom value since edge
92+
* styles use margin-bottom.
93+
*/
5094
:host(.fab-vertical-bottom.fab-edge) {
51-
bottom: -$fab-size * 0.5;
95+
bottom: 0;
5296
}
5397

98+
/**
99+
* We need to adjust the parent FAB button down by half
100+
* its height so that half of it sits on the footer. As a result,
101+
* we target the slotted ion-fab-button instead of targeting the host.
102+
*/
103+
:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-button) {
104+
margin-bottom: -50%;
105+
}
54106

55-
:host(.fab-vertical-center) {
56-
@include margin(-$fab-size * 0.5, null, null, null);
107+
/**
108+
* The small FAB button adds top and bottom margin. We need to account for
109+
* that margin when we adjust the FAB button for edge styles since we
110+
* are overriding the margin-bottom value below.
111+
*/
112+
:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-button.fab-button-small) {
113+
margin-bottom: calc((-100% + $fab-button-small-margin * 2) / 2);
114+
}
115+
116+
/**
117+
* Since we are adjusting the FAB button we also need
118+
* to adjust the sibling ion-fab-list otherwise there will be
119+
* a gap between the parent FAB button and the associated list.
120+
*/
121+
:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-list.fab-list-side-start),
122+
:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-list.fab-list-side-end) {
123+
@include margin(null, null, -50%, null);
124+
}
125+
126+
:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-list.fab-list-side-top),
127+
:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-list.fab-list-side-bottom) {
128+
@include margin(null, null, calc(50% + #{$fab-list-margin}) null);
129+
}
57130

58-
top: 50%;
131+
:host(.fab-vertical-center) {
132+
@include position(0px, null, 0px, null);
133+
@include margin(auto, null);
59134
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { expect } from '@playwright/test';
2+
import { configs, test, Viewports } from '@utils/test/playwright';
3+
4+
/**
5+
* This behavior does not vary across modes
6+
*/
7+
configs({ modes: ['ios'] }).forEach(({ title, config, screenshot }) => {
8+
test.describe(title('fab: custom size'), () => {
9+
test('should position fabs correctly with custom sizes', async ({ page }) => {
10+
await page.goto(`/src/components/fab/test/custom-size`, config);
11+
12+
await page.setViewportSize(Viewports.tablet.landscape);
13+
14+
await expect(page).toHaveScreenshot(screenshot(`fab-custom-size`));
15+
});
16+
});
17+
});
75.1 KB
Loading
116 KB
Loading
67.6 KB
Loading
75.1 KB
Loading
116 KB
Loading

0 commit comments

Comments
 (0)