// Foundation for Sites by ZURB // foundation.zurb.com // Licensed under MIT Open Source //// /// @group off-canvas //// /// Width map of a left/right off-canvas panel. /// @type Map $offcanvas-sizes: ( small: 250px, ) !default; /// Height map of a top/bottom off-canvas panel. /// @type Map $offcanvas-vertical-sizes: ( small: 250px, ) !default; /// Background color of an off-canvas panel. /// @type Color $offcanvas-background: $light-gray !default; /// Box shadow for the off-canvas overlap panel. /// @type Shadow $offcanvas-shadow: 0 0 10px rgba($black, 0.7) !default; /// Inner box shadow size for the off-canvas push panel. /// @type Number $offcanvas-inner-shadow-size: 20px !default; /// Inner box shadow color for the off-canvas push panel. /// @type Color $offcanvas-inner-shadow-color: rgba($black, 0.25) !default; /// Z-index of an off-canvas content overlay. /// @type Number $offcanvas-overlay-zindex: 11 !default; /// Z-index of an off-canvas panel with the `push` transition. /// @type Number $offcanvas-push-zindex: 12 !default; /// Z-index of an off-canvas panel with the `overlap` transition. /// @type Number $offcanvas-overlap-zindex: 13 !default; /// Z-index of an off-canvas panel using the `reveal-for-*` classes or mixin. /// @type Number $offcanvas-reveal-zindex: 12 !default; /// Length of the animation on an off-canvas panel. /// @type Number $offcanvas-transition-length: 0.5s !default; /// Timing function of the animation on an off-canvas panel. /// @type Keyword $offcanvas-transition-timing: ease !default; /// If `true`, a revealed off-canvas will be fixed-position, and scroll with the screen. /// @type Bool $offcanvas-fixed-reveal: true !default; /// Background color for the overlay that appears when an off-canvas panel is open. /// @type Color $offcanvas-exit-background: rgba($white, 0.25) !default; /// CSS class used for the main content area. The off-canvas mixins use this to target the page content. $maincontent-class: 'off-canvas-content' !default; /// Adds baseline styles for off-canvas. This CSS is required to make the other pieces work. @mixin off-canvas-basics { /// Transform deprecated size settings into map & show warning @if variable-exists(offcanvas-size) { $offcanvas-sizes: (small: $offcanvas-size, medium: $offcanvas-size) !global; @warn '$offcanvas-size is deprecated and not used anymore! Please update your settings and use the map $offcanvas-sizes instead'; } @if variable-exists(offcanvas-vertical-size) { $offcanvas-vertical-sizes: (small: $offcanvas-vertical-size, medium: $offcanvas-vertical-size) !global; @warn '$offcanvas-vertical-size is deprecated and not used anymore! Please update your settings and use the map $offcanvas-vertical-sizes instead'; } // Checks the z-indexes and increase them due to backwards compatibility. // This is necessary because the overlay's z-index is new since v6.4 and may be identical to the user custom settings of the push z-index. @if $offcanvas-push-zindex <= $offcanvas-overlay-zindex { $offcanvas-push-zindex: $offcanvas-overlay-zindex + 1 !global; } @if $offcanvas-overlap-zindex <= $offcanvas-push-zindex { $offcanvas-overlap-zindex: $offcanvas-push-zindex + 1 !global; } @if $offcanvas-reveal-zindex <= $offcanvas-overlay-zindex { $offcanvas-reveal-zindex: $offcanvas-overlay-zindex + 1 !global; } // Hides overflow on body when an off-canvas panel is open. .is-off-canvas-open { overflow: hidden; } // Off-canvas overlay (generated by JavaScript) .js-off-canvas-overlay { position: absolute; top: 0; left: 0; z-index: $offcanvas-overlay-zindex; width: 100%; height: 100%; transition: opacity $offcanvas-transition-length $offcanvas-transition-timing, visibility $offcanvas-transition-length $offcanvas-transition-timing; background: $offcanvas-exit-background; opacity: 0; visibility: hidden; overflow: hidden; &.is-visible { opacity: 1; visibility: visible; } &.is-closable { cursor: pointer; } &.is-overlay-absolute { position: absolute; } &.is-overlay-fixed { position: fixed; } } } // Adds basic styles for an off-canvas wrapper. @mixin off-canvas-wrapper() { position: relative; overflow: hidden; } /// Adds basic styles for an off-canvas panel. @mixin off-canvas-base( $background: $offcanvas-background, $transition: $offcanvas-transition-length $offcanvas-transition-timing, $fixed: true ) { @include disable-mouse-outline; @if $fixed == true { position: fixed; } @else { position: absolute; } // Set the off-canvas z-index. z-index: $offcanvas-push-zindex; // Increase CSS specificity &.is-transition-push { z-index: $offcanvas-push-zindex; } transition: transform $transition; backface-visibility: hidden; background: $background; // Hide inactive off-canvas within the content that have the same position &.is-closed { visibility: hidden; } // Overlap only styles. &.is-transition-overlap { z-index: $offcanvas-overlap-zindex; &.is-open { box-shadow: $offcanvas-shadow; } } // Sets transform to 0 to show an off-canvas panel. &.is-open { transform: translate(0, 0); } } /// Adds styles to position an off-canvas panel to the left/right/top/bottom. @mixin off-canvas-position( $position: left, $orientation: horizontal, $sizes: if($orientation == horizontal, $offcanvas-sizes, $offcanvas-vertical-sizes) ) { @if $position == left { top: 0; left: 0; height: 100%; overflow-y: auto; @each $name, $size in $sizes { @include breakpoint($name) { width: $size; transform: translateX(-$size); } } // Sets the position for nested off-canvas element @at-root .#{$maincontent-class} .off-canvas.position-#{$position} { @each $name, $size in $sizes { @include breakpoint($name) { transform: translateX(-$size); } } &.is-transition-overlap.is-open { transform: translate(0, 0); } } // Sets the open position for the content @at-root .#{$maincontent-class}.is-open-#{$position} { &.has-transition-push { @each $name, $size in $sizes { @include breakpoint($name) { transform: translateX($size); } } } } } @else if $position == right { top: 0; right: 0; height: 100%; overflow-y: auto; @each $name, $size in $sizes { @include breakpoint($name) { width: $size; transform: translateX($size); } } // Sets the position for nested off-canvas element @at-root .#{$maincontent-class} .off-canvas.position-#{$position} { @each $name, $size in $sizes { @include breakpoint($name) { transform: translateX($size); } } &.is-transition-overlap.is-open { transform: translate(0, 0); } } // Sets the open position for the content @at-root .#{$maincontent-class}.is-open-#{$position} { &.has-transition-push { @each $name, $size in $sizes { @include breakpoint($name) { transform: translateX(-$size); } } } } } @else if $position == top { top: 0; left: 0; width: 100%; overflow-x: auto; @each $name, $size in $sizes { @include breakpoint($name) { height: $size; transform: translateY(-$size); } } // Sets the position for nested off-canvas element @at-root .#{$maincontent-class} .off-canvas.position-#{$position} { @each $name, $size in $sizes { @include breakpoint($name) { transform: translateY(-$size); } } &.is-transition-overlap.is-open { transform: translate(0, 0); } } // Sets the open position for the content @at-root .#{$maincontent-class}.is-open-#{$position} { &.has-transition-push { @each $name, $size in $sizes { @include breakpoint($name) { transform: translateY($size); } } } } } @else if $position == bottom { bottom: 0; left: 0; width: 100%; overflow-x: auto; @each $name, $size in $sizes { @include breakpoint($name) { height: $size; transform: translateY($size); } } // Sets the position for nested off-canvas element @at-root .#{$maincontent-class} .off-canvas.position-#{$position} { @each $name, $size in $sizes { @include breakpoint($name) { transform: translateY($size); } } &.is-transition-overlap.is-open { transform: translate(0, 0); } } // Sets the open position for the content @at-root .#{$maincontent-class}.is-open-#{$position} { &.has-transition-push { @each $name, $size in $sizes { @include breakpoint($name) { transform: translateY(-$size); } } } } } // If $offcanvas-inner-shadow-size is set, add inner box-shadow. // This mimics the off-canvas panel having a lower z-index, without having to have one. @if $offcanvas-inner-shadow-size { &.is-transition-push { @if $position == left { @include inner-side-shadow(right, $offcanvas-inner-shadow-size, $offcanvas-inner-shadow-color); } @else if $position == right { @include inner-side-shadow(left, $offcanvas-inner-shadow-size, $offcanvas-inner-shadow-color); } @else if $position == top { @include inner-side-shadow(bottom, $offcanvas-inner-shadow-size, $offcanvas-inner-shadow-color); } @else if $position == bottom { @include inner-side-shadow(top, $offcanvas-inner-shadow-size, $offcanvas-inner-shadow-color); } } } } /// Sets the styles for the content container. @mixin off-canvas-content() { transform: none; transition: transform $offcanvas-transition-length $offcanvas-transition-timing; backface-visibility: hidden; // Transform scope until the element is closed (makes sure transitionend gets triggered) &.has-transition-push { transform: translate(0, 0); } // Consider element & content, nested in another content .off-canvas.is-open { transform: translate(0, 0); } } /// Adds styles that reveal an off-canvas panel. @mixin off-canvas-reveal( $position: left, $zindex: $offcanvas-reveal-zindex, $content: $maincontent-class, $breakpoint: small ) { transform: none; z-index: $zindex; transition: none; visibility: visible; @if not $offcanvas-fixed-reveal { position: absolute; } .close-button { display: none; } // Consider revealed element is nested in content .#{$maincontent-class} & { transform: none; } @at-root .#{$content}.has-reveal-#{$position} { margin-#{$position}: -zf-get-bp-val($offcanvas-sizes, $breakpoint); } // backwards compatibility (prior to v6.4) & ~ .#{$content} { margin-#{$position}: -zf-get-bp-val($offcanvas-sizes, $breakpoint); } } /// Overrides the off-canvas styles @mixin in-canvas() { visibility: visible; height: auto; position: static; background: none; width: auto; overflow: visible; transition: none; // Increase CSS specificity &.position-left, &.position-right, &.position-top, &.position-bottom { box-shadow: none; transform: none; } .close-button { display: none; } } @mixin foundation-off-canvas { @include off-canvas-basics; // Off-canvas wrapper .off-canvas-wrapper { @include off-canvas-wrapper; } // Off-canvas container .off-canvas { @include off-canvas-base; // Force position absolute for nested off-canvas because fixed doesn't work for push transition within the transform scope. @at-root .#{$maincontent-class} & { // NOTE: since overlap transition is currently forced if nested, there's no need to force position absolute until nested push transition is supported. // position: absolute; } } // Off-canvas container with absolute position .off-canvas-absolute { @include off-canvas-base($fixed: false); } // Off-canvas position classes .position-left { @include off-canvas-position(left, horizontal); } .position-right { @include off-canvas-position(right, horizontal); } .position-top { @include off-canvas-position(top, vertical); } .position-bottom { @include off-canvas-position(bottom, vertical); } .off-canvas-content { @include off-canvas-content; } // Reveal off-canvas panel on larger screens @each $name, $value in $breakpoint-classes { @if $name != $-zf-zero-breakpoint { @include breakpoint($name) { .position-left.reveal-for-#{$name} { @include off-canvas-reveal(left, $offcanvas-reveal-zindex, $maincontent-class, $name); } .position-right.reveal-for-#{$name} { @include off-canvas-reveal(right, $offcanvas-reveal-zindex, $maincontent-class, $name); } .position-top.reveal-for-#{$name} { @include off-canvas-reveal(top, $offcanvas-reveal-zindex, $maincontent-class, $name); } .position-bottom.reveal-for-#{$name} { @include off-canvas-reveal(bottom, $offcanvas-reveal-zindex, $maincontent-class, $name); } } } } // Move in-canvas for larger screens @each $name, $value in $breakpoint-classes { @if $name != $-zf-zero-breakpoint { @include breakpoint($name) { .off-canvas.in-canvas-for-#{$name} { @include in-canvas; } } } } }