1/* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17@use '@angular/cdk'; 18 19$drawer-content-z-index: 1; 20$drawer-side-drawer-z-index: 2; 21$drawer-backdrop-z-index: 3; 22$drawer-over-drawer-z-index: 4; 23 24// Mixin that creates a new stacking context. 25// see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context 26@mixin drawer-stacking-context($z-index: 1) { 27 position: relative; 28 29 // Use a z-index to create a new stacking context. (We can't use transform because it breaks fixed 30 // positioning inside of the transformed element). 31 z-index: $z-index; 32} 33 34.mat-drawer-container { 35 // We need a stacking context here so that the backdrop and drawers are clipped to the 36 // MatDrawerContainer. This creates a new z-index stack so we use low numbered z-indices. 37 // We create another stacking context in the '.mat-drawer-content' and in each drawer so that 38 // the application content does not get messed up with our own CSS. 39 @include drawer-stacking-context(); 40 41 box-sizing: border-box; 42 -webkit-overflow-scrolling: touch; 43 44 // Need this to take up space in the layout. 45 display: block; 46 47 // Hide the drawers when they're closed. 48 overflow: hidden; 49 50 // TODO(hansl): Update this with a more robust solution. 51 &[fullscreen] { 52 top: 0; 53 left: 0; 54 right: 0; 55 bottom: 0; 56 position: absolute; 57 58 &.mat-drawer-container-has-open { 59 overflow: hidden; 60 } 61 } 62 63 // When the consumer explicitly enabled the backdrop, 64 // we have to pull the side drawers above it. 65 &.mat-drawer-container-explicit-backdrop .mat-drawer-side { 66 z-index: $drawer-backdrop-z-index; 67 } 68 69 // Note that the `NoopAnimationsModule` is being handled inside of the component code. 70 &.ng-animate-disabled, .ng-animate-disabled & { 71 .mat-drawer-backdrop, .mat-drawer-content { 72 transition: none; 73 } 74 } 75} 76 77.mat-drawer-backdrop { 78 top: 0; 79 left: 0; 80 right: 0; 81 bottom: 0; 82 position: absolute; 83 84 display: block; 85 86 // Because of the new stacking context, the z-index stack is new and we can use our own 87 // numbers. 88 z-index: $drawer-backdrop-z-index; 89 90 // We use 'visibility: hidden | visible' because 'display: none' will not animate any 91 // transitions, while visibility will interpolate transitions properly. 92 // see https://developer.mozilla.org/en-US/docs/Web/CSS/visibility, the Interpolation 93 // section. 94 visibility: hidden; 95 96 &.mat-drawer-shown { 97 visibility: visible; 98 } 99 100 .mat-drawer-transition & { 101 transition: { 102 duration: 400ms; 103 timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); 104 property: background-color, visibility; 105 } 106 } 107 108 @include cdk.high-contrast(active, off) { 109 opacity: 0.5; 110 } 111} 112 113.mat-drawer-content { 114 @include drawer-stacking-context($drawer-content-z-index); 115 116 display: block; 117 height: 100%; 118 overflow: auto; 119 120 .mat-drawer-transition & { 121 transition: { 122 duration: 400ms; 123 timing-function: cubic-bezier(0.25, 0.8, 0.25, 1); 124 property: transform, margin-left, margin-right; 125 } 126 } 127} 128 129.mat-drawer { 130 $high-contrast-border: solid 1px currentColor; 131 132 @include drawer-stacking-context($drawer-over-drawer-z-index); 133 134 display: block; 135 position: absolute; 136 top: 0; 137 bottom: 0; 138 z-index: 3; 139 outline: 0; 140 box-sizing: border-box; 141 overflow-y: auto; // TODO(kara): revisit scrolling behavior for drawers 142 transform: translate3d(-100%, 0, 0); 143 144 &, [dir='rtl'] &.mat-drawer-end { 145 @include cdk.high-contrast(active, off) { 146 border-right: $high-contrast-border; 147 } 148 } 149 150 [dir='rtl'] &, &.mat-drawer-end { 151 @include cdk.high-contrast(active, off) { 152 border-left: $high-contrast-border; 153 border-right: none; 154 } 155 } 156 157 &.mat-drawer-side { 158 z-index: $drawer-side-drawer-z-index; 159 } 160 161 &.mat-drawer-end { 162 right: 0; 163 transform: translate3d(100%, 0, 0); 164 } 165 166 [dir='rtl'] & { 167 transform: translate3d(100%, 0, 0); 168 169 &.mat-drawer-end { 170 left: 0; 171 right: auto; 172 transform: translate3d(-100%, 0, 0); 173 } 174 } 175 176 // Usually the `visibility: hidden` added by the animation is enough to prevent focus from 177 // entering the hidden drawer content, but children with their own `visibility` can override it. 178 // This is a fallback that completely hides the content when the element becomes hidden. 179 // Note that we can't do this in the animation definition, because the style gets recomputed too 180 // late, breaking the animation because Angular didn't have time to figure out the target 181 // transform. This can also be achieved with JS, but it has issues when starting an 182 // animation before the previous one has finished. 183 &[style*='visibility: hidden'] { 184 display: none; 185 } 186} 187 188// Note that this div isn't strictly necessary on all browsers, however we need it in 189// order to avoid a layout issue in Chrome. The issue is that in RTL mode the browser doesn't 190// account for the sidenav's scrollbar while positioning, which ends up pushing it partially 191// out of the screen. We work around the issue by having the scrollbar be on this inner container. 192.mat-drawer-inner-container { 193 width: 100%; 194 height: 100%; 195 overflow: auto; 196 -webkit-overflow-scrolling: touch; 197} 198 199.mat-sidenav-fixed { 200 position: fixed; 201}