this.position = 'left';
this.$content = $();
this.nested = !!(this.options.nested);
- this.$relativeParent;
- this.relativeScope = false;
//Triggers init is idempotent, just need to make sure it is initialized
Triggers.init($);
this.$element.attr('aria-hidden', 'true');
- this.$element.addClass(`is-transition-${this.options.transition} is-closed`);
-
- // Find triggers that affect this element and add aria-expanded to them
- this.$triggers = $(document)
- .find('[data-open="'+id+'"], [data-close="'+id+'"], [data-toggle="'+id+'"]')
- .attr('aria-expanded', 'false')
- .attr('aria-controls', id);
-
- // Get position by checking for related CSS class
- this.position = this.$element.is('.position-left, .position-top, .position-right, .position-bottom') ? this.$element.attr('class').match(/position\-(left|top|right|bottom)/)[1] : this.position;
-
// Find off-canvas content, either by ID (if specified), by siblings or by closest selector (fallback)
if (this.options.contentId) {
this.$content = $('#'+this.options.contentId);
console.warn('Remember to use the nested option if using the content ID option!');
}
- // For a nested element, find closest (relative) positioned element
- if (this.nested) {
- this.$relativeParent = this.$element.offsetParent();
- // Initial adjustment of the element according to local scope
- this._adjustToLocalScope();
+ if (this.nested === true) {
+ // Force transition overlap if nested
+ this.options.transition = 'overlap';
+ // Remove appropriate classes if already assigned in markup
+ this.$element.removeClass('is-transition-push');
+ this.$content.removeClass('has-transition-push');
}
+ this.$element.addClass(`is-transition-${this.options.transition} is-closed`);
this.$content.addClass(`has-transition-${this.options.transition}`);
+ // Find triggers that affect this element and add aria-expanded to them
+ this.$triggers = $(document)
+ .find('[data-open="'+id+'"], [data-close="'+id+'"], [data-toggle="'+id+'"]')
+ .attr('aria-expanded', 'false')
+ .attr('aria-controls', id);
+
+ // Get position by checking for related CSS class
+ this.position = this.$element.is('.position-left, .position-top, .position-right, .position-bottom') ? this.$element.attr('class').match(/position\-(left|top|right|bottom)/)[1] : this.position;
+
// Add an overlay over the content if necessary
if (this.options.contentOverlay === true) {
var overlay = document.createElement('div');
}
this._setContentClasses();
-
- this._emulateFixedPosition(true);
}
/**
* @private
*/
_events() {
- var id = this.$element.attr('id');
-
this.$element.off('.zf.trigger .zf.offcanvas').on({
'open.zf.trigger': this.open.bind(this),
'close.zf.trigger': this.close.bind(this),
var $target = this.options.contentOverlay ? this.$overlay : this.$content;
$target.on({'click.zf.offcanvas': this.close.bind(this)});
}
-
- var resizeListener = this.resizeListener = `resize.zf.${id}`;
- var resizeTimeout;
-
- $(window).off(resizeListener).on(resizeListener, () => {
- // Delay as timeout to prevent too many calls on resizing
- clearTimeout(resizeTimeout);
- resizeTimeout = setTimeout(() => {
- this._adjustToLocalScope();
- this._emulateFixedPosition(true);
- }, 250);
- });
}
/**
}
}
- /**
- * Adjust element's left position if relative parent is affecting local coords (left).
- * This is required if using a nested element within a push/pull column.
- * @private
- */
- _adjustToLocalScope() {
- if (this.nested) {
- // Check if relative parent is affecting local coords
- if (parseInt(this.$relativeParent.css('left')) > 0 || this.$relativeParent.offset().top > 0) {
- this.relativeScope = true;
- // Adjust element to local scope
- let xOffset = Math.ceil(parseFloat(this.$relativeParent.css('left'))) * (-1);
- switch (this.position) {
- case 'top':
- this.$element.css('left', xOffset).width($(window).width());
- break;
- case 'bottom':
- this.$element.css('left', xOffset).width($(window).width());
- break;
- case 'left':
- this.$element.css('left', xOffset);
- break;
- }
- } else {
- this.relativeScope = false;
- // Reset adjustment
- this.$element.css({
- 'left': '',
- 'width': ''
- });
- }
- }
- }
-
- /**
- * Emulate fixed position for a nested off-canvas element by using fixed height and current document scrollTop.
- * This is necessary due to the transform property of the content that creates a new local coordinate system.
- * @param {Boolean} resetHeight - true if the element's height should be set as well (mostly on init and window resize)
- * @private
- */
- _emulateFixedPosition(resetHeight = false) {
-
- if (this.nested === true) {
-
- var topOffset = this.relativeScope ? this.$relativeParent.offset().top : 0;
-
- if (this.position === 'top') {
-
- this.$element.css('top', $(document).scrollTop() - topOffset);
-
- } else if (this.position === 'bottom') {
-
- this.$element.css('top', $(document).scrollTop() + $(window).height() - this.$element.outerHeight() - topOffset);
-
- } else { // left|right
-
- this.$element.css('top', $(document).scrollTop() - topOffset);
-
- if (resetHeight === true) {
- this.$element.height( $(window).height() );
- }
- }
- }
- }
-
/**
* Handles the revealing/hiding the off-canvas at breakpoints, not the same as open.
* @param {Boolean} isRevealed - true if element should be revealed.
this.$element.siblings('[data-off-canvas-content]').css('transition-duration', '');
}
- this._adjustToLocalScope();
- this._emulateFixedPosition();
-
/**
* Fires when the off-canvas menu opens.
* @event OffCanvas#opened
this.$content.addClass('is-open-' + this.position);
// If `contentScroll` is set to false, add class and disable scrolling on touch devices.
- // If off-canvas element is nested, force `contentScroll` false.
- if (this.options.contentScroll === false || this.nested === true) {
+ if (this.options.contentScroll === false) {
$('body').addClass('is-off-canvas-open').on('touchmove', this._stopScrolling);
this.$element.on('touchstart', this._recordScrollable);
this.$element.on('touchmove', this._stopScrollPropagation);
this.$content.removeClass('is-open-left is-open-top is-open-right is-open-bottom');
// If `contentScroll` is set to false, remove class and re-enable scrolling on touch devices.
- // // If off-canvas element is nested, force `contentScroll` false.
- if (this.options.contentScroll === false || this.nested === true) {
+ if (this.options.contentScroll === false) {
$('body').removeClass('is-off-canvas-open').off('touchmove', this._stopScrolling);
this.$element.off('touchstart', this._recordScrollable);
this.$element.off('touchmove', this._stopScrollPropagation);
this.close();
this.$element.off('.zf.trigger .zf.offcanvas');
this.$overlay.off('.zf.offcanvas');
- $(window).off(this.resizeListener);
}
}
/// Z-index of an off-canvas content overlay.
/// @type Number
-$offcanvas-overlay-zindex: 1 !default;
+$offcanvas-overlay-zindex: 11 !default;
/// Z-index of an off-canvas panel with the `push` transition.
/// @type Number
-$offcanvas-push-zindex: 2 !default;
+$offcanvas-push-zindex: 12 !default;
/// Z-index of an off-canvas panel with the `overlap` transition.
/// @type Number
-$offcanvas-overlap-zindex: 10 !default;
+$offcanvas-overlap-zindex: 13 !default;
/// Z-index of an off-canvas panel using the `reveal-for-*` classes or mixin.
/// @type Number
-$offcanvas-reveal-zindex: 2 !default;
+$offcanvas-reveal-zindex: 12 !default;
/// Length of the animation on an off-canvas panel.
/// @type Number
// 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-push-zindex + 1 !global; }
- @if $offcanvas-overlap-zindex <= $offcanvas-overlay-zindex { $offcanvas-overlap-zindex: $offcanvas-overlap-zindex + 1 !global; }
- @if $offcanvas-reveal-zindex <= $offcanvas-overlay-zindex { $offcanvas-reveal-zindex: $offcanvas-reveal-zindex + 1 !global; }
+ @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 {
// Set the off-canvas z-index.
// Since the push z-index may be set by custom settings, a condition makes sure it is greater than the overlay's z-index (backwards compatibility).
- z-index: if($offcanvas-push-zindex > $offcanvas-overlay-zindex, $offcanvas-push-zindex, $offcanvas-overlay-zindex + 1);
+ z-index: $offcanvas-push-zindex;
transition: transform $transition;
backface-visibility: hidden;
// Overlap only styles.
&.is-transition-overlap {
- z-index: if($offcanvas-overlap-zindex > $offcanvas-overlay-zindex , $offcanvas-overlap-zindex, $offcanvas-overlay-zindex + 2);
+ z-index: $offcanvas-overlap-zindex;
&.is-open {
box-shadow: $offcanvas-shadow;
}
// No transform on overlap transition
- @at-root .#{$maincontent-class}.has-transition-overlap[class*="is-open"] {
- transform: translate(0, 0);
+ @at-root .#{$maincontent-class}.has-transition-overlap {
+ transform: none;
}
}
.off-canvas {
@include off-canvas-base;
- // Force position absolute for nested off-canvas because fixed doesn't work in this case (and gets emulated by JS anyway).
- // This is important for the IE which doesn't show an opened push off-canvas element otherwise!
+ // Force position absolute for nested off-canvas because fixed doesn't work for push transition within the transform scope.
@at-root .#{$maincontent-class} & {
- position: absolute;
+ // 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;
}
}