How to force ShiftNav to Lock in place the Header

2019-08-08 06:45发布

问题:

I am trying to make the ShiftNav menu plugin to apply Lock Scroll - aka lock_body in source code - on a new theme, which should make the-shifted-to-the right-by-the-opened-menu-content locked on y-scroll - obviously, (tested on previous theme). This option will work if the Shift Body will be enabled, which I did.

In these conditions the Lock Scroll it doesn't work. I've tried to fix the header and other elements in position using position: fixed !important; but as soon as the left menu will open, the header logo, etc, will go up at scroll.

The theme and the plugin have plenty of js, css, code; I really can't reproduce this into a fiddle, I have no knowledge to do this, sorry to being off MCVE, but I can provide a live link, and the sequences that should produce the lock scroll at menu-open.

In settings.config.php it looks like this (the bottom part)

function shiftnav_get_settings_fields(){

$prefix = SHIFTNAV_PREFIX;


$main_assigned = '';
if(!has_nav_menu('shiftnav')){
    $main_assigned = 'No Menu Assigned';
}
else{
    $menus = get_nav_menu_locations();
    $menu_title = wp_get_nav_menu_object($menus['shiftnav'])->name;
    $main_assigned = $menu_title;
}

$main_assigned = '<span class="shiftnav-main-assigned">'.$main_assigned.'</span>  <p class="shiftnav-desc-understated">The menu assigned to the <strong>ShiftNav [Main]</strong> theme location will be displayed.  <a href="'.admin_url( 'nav-menus.php?action=locations' ).'">Assign a menu</a></p>';

$fields = array(


    $prefix.'shiftnav-main' => array(

        array(
            'name'  => 'menu_assignment',
            'label' => __( 'Assigned Menu' , 'shiftnav' ),
            'desc'  => $main_assigned,
            'type'  => 'html',

        ),

        ....

$fields = apply_filters( 'shiftnav_settings_panel_fields' , $fields );

$fields[$prefix.'general'] = array(

    array(
        'name'      => 'lock_body',
        'label'     => __( 'Lock Scroll', 'shiftnav' ),
        'desc'      => __( 'Lock both vertical and horizontal scrolling on site content when menu is active.  No effect if <strong>Shift Body</strong> is disabled.', 'shiftnav' ),
        'type'      => 'checkbox',
        'default'   => 'on'
    ),
);


return $fields;

In shiftnav.js file we have:

        /* Initalizers */

    initializeShiftNav: function(){

        var $body = $('body'),
            plugin = this;

        //Only enable the site once
        if( !$body.hasClass( 'shiftnav-enabled' ) ){

            $body.addClass( 'shiftnav-enabled' );
            if( shiftnav_data.lock_body == 'on' ) $body.addClass( 'shiftnav-lock' );
            if( shiftnav_data.lock_body_x == 'on' ) $body.addClass( 'shiftnav-lock-x' );

            if( shiftnav_data.shift_body != 'off' ){
                if( shiftnav_data.shift_body_wrapper != '' ){
                    $( shiftnav_data.shift_body_wrapper ).addClass( 'shiftnav-wrap' );
                }
                else{
                    $body.wrapInner( '<div class="shiftnav-wrap"></div>' ); //unique
                    $( 'video[autoplay]' ).each( function(){
                        $(this).get(0).play();
                    });
                }
            }
            else $body.addClass( 'shiftnav-disable-shift-body' );

            //Move elements outside of shifter
            $( '#shiftnav-toggle-main, #wpadminbar, .shiftnav-fixed-left, .shiftnav-fixed-right' ).appendTo( 'body' );

            var $wrap = $( '.shiftnav-wrap' );

            //Pad top
            var toggleHeight = $( '#shiftnav-toggle-main' ).outerHeight();
            $wrap.css( 'padding-top' , toggleHeight );
            if( shiftnav_data.shift_body == 'off' ) $body.css( 'padding-top' , toggleHeight );

            //Setup non-transform
            //Some browsers provide false positives for feature detection, so we have to do browser detection as well, sadly
            var fpos = false;   //falsePositive - 
            var ua = navigator.userAgent.toLowerCase();

            //Many mobile Android browsers are dumb
            if( /android/.test( ua ) ){
                fpos = true; //we're going to whitelist mobile Android browsers, so assume false positive on Android

                //always ignore old androids
                if( /android [1-3]/.test( ua ) ) fpos = true;
                //Chrome on 4+ is good
                else if( /chrome/.test( ua ) ) fpos = false;
                //Firefox on 4+ is good
                else if( /firefox/.test( ua ) ) fpos = false;

                //always allow Chrome
                //else if( /chrome/.test( ua ) ) fpos = false;
                //Android 4.4+ is okay
                //else if( /android 4.[4-9]/.test( ua ) ) fpos = false;
                //else fpos = true;
            }


            if( !shift_supports( 'transform' ) || fpos || plugin.settings.disable_transforms ){
                $body.addClass( 'shiftnav-no-transforms' );
            }


            //Setup swipe open on MAIN SHIFTNAV only
            if( shiftnav_data.swipe_open == 'on' ){
                var wrap_start_y = 0,
                    wrap_start_x = 0,
                    wrap_cur_y = 0,
                    wrap_cur_x = 0,
                    viewport_width = $( window ).width();


                if( shiftnav_data.shift_body == 'off' ) $wrap = $( 'body' );

                $wrap.on( 'touchstart' , function( e ){
                    if( plugin.settings.breakpoint && $( window ).width() > plugin.settings.breakpoint ) return;
                    wrap_start_y = e.originalEvent.changedTouches[0].pageY;
                    wrap_start_x = e.originalEvent.changedTouches[0].pageX;
                    //console.log( "START: " + wrap_start_x );
                });

                //Left edge activate on swipe from left
                if( $( '#shiftnav-main' ).hasClass( 'shiftnav-left-edge' ) ){
                    $wrap.on( 'touchmove' , function( e ){
                        wrap_cur_x = e.originalEvent.changedTouches[0].pageX;
                        //console.log( wrap_cur_x );

                        //if close to left edge 
                        if( wrap_start_x < plugin.settings.swipe_edge_proximity ){
                            e.preventDefault();

                            //if swipe more than 150
                            if( wrap_cur_x - wrap_start_x > plugin.settings.swipe_tolerance_x ){
                                wrap_cur_y = e.originalEvent.changedTouches[0].pageY;
                                if( Math.abs( wrap_cur_y - wrap_start_y ) < plugin.settings.swipe_tolerance_y ){
                                    plugin.openShiftNav( 'swipe right' );
                                    e.stopPropagation();
                                }
                            }
                        }
                    });
                }
                //Right edge activate on swipe from right
                else{
                    $wrap.on( 'touchmove' , function( e ){
                        wrap_cur_x = e.originalEvent.changedTouches[0].pageX;

                        //if we start from the edge, tell android we've got this covered
                        if( wrap_start_x > ( viewport_width - plugin.settings.swipe_edge_proximity ) ){
                            e.preventDefault();

                            //if swipe more than 150, open panel
                            if( ( wrap_start_x - wrap_cur_x > plugin.settings.swipe_tolerance_x ) ){
                                wrap_cur_y = e.originalEvent.changedTouches[0].pageY;
                                if( Math.abs( wrap_cur_y - wrap_start_y ) < plugin.settings.swipe_tolerance_y ){
                                    plugin.openShiftNav( 'swipe left' );
                                    e.stopPropagation();
                                }
                            }
                        }


                    });
                }
            }

            //Handle searchbar toggle
            $( '.shiftnav-searchbar-toggle' ).on( this.toggleevent , function( e ){
                e.stopPropagation();
                e.preventDefault();

                var $drop = $( this ).next( '.shiftnav-searchbar-drop' );

                //Close
                if( $drop.hasClass( 'shiftnav-searchbar-drop-open' ) ){
                    $drop.removeClass( 'shiftnav-searchbar-drop-open' );
                    $( 'body' ).off( 'click.shiftnav-searchbar-drop' );
                }
                //Open
                else{
                    $drop.addClass( 'shiftnav-searchbar-drop-open' );
                    $drop.find( '.shiftnav-search-input' ).focus();

                    //Close on click-off - can't do this immediately because IE is so damn dumb
                    setTimeout( function(){
                        $( 'body' ).on( 'click.shiftnav-searchbar-drop' , function( e ){
                            $( '.shiftnav-searchbar-drop' ).removeClass( 'shiftnav-searchbar-drop-open' );
                            $( 'body' ).off( 'click.shiftnav-searchbar-drop' );
                        });
                    }, 100);
                }
            });
            $( '.shiftnav-searchbar-drop' ).on( this.toggleevent , function( e ){
                e.stopPropagation();
            });
            $( '.shiftnav-searchbar-drop .shiftnav-search-input').on( 'blur' , function( e ){
                if( $( this ).val() == '' && !toggle_clicked ){
                    $( this ).parents( '.shiftnav-searchbar-drop' ).removeClass( 'shiftnav-searchbar-drop-open' );
                }
            });
            var toggle_clicked;
            $( '.shiftnav-searchbar-toggle' ).on( 'mousedown' , function( e ){
                toggle_clicked = true;
            });
            $( '.shiftnav-searchbar-toggle' ).on( 'mouseup' , function( e ){
                toggle_clicked = false;
            });


        }

        this.$shiftnav.appendTo( 'body' );

        if( this.$shiftnav.hasClass( 'shiftnav-right-edge' ) ){
            this.edge = 'right';
        }
        else this.edge = 'left';

        this.openclass = 'shiftnav-open shiftnav-open-' + this.edge;

        //Set retractor heights
        this.$shiftnav.find( '.shiftnav-submenu-activation' ).each( function(){
            var length = $( this ).outerHeight();
            $( this ).css( { 'height' : length , 'width' : length } );

            //$( this ).css( 'height' , $( this ).parent( '.menu-item' ).height() );
        });



        //Current open
        if( plugin.settings.open_current ){
            $( '.shiftnav .shiftnav-sub-accordion.current-menu-item, .shiftnav .shiftnav-sub-accordion.current-menu-ancestor' ).addClass( 'shiftnav-active' );
        }

    },

In page index.html also we have "lock_body":"on" here:

    /* <![CDATA[ */
var shiftnav_data = {"shift_body":"on","shift_body_wrapper":".edge-wrapper","lock_body":"on","lock_body_x":"off","swipe_close":"off","swipe_open":"off","swipe_tolerance_x":"150","swipe_tolerance_y":"60","swipe_edge_proximity":"80","open_current":"off","collapse_accordions":"off","scroll_panel":"off","breakpoint":"","touch_off_close":"off","scroll_offset":"100","disable_transforms":"off"};
/* ]]> */

The Chrome console looks like this:

At this point I am interested to know if there is a possibility to force the ShiftNav to apply the Lock Scroll on this new theme; it will be great to have it applied ONLY to header and his elements (logo, etc) in other words,

It will be great to have the header fixed like the burger button at scrollTop when the menu is expanded to the right.

Website testpage

回答1:

This is due to your -webkit-transform and transform styling declarations for the containing
<div class="edge-wrapper shiftnav-wrap">. transform creates a new local coordinate system so the logo is fixed to that coordinate system rather than the body. see these posts: 1 2 3



回答2:

I've found a nice workaround that will ignore all the -webkit-transform, transform styling declarations and so on. Someone said : ... you can’t have a fixed element inside an element that has CSS transforms applied to it; Fixed position elements will act as position:absolute within a transformed context. This is actually part of the CSS spec.

Well, in this particular case, talking about ShiftNav and a custom theme, The good news is that

  • Yes you can, as long as you look at the picture having a step backward in order to see the whole picture.

The solution is to remove the logo from the header (or other elements as long as there is no facy stuff going on up there) and to put these elements into the Toggle Bar > Toggle Content Field inside the ShiftNav Settings. This will allow you to use without restrictions the Shift Body option, you will have a "fake header" fixed, the content is scrollable even if the main wrapp is shifted by the push-side menu, everything is nice, thanks to this plugin.

Voilà, have a look