7
\$\begingroup\$

I'm using Twitter Bootstrap's navbar. While testing different screen resolutions, I noticed that on lower resolutions, sometimes the submenu would get cut off by the right side of the page.

In the code below, when a dropdown is opened, I'm getting the width of the dropdown menu and dropdown submenu, adding those together and checking them against the width of the window. If the width is greater than the window width, I add the class pull-right so the dropdown menu and/or dropdown submenu will extend to the left and not get cut off by the right side of the page.

In this jsFiddle, you can see what I'm talking about by increasing/decreasing the width of the Results section. When you increase the width of the Results section far enough, the submenu for 'Dropdown 2' will open to the right. When you decrease the size of the Results section enough that the submenu would get cut off, the 'pull-right' class is applied and it extends to the left.

For the most part, this code is doing what it should, but does anyone have any suggestions on how to improve it?

JavaScript

$('.dropdown-toggle').click(function() {
    var dropdownList = $('.dropdown-menu');
    var dropdownOffset = $(this).offset();
    var offsetLeft = dropdownOffset.left;
    var dropdownWidth = dropdownList.width();
    var docWidth = $(window).width();

    var subDropdown = $('.dropdown-menu').eq(1);
    var subDropdownWidth = subDropdown.width();

    var isDropdownVisible = (offsetLeft + dropdownWidth <= docWidth);
    var isSubDropdownVisible = (offsetLeft + dropdownWidth + subDropdownWidth <= docWidth);

    if (!isDropdownVisible || !isSubDropdownVisible) {
        $('.dropdown-menu').addClass('pull-right');
    } else {
        $('.dropdown-menu').removeClass('pull-right');
    }
});

Please let me know if I need to better my explanation or if any other details are needed.

\$\endgroup\$
0

3 Answers 3

4
\$\begingroup\$

A couple things you can do:

Use .on() to save a few function calls:

$('.dropdown-toggle').on('click', function() { ... });

You can also actually use the cache you save called dropdownList:

var subDropdown = dropdownList.eq(1);
//...
dropdownList.addClass('pull-right');
//...
dropdownList.removeClass('pull-right');

From what I can tell, this is only a problem on small width screens. I suggest you replace the nav bar with a select list when the screen is too small. You can use media-queries for this or even jQuery. You should just hide/show the nav and dropdown to suit your specific needs. I didn't include that part in the fiddle but something like this should do the trick: jsfiddle.net/bloqhead/Kq43X

\$\endgroup\$
1
  • \$\begingroup\$ thanks for taking a look at it and for the suggestion. Bootstrap does have similar functionality (and look) to the dropdown list when the screen width is less than a certain number of pixels (I don't remember the exact number). Before adding my code I noticed it because the page title in my last submenu is very long (can't shorten it either) so it actually needs to change direction at 1280x800 no matter what. Using .on() and cache seem good though. I'll leave this open for a day or so to see if anyone else chimes in with anything, if not I'll mark this as answer. Thanks again! \$\endgroup\$
    – Brian
    Sep 19, 2013 at 19:05
5
\$\begingroup\$

I came across this post searching for a fix to a slightly different problem. I have long entries in a drop-down menu that get cut off on small screen sizes. I found that if I allow the content in the dropdown to wrap it automatically gets adjusted to the page width:

.dropdown-menu > li > a {
    white-space: normal;
}

If you don't want it to wrap if there is enough space, add no-wrap back in with a media query. Because it is so simple I figured I leave this here for others, even though it does not directly apply to the cascading dropdown in your example.

\$\endgroup\$
1
\$\begingroup\$

Adding a little bit to what Jonny Sooter said. I would suggest to also use a little best practice where you don't call the reserved keyword "var" every time you create a variable.

Like:

$('.dropdown-toggle').on("click", function() {
  var dropdownList = $('.dropdown-menu'),
  dropdownOffset = $(this).offset(),
  offsetLeft = dropdownOffset.left,
  dropdownWidth = dropdownList.width(),
  docWidth = $(window).width(),

  subDropdown = dropdownList.eq(1),
  subDropdownWidth = subDropdown.width(),

  isDropdownVisible = (offsetLeft + dropdownWidth <= docWidth),
  isSubDropdownVisible = (offsetLeft + dropdownWidth + subDropdownWidth <= docWidth);

  if (!isDropdownVisible || !isSubDropdownVisible) {
        dropdownList.addClass('pull-right');
  } else {
        dropdownList.removeClass('pull-right');
  }
});

Hope that helps.

EDIT:

As apparently someone did not like my answer for some reason... I'm going to explain why I said what I said.

As I can see, the code is using a lot of "var"s to declare variables. The thing is, that you might not see a performance issue in the client in a few lines like in this case, but I assume that if the code was written this way, a lot more code could be written the same way, and if the question was "how to improve it?" not "in specifically this _____ way how could I improve it", my answer was according to performance (client side). We should always assume that the internet is as slow as it could be, the less info, the better.

I have seen a lot of people debate on rather it actually helps or not, the thing is, it does help (maybe just a little, but it does), and this might even add up to a lot. The reason why; is because at the end, your code is downloaded to the client, the less bytes you have to download, the best. Even, a lot of minifiers do this (point is, if they do it for performance, why shouldn't we for our own code?)

And I got the reference out of the book "Secrets of the JavaScript Ninja" written by: John Resig (creator of jQuery and lots more) and Bear Bibeault. I encourage you to read this book.

Also: an older question.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.