简体   繁体   中英

Positioning jQuery dropdown menu so that it displays completely on the screen on a mobile device

I have a basic jQuery dropdown menu and am testing it on mobile devices, specifically phones.

One issue I've encountered is that submenus on the right side sometimes go off the edge of the screen, because the text in one or more of the items is too long. The user can, of course, scroll slightly to the right, but that's not a great solution. There is a similar question here , but I couldn't get the proposed answers to work (plus I'm fumbling around since I'm still totally new to JS/jQuery).

The general idea seems to be to get the left position+width of the current submenu (making sure they are shown first, then hide them again or show them and shift them when the user taps the menu) and see if that value is greater than the screen width. If it is, then it should be shifted to the left by the difference. However, my attempts don't seem to do anything to the elements and the menus keep appearing partially off-screen. Currently, I have this (runs after the body loads):

var menus = $('#navbar').find('.subMenu');
menus.show();
menus.each(function(index) {
  var offsetMenu = $(this).offset();
  var diff = screen.width - ($(this).outerWidth + offsetMenu.left);
  if(diff < 0) {
    $(this).offset({top:offsetMenu.top, left:offsetMenu + diff});
  }
  });
menus.hide();

The jQuery version is 1.7.2 and the HTML structure is as follows (simplified version):

<div id="navbar">
  <ul>
    <li class="dropdown"><a href="#">Link A</a></li>
    <li class="dropdown"><a href="#">Link B</a>
      <ul class="subMenu">
        <li><a href="#">Link 1</a></li>
        <li><a href="#">Link 2</a></li>
      </ul>
    </li>
  </ul>
</div>

How can I get this to work?

Edit: Here's the relevant CSS, too.

#navbar ul.subMenu {
    position:absolute;
    display:none;
    background-color:#FFAF1E;
}
#navbar ul.subMenu li {
    clear:both;
}
#navbar a {
    text-decoration:none;
    color:#0C1F6E;
    display:block;
    padding-right:10px;
    padding-left:10px;
}

I finally got the following to work:

function adjustSubMenus()
  {
      var menus = $('#navbar').find('.subMenu');
      menus.each(function(){
          $(this).css("left","");
          adjustSingleMenu($(this))
          } );
  }
  function adjustSingleMenu(element)
  {
      element.show();
      var thisMenuWidth = element.outerWidth();
      var thisMenuPos = element.offset();
      var diff = (thisMenuWidth + thisMenuPos.left) - window.outerWidth;
      if(diff > 0) {
          element.css("left", function() { return thisMenuPos.left - diff; });
      }
      element.hide();
  }
  $('body').ready(function() {
      $(window).resize(adjustSubMenus());
      if(window.outerWidth <= 720) {
          $('html').mousedown(function() {
              $('#navbar').find('.subMenu').each(function(index) { 
                if($(this).is(":visible") ) {
                    $(this).css("left","");
                    $(this).hide(); 
                    }
              } );
          });

          $('#navbar').mousedown(function(event) {
              event.stopPropagation();
          });

          $('.dropdown').mousedown(function() {
              var ele = $(this).find('.subMenu');
              $('#navbar').find('.subMenu').each(function(index) { 
                if(!$(this).is(ele) && $(this).is(":visible") ) {
                    $(this).css("left","");
                    $(this).hide(); 
                    }
              } );
              if(ele.is(":visible")) {
                  ele.css("left","");
                  ele.hide();
              }
              else {
                  adjustSingleMenu(ele);
                  ele.show();                 
              }
              });
      }
      else
      {
          $('.dropdown').hover(
              function() { $(this).find('.subMenu').stop(true,true).slideDown("fast"); },
              function() { $(this).find('.subMenu').stop(true,true).hide(); } 
          );
      }
  });

The only minor caveat is that if you have a menu open as you change the orientation of the phone, the menu may appear off the screen. Closing and reopening the menu will fix this issue. Everything else works perfectly.

You could try creating CSS that works just for the mobile (tied to a CSS class name), and then upon detection of either a narrow screen or a mobile device, add the CSS class to your elements.

Javascript:

if (is_mobile)
{
    $(".subMenu").addClass('mobile');
}

CSS:

/* CSS */
.mobile { width:100%; left:0 !important; position:absolute; }

shouldn't the function check the width of the submenu plus its offset left and then if this is greater than the screenwidth then set the left value at 0 and its width as the screen width?

eg

    var menus = $('#navbar').find('.subMenu'),
        screenWidth = $(window).width();
        //screenWidth = screen.width; //I assume this calculates the screens width properly
    menus.show();
    menus.each(function(index) {
      var thisMenu = $(this),
          thisMenuWidth = thisMenu.outerWidth(),
          thisMenuLeft = thisMenu.offset().left;
      if(screenWidth < (thisMenuWidth + thisMenuLeft)) {
        thisMenu
            .width(screenWidth)
            .css({ //could replace this with .addClass("yourClass") and add this styling to that "yourClass" instead
             "left": "0", 
             "position": "absolute"
            });
      }
      });
    menus.hide();

Update:

I assumed screen.width was some special calculation you had already devised for a mobile device. i have changed this line now. the above should work. i see you already have a solution although that doesnt fix the width of the menu. if the menu is wider than the screen the above will fix its width.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM