7

Can this be achieved by only modifying the class of the <ui> <li> custom dropdown menu? By just modifying the top, left, right, bottom part and nothing else? Or is there some special magic, if anyone knows a tutorial please share with me. I've been unable to find some on the Internet, thanks a lot.

Screenshot:

enter image description here

HTML:

<div class="container">
<ul class="menu openDown">
    <li>Option 1</li>
    <li>Option 2</li>
    <li>Option 3</li>
    <li>Option 4</li>
    <li>Option 5</li>
</ul>  

Here's a fiddle:

http://jsfiddle.net/heM4v/11/

EDIT: This MUST be modified on scroll, detecting if the user scrolled down or up, and based on scroll amount, modify the class of the menu to either point up or down. Thanks!

EDIT: This post is NOT duplicate since the link (Drop-down menu that opens up/upward with pure css), is very different from this one, I want the menu drop direction to depend on the amount of scroll either up/down by the user, meaning determine scroll position and modify the class to either drop the menu up/down. In the Stackoverflow link give this isn't achieved and it's pure CSS hover based, meaning you'd use it in ".no-js" form.

EDIT: Two snippets, not sure if this might help you folks figure it out.

var menuHeight = $(this).parent().find('.menu').innerHeight();

$(window).scroll(function () {
            var fromTop = $(this).scrollTop() + menuHeight;
            console.log(fromTop); 
        }); 

EDIT: The bounty is still open, if someone knows any tutorial or how to achieve this, share your answer, and you will get 50 in reputation points.

Ricardo
  • 3,696
  • 5
  • 36
  • 50
John Smith
  • 465
  • 4
  • 15
  • 38
  • 3
    your html and jqeury code no magician here:p – M.chaudhry Jun 21 '14 at 15:10
  • 2
    @M.chaudhry I am almost done with a jsfiddle – John Smith Jun 21 '14 at 15:15
  • 2
    @Rajaprabhu, please remove the "marked as duplicate" – John Smith Jun 21 '14 at 15:38
  • 2
    @Rajapabhu Because it isn't, technically speaking. Remember: "It is very different from this one, I want the menu drop direction to depend on the amount of scroll either up/down by the user, meaning determine scroll position and modify the class to either drop the menu up/down." – John Smith Jun 21 '14 at 15:43
  • 2
    I will continue to work around this, if someone knows a way to do this, or has a solution share it here, and I'd mark your post as the answer +1 in extra vote. – John Smith Jun 21 '14 at 16:19
  • I think you should calculate the distance from the top of the screen to that button and the distance from the bottom to that button and then decide the direction of the menu depends on the higher number. – MaveRick Oct 27 '14 at 13:53
  • @MaveRick I am not exactly sure of how to do that, and if anyone knows how, please share with me, I'd be very happy to know exactly. Thanks a lot. See my code-snippet above. – John Smith Oct 27 '14 at 14:34
  • I realize that my code-snippet is incomplete still. (I posted 4 months ago, so what I had in my mind when I wrote that was a little bit different I guess, but I still strive to achieve what presented in the print screen above). – John Smith Oct 27 '14 at 14:45
  • -1 for unclear description. OP is looking to make a drop up menu. Possible duplicate of http://stackoverflow.com/q/16240828/541591 – James Wong Oct 28 '14 at 01:09
  • @JamesWong It's not the same, see my print screen, I want to drop down menu (toggled) to position itself differently depending on the current scroll position. E.g. on Facebook this happens. – John Smith Oct 28 '14 at 07:11

2 Answers2

7

Edit 2 (see comments)

After discussing with the OP, here's what was wanted:

  1. Create a class that reverses the dropdown
  2. When opening the dropdown, calculate the position of the inner list in the window
  3. depending on that position (is the button above or below the middle of the browser window), apply the reversed class.

CSS

[This is made for bootstrap, edit the class to match your needs]

.reverse {
    top:auto;
    bottom:100%;
}

JS

$(".dropdown-toggle").click(function(){
    // get the scollTop (distance scrolled from top)
    var scrollTop = $(window).scrollTop();
    // get the top offset of the dropdown (distance from top of the page)
    var topOffset = $(".dropdown").offset().top;
    // calculate the dropdown offset relative to window position
    var relativeOffset = topOffset-scrollTop;
    // get the window height
    var windowHeight = $(window).height();
    
    // if the relative offset is greater than half the window height,
    // reverse the dropdown.
    if(relativeOffset > windowHeight/2){
        $(".dropdown-menu").addClass("reverse");
    }
    else{
        $(".dropdown-menu").removeClass("reverse");
    }
});

Same goes for this, this will work on a bootstrap dropdown, so you'll need to update the selectors if you want to use another framework.

The idea is to calculate the difference between the top offset of the element and the current scrollTop, then add the reverse class to the inner ul depending on the comparison between that value and the middle of the page.

Fiddle

EDIT 1 (see comments)

As per requested, here's how I tweaked things around a bit.

N.B. This uses Twitter Bootstrap, both for styling and markup and for javascript, but it is by no means necessary and can be recreated without too much hassle.

HTML

As asked, I added two reverse-toggle elements to the dropdown, (one at the beginning, the other at the end).

<li role="presentation" class="reverse-toggle top-reverse hidden"><a role="menuitem" tabindex="-1" href="javascript:void(0)">Reverse towards top</a></li>

The important part here is the reverse-toggle top-reverse classes. The rest is Bootstrap markup.

It is also important to add the javascript:void(0) to the a element, if this isn't added the dropdown will close when the buttons are clicked.

 CSS

As stated earlier, the only important rules here are those given by the .reverse class. This class will be applied to the ul containing the dropdown and is responsible for the reversed state.

.reverse {
    top: auto;
    bottom:100%;
}

JS

$(window).scroll(function () {
    // if the dropdown is "high enough" on the page, show the toggle commands
    if(($(window).scrollTop() + $(window).height() > $(document).height() - 256)){
        if($(".dropdown-menu").hasClass("reverse")){
            // if the dropdown is already reversed
            $(".bottom-reverse").removeClass("hidden");
            $(".top-reverse").addClass("hidden");
        }
        else{
            $(".top-reverse").removeClass("hidden");
            $(".bottom-reverse").addClass("hidden");
        }
    }
    else{
        $(".top-reverse").addClass("hidden");
        $(".bottom-reverse").addClass("hidden");
    }
});

$(".reverse-toggle").click(function(){
    $(".dropdown-menu").toggleClass("reverse").dropdown("toggle");
    $(".top-reverse").toggleClass("hidden");
    $(".bottom-reverse").toggleClass("hidden");
});

The JS here does the two following things:

  1. If the page is scrolled, depending on the page position (first if) and the state of the dropdown (second if, either reverse or not), the correct button is shown in the dropdown.
  2. If one of the reverse-toggle buttons is clicked, the dropdown ul changes states.

Fiddle

Here

Original answer

My solution works the following way:

  1. Create a reverse class that specifies the dropdown location (in twitter bootstrap, that class contains only top:auto; and bottom:100%)
  2. Add that class or remove it depending on the scrollTop() value.

It can pretty easily be ported to other frameworks assuming you find the correct class to add.

See the fiddle.

Community
  • 1
  • 1
Sir Celsius
  • 822
  • 8
  • 22
  • 1
    I modified the code this way, http://jsfiddle.net/2uyh4j3w/4/ But it doesn't behave naturally. E.g. when I scroll up, the button is indeed reaching the bottom, and shall then be reversed, and when I scroll up, it shall be reserved back to normal behavior. – John Smith Oct 27 '14 at 15:30
  • 1
    Do you think this can be implemented with a click instead, each that it gets current position somehow, and then determines if reverse or normal. – John Smith Oct 27 '14 at 15:34
  • 1
    By your first comment, do you mean you want the dropdown to be reversed (above the button) when the button is in the lower part of the window? And by your second, you want to get the position (above or below the 'middle' of the page) on click and act accordingly? – Sir Celsius Oct 27 '14 at 15:57
  • Yes, that means when there's detection that it's at the near the bottom of browser Window. However, now I realize, that the menu shall not be adaptive the way it's now, but that this shall occur on click, that's actually more naturally. (That's what I saw on other websites while trying this out now). So how would this be done, is it On click and get current scroll position? – John Smith Oct 27 '14 at 16:02
  • Not exactly, it doesn't compare scroll. The toggle or self-toggle or opening of the menu occurs when you click the "dropdown" itself, that's what I want (not a separate button). Still have some scroll or something, or maybe on click get my offset position in scroll and say, hey the menu has to be revered etc. – John Smith Oct 27 '14 at 17:01
  • 1
    Re: "Create a reverse class that specifies the dropdown location (in twitter bootstrap, that class contains only top:auto; and bottom:100%)" - I cannot find such in the bootstrap code on Github. BTW, have they provided any JavaScript with support for this? – John Smith Oct 27 '14 at 17:27
  • My sentence wasn't that clear, I mean that you can easily build a `reverse` class on top of bootstrap's dropdown. It doesn't exist as such, I wrote the one in my answer's fiddle. – Sir Celsius Oct 27 '14 at 17:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/63721/discussion-between-sir-celsius-and-john-smith). – Sir Celsius Oct 27 '14 at 18:05
2

Vanilla JS

If you use Bootstrap with jQuery, this code do not sense. This code is for those who use native JS.

document.querySelector('.dropdown-toggle').addEventListener(
    'click',
    function() {
        var scrollTop = (((t = document.documentElement) || (t = document.body.parentNode)) &&
            typeof t.scrollTop == 'number' ? t : document.body).scrollTop;
        var topOffset = this.getBoundingClientRect().top;
        var relativeOffset = topOffset - scrollTop;
        var windowHeight = window.innerHeight;

        if (relativeOffset > windowHeight / 2) {
            document.querySelector('.dropdown-menu').classList.add("reverse");
        } else {
            document.querySelector('.dropdown-menu').classList.remove("reverse");
        }
    }, false);
falselight
  • 527
  • 7
  • 11