/
githubmirror
/
components
Обзор
Документация
Войти
/
githubmirror
/
components
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/material/button/fab.scss
257 строк
8 KB
Kristiyan Kostadinov
fix(material/button): match focus indicator shape to FAB (#33527)
15 июл 2026, 06:02
Не верифицирован
15 июл 2026, 06:02
d324696
Код
Авторство
О чём код?
@use './button-base'; @use '../core/tokens/token-utils'; @use '../core/style/private' as style-private; @use '../core/style/vendor-prefixes'; @use '../core/focus-indicators/private' as focus-indicators-private; @use './m3-fab'; $fallbacks: m3-fab.get-tokens(); $indicator-border-width: focus-indicators-private.$default-border-width; $border-width: var(--mat-focus-indicator-border-width, #{$indicator-border-width}); $indicator-offset: calc(#{$border-width} + 2px); .mat-mdc-fab-base { @include vendor-prefixes.user-select(none); position: relative; display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; width: 56px; height: 56px; padding: 0; border: none; fill: currentColor; text-decoration: none; cursor: pointer; -moz-appearance: none; -webkit-appearance: none; overflow: visible; transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1), opacity 15ms linear 30ms, transform 270ms 0ms cubic-bezier(0, 0, 0.2, 1); flex-shrink: 0; // Prevent the button from shrinking since it's always supposed to be a circle. // Due to the shape of the FAB, inheriting the shape looks off. Disable it explicitly. @include button-base.mat-private-button-interactive($focus-indicator-inherits-shape: false); @include style-private.private-animation-noop(); &::before { position: absolute; box-sizing: border-box; width: 100%; height: 100%; top: 0; left: 0; border: 1px solid transparent; border-radius: inherit; content: ''; pointer-events: none; } // MDC used to include this and it seems like a lot of apps depend on it. &[hidden] { display: none; } &::-moz-focus-inner { padding: 0; border: 0; } &:active, &:focus { outline: none; } &:hover { cursor: pointer; } & > svg { width: 100%; } // MDC expects the fab icon to contain this HTML content: // ```html // <span class="mdc-fab__icon material-icons">favorite</span> // ``` // However, Angular Material expects a `mat-icon` instead. The following // mixin will style the icons appropriately. // stylelint-disable-next-line selector-class-pattern .mat-icon, .material-icons { transition: transform 180ms 90ms cubic-bezier(0, 0, 0.2, 1); fill: currentColor; will-change: transform; } .mat-focus-indicator::before { margin: calc(#{$indicator-offset} * -1); border-radius: calc(#{token-utils.slot(fab-container-shape, $fallbacks)} + #{$indicator-offset}); } @include button-base.mat-private-button-disabled { // Necessary for interactive disabled buttons. &, &:focus { box-shadow: none; } } } .mat-mdc-fab { background-color: token-utils.slot(fab-container-color, $fallbacks); border-radius: token-utils.slot(fab-container-shape, $fallbacks); color: token-utils.slot(fab-foreground-color, $fallbacks, inherit); box-shadow: token-utils.slot(fab-container-elevation-shadow, $fallbacks); @media (hover: hover) { &:hover { box-shadow: token-utils.slot(fab-hover-container-elevation-shadow, $fallbacks); } } &:focus { box-shadow: token-utils.slot(fab-focus-container-elevation-shadow, $fallbacks); } &:active, &:focus:active { box-shadow: token-utils.slot(fab-pressed-container-elevation-shadow, $fallbacks); } @include button-base.mat-private-button-disabled { color: token-utils.slot(fab-disabled-state-foreground-color, $fallbacks); background-color: token-utils.slot(fab-disabled-state-container-color, $fallbacks); } @include button-base.mat-private-button-touch-target(true, fab-touch-target-size, fab-touch-target-display, $fallbacks); @include button-base.mat-private-button-ripple(fab-ripple-color, fab-state-layer-color, fab-disabled-state-layer-color, fab-hover-state-layer-opacity, fab-focus-state-layer-opacity, fab-pressed-state-layer-opacity, $fallbacks); } .mat-mdc-mini-fab { width: 40px; height: 40px; background-color: token-utils.slot(fab-small-container-color, $fallbacks); border-radius: token-utils.slot(fab-small-container-shape, $fallbacks); color: token-utils.slot(fab-small-foreground-color, $fallbacks, inherit); box-shadow: token-utils.slot(fab-small-container-elevation-shadow, $fallbacks); @media (hover: hover) { &:hover { box-shadow: token-utils.slot(fab-small-hover-container-elevation-shadow, $fallbacks); } } &:focus { box-shadow: token-utils.slot(fab-small-focus-container-elevation-shadow, $fallbacks); } &:active, &:focus:active { box-shadow: token-utils.slot(fab-small-pressed-container-elevation-shadow, $fallbacks); } .mat-focus-indicator::before { border-radius: calc(#{token-utils.slot(fab-small-container-shape, $fallbacks)} + #{$indicator-offset}); } @include button-base.mat-private-button-disabled { color: token-utils.slot(fab-small-disabled-state-foreground-color, $fallbacks); background-color: token-utils.slot(fab-small-disabled-state-container-color, $fallbacks); } @include button-base.mat-private-button-touch-target(true, fab-small-touch-target-size, fab-small-touch-target-display, $fallbacks); @include button-base.mat-private-button-ripple(fab-small-ripple-color, fab-small-state-layer-color, fab-small-disabled-state-layer-color, fab-small-hover-state-layer-opacity, fab-small-focus-state-layer-opacity, fab-small-pressed-state-layer-opacity, $fallbacks); } .mat-mdc-extended-fab { // Before tokens MDC included the font smoothing automatically, but with // tokens it doesn't. We add it since it can cause tiny differences in // screenshot tests and it generally looks better. @include vendor-prefixes.smooth-font(); padding-left: 20px; padding-right: 20px; width: auto; max-width: 100%; line-height: normal; box-shadow: token-utils.slot(fab-extended-container-elevation-shadow, $fallbacks); height: token-utils.slot(fab-extended-container-height, $fallbacks); border-radius: token-utils.slot(fab-extended-container-shape, $fallbacks); font-family: token-utils.slot(fab-extended-label-text-font, $fallbacks); font-size: token-utils.slot(fab-extended-label-text-size, $fallbacks); font-weight: token-utils.slot(fab-extended-label-text-weight, $fallbacks); letter-spacing: token-utils.slot(fab-extended-label-text-tracking, $fallbacks); @media (hover: hover) { &:hover { box-shadow: token-utils.slot(fab-extended-hover-container-elevation-shadow, $fallbacks); } } &:focus { box-shadow: token-utils.slot(fab-extended-focus-container-elevation-shadow, $fallbacks); } &:active, &:focus:active { box-shadow: token-utils.slot(fab-extended-pressed-container-elevation-shadow, $fallbacks); } @include button-base.mat-private-button-disabled { // Necessary for interactive disabled buttons. &, &:focus { box-shadow: none; } } // stylelint-disable selector-class-pattern // For Extended FAB with text label followed by icon. // We are checking for the a button class because white this is a FAB it // uses the same template as button. [dir='rtl'] & .mdc-button__label + .mat-icon, [dir='rtl'] & .mdc-button__label + .material-icons, > .mat-icon, > .material-icons { margin-left: -8px; margin-right: 12px; } .mdc-button__label + .mat-icon, .mdc-button__label + .material-icons, [dir='rtl'] & > .mat-icon, [dir='rtl'] & > .material-icons { margin-left: 12px; margin-right: -8px; } // stylelint-enable selector-class-pattern // All FABs are square except the extended ones so we // need to set the touch target back to full-width. .mat-mdc-button-touch-target { width: 100%; } } .mat-mdc-button-progress-indicator-container { position: absolute; inset-inline-start: 0; margin-block-start: 0; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; box-sizing: border-box; } .mat-mdc-button-progress-indicator-shown { mat-icon, [matButtonIcon], .mdc-button__label { visibility: hidden; } }