Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chosen gets "cut" when placed in area with "overflow:hidden". #86

Open
ethaniel opened this issue Jul 27, 2011 · 129 comments
Open

Chosen gets "cut" when placed in area with "overflow:hidden". #86

ethaniel opened this issue Jul 27, 2011 · 129 comments
Labels

Comments

@ethaniel
Copy link

ethaniel commented Jul 27, 2011

I have a div with a form. The div has "overflow:hidden" option in the css.
When Chosen gets created, and it goes below the bottom line of the div, it gets cut.

Here is a screenshot:

Imgur

@reconbot
Copy link

This is the same as issue #59

@dfischer
Copy link

Isn't this unavoidable since the container element, is well, "overflow :hidden" that's just how CSS works. The only way around this is to render the drop down outside of the container and then use absolute positioning.

@johnnyfreeman
Copy link

Yeah, I agree with dfischer. Doesn't seem like a Chosen issue. By definition, the overflow property specifies what happens if content overflows an element's boundaries. If you don't want it the overflow to be hidden, then change that property.

@reconbot
Copy link

While true, I think this is a common use case with dialog boxes. (Especially jquery dialog)

@dfischer
Copy link

It is a common use case, however based on this ticket, like I previously mentioned... the entire structure and implementation has to change if you want to accomplish this.

You are required to render outside of the container for this to happen and then use jQuery/JS magic to figure out the positioning relative to the trigger.

jQuery Dialog's case doesn't depend upon a container element so it just uses positioning based on center dimensions and width of the dialog.

@dfischer
Copy link

This is more of a CSS issue, not a Chosen issue. Don't put overflow: hidden on the container. You're going to have to use another technique to clear the floats below it if that's what you're doing.

@medelbrock
Copy link

I just wrote some code which I think does what you're looking for:

$.fn.extend({
chosen: function (data, options) {
if ($(this).parent().css("overflow") == "hidden") {
//get the offsets between parent and child to calculate the diff
//when we push to absolute
var y = $(this).offset().top - $(this).parent().offset().top,
x = $(this).offset().left - $(this).parent().offset().left,
$t1 = $("<div/>", {
css: {
"position": "relative",
"height": $(this).parent().height,
"width": $(this).parent().width
}
}),
$t2 = $("<div/>", {
css: {
"position": "absolute",
"top": y,
"left": x
}
});
$t1.insertBefore($(this).parent());
$(this).parent().appendTo($t1);
$t2.appendTo($t1);
$(this).appendTo($t2);
}
return $(this).each(function (input_field) {
if (!($(this)).hasClass("chzn-done")) {
return new Chosen(this, data, options);
}
});
}
});

(btw I'm new to github as of today so if there is a different place where I should be posting code let me know)

That code effectively does the following:

  1. calculate the offset between the select box and the parent.
  2. create a parent div with the same dimensions as your overflow hidden and set to relative.
  3. create a parent for the select box creating the element as absolute using the x and y offsets from step 1.
  4. insert new parent before the select's parent, append the overflow div inside of the new parent, append that new select parent inside of the master parent, append the select to the new child parent.

@tompaton
Copy link

Interesting idea Matthew, but I think that's not going to work in a jQuery-UI dialog is it?

It's more likely that the dropdown element (.chzn-drop) needs to be pulled out of the .chzn-container and up to the document body...

@medelbrock
Copy link

Just add a style to the page and your answer is yes:

.ui-dialog{ overflow:visible; }

@ethaniel
Copy link
Author

Doesn't work for me, since I create my pages using div's as columns (as opposed to td's and tables).
I use "overflow:hidden" to stop runaway content from ruining neighbour divs.

I suppose many of you use the same structure.

@tompaton
Copy link

That won't work, as the dialogs are set to overflow:auto so they can
have scrollbars if necessary.

On Fri, Jul 29, 2011 at 11:47 PM, ethaniel
reply@reply.github.com
wrote:

Doesn't work for me, since I create my pages using div's as columns (as opposed to td's and tables).
I use "overflow:hidden" to stop runaway content from ruining neighbour divs.

I suppose many of you use the same structure.

Reply to this email directly or view it on GitHub:
#86 (comment)

@medelbrock
Copy link

Before we get any further into this conversation, what I've done is a theoretical fix. It can't be applied to all scenarios because all it takes is one element having a counter-attribute to screw it up. The above solution with the overflow visible will only work with dialog option resizable:false. Why would you need to have a select overflow outside of a dialog?

@tompaton
Copy link

Ok, here are a bunch of screenshots which hopefully clarify the issue.

http://i.imgur.com/9ZY9O.png
http://i.imgur.com/c2PLo.png
http://i.imgur.com/1oqZ7.png
http://i.imgur.com/ZBrQj.png

Screenshots 1 & 2 show how it behaves, there isn't enough space for
the dropdown "inside" the dialog, so it scrolls and is hidden as a
result. This is very clunky to use and ugly and not how the built in
select controls work (they show over the top of the content, no matter
how deep inside it they are or what it's overflow style is.)

Screenshots 3 & 4 show my current work-around, which is to put a whole
heap of space below the dropdown. This is also ugly and makes the form
harder to use.

So, to summarise, the real point is that native select controls aren't
restricted to their parent container and if it's possible, the chosen
enhanced select control shouldn't be either, since it's designed to be
a drop-in replacement for the native control.

@medelbrock
Copy link

This theoretically can be done but it would require a completely different construction/positioning system by the chosen plugin. This change would be extensive and require about a 30% rewrite of the current plugin. I consider this a feature request and not a bug. All browsers have a default render for select elements.Chosen replicates it using divs but is not treated like a select element.

@dfischer
Copy link

Like I said, the only way to do this is absolute positioning OUTSIDE of the triggered element. There's no other way. Correct on @medelbrock

@reconbot
Copy link

While it would be very nice to have chosen behave like a browser widget, I agree this should be considered a feature not a bug. Can we currently set a max height?

@tompaton
Copy link

tompaton commented Aug 2, 2011

@veloper: I gave that a go (as best I could) and it didn't seem to help. I can't see how it would work either, as the div.chzn-drop is still contained in the dialog, so will be clipped regardless of whether it is absolutely positioned or not.

The only way to stop that is going to be to pull the div.chzn-drop out of the dialog and make it a child of <body>, but as everyone is pointing out, that is a bigger change than anyone is willing to get their hands dirty trying.

@tompaton
Copy link

tompaton commented Aug 5, 2011

Unfortunately using overflow:visible isn't an option, the dialog needs to be scrollable if necessary.

@chris-herring
Copy link

I think I've solved the issue by setting the drop down position to absolute and whenever showing the drop down setting it's position.
e.g. Changing (editing the javascript)

this.dropdown.css({
    "top": dd_top + "px",
    "left": 0
});

to

var parent = this.dropdown.parent();
var offset = parent.offset();
dd_top = offset.top + parent.outerHeight();
dd_width = parent.width();
this.dropdown.css({
    "top": dd_top + "px",
    "left": offset.left,
    "width": dd_width + "px"
});

@Polemarchus
Copy link

I'm running into this problem myself while trying to make Chosen work inside a Wijmo / jQuery UI Dialog. I may be way out of my league here, but isn't there a fairly simple fix of making the "dropdown" portion have "display: none" while hidden, and then "display: block" when shown? You'd still incur the scroll bars when the dropdown is open, but that's probably better than having the scroll bars always present.

@levushka
Copy link

levushka commented Sep 5, 2011

The fix (tested in Chrome 13, Firefox 7 and IE 9) :

In chosen.css:

.chzn-container .chzn-drop {
position: fixed;
}

and in Chosen.prototype.results_show

var offset = this.container.offset();
this.dropdown.css({
"top": (offset.top+dd_top) + "px",
"left": offset.left + "px",
"display": "block"
});

http://img30.imageshack.us/img30/4094/chosen3.png

@tompaton
Copy link

tompaton commented Sep 5, 2011

That's the stuff, good thinking @levushka. Resolved now in my branch: tompaton@fda0705

@tompaton
Copy link

tompaton commented Sep 6, 2011

Ok, it's a little more complicated than that. The above fix didn't work if the page was scrolled.

I've updated my repo with a changeset that sort of fixes it, the dropdown is positioned correctly now, but if the page is scrolled while the dropdown is visible it doesn't move as expected. That's annoying, but not a show stopper.

@jokeyrhyme
Copy link

iOS 5 might solve this, but iOS currently doesn't support position: fixed in the same way that desktop browsers do. Chosen works terrifically on the desktop, but this might limit its uses on poorly designed mobile browsers...

I'm not just picking on Apple here, older version of Android also lack support for position: fixed.

@jokeyrhyme
Copy link

As of jQuery 1.7 (not yet released, but in release candidate) they have a built-in test for CSS Position Fixed support:
http://bugs.jquery.com/ticket/6809

Might be worth detecting jQuery 1.7 and using their result, or copying their code and getting a separate result otherwise.

@fluxsaas
Copy link

fluxsaas commented Nov 9, 2011

+1 for position at the end of body element.

check the jquery widget "autocomplete". pretty good solution for that problem:

http://jqueryui.com/demos/autocomplete/

great plugin by the way.

@frostyoni
Copy link

I had this issue mostly in webkit browsers. IE just goes mental with chosen, so i disabled it if ie. Using jquery, i check if the browser is a webkit one, and adjust the overflow of the div containing my chosens like so:

if($.browser.webkit) $(this).css("overflow",($(this).is(":visible"))?"visible":"hidden");

where this is the div containing the chosens.

@JonoB
Copy link

JonoB commented Mar 7, 2012

+1 @levushka and @tompaton Not perfect, but good enough-ish. Barely :)

@Evandar276
Copy link

@levushka solution is great, but it is global ... so at window.top when you scroll down and click to chosen, it roll down in wrong position. So here is solutuion for normal pages and popup windows

in Chosen.prototype.results_show

replace:

  this.dropdown.css({
    "top": dd_top + "px",
    "left": 0
  });

with:

if($('.popup').length!=0) {

  var offset = this.container.offset();
  this.dropdown.css({
    "top": (offset.top+dd_top) + "px",
    "left": offset.left + "px",
    "display": "block"
  });

} else {

  this.dropdown.css({
    "top": dd_top + "px",
    "left": 0
  });

}

CSS:

   .popup .chzn-container .chzn-drop { position:fixed; }

If you are using jQuery UI or something else, you can have problems with z-index, so set chosen z-index to higher values (jQuery UI is it 1010+)

Now it is wokring in FF and for Chrome you need:

     .popup { overflow-x:visible; overflow-y:visible; }

lover elements can have overlow:hidden with no problems.

@bettysteger
Copy link

@chassq hmm your solution doesn't work for me, .. see this screenshot:

image

I have a div around the chosen selects with

  max-height: 200px;
  overflow-y: auto;
  overflow-x: hidden;

@bettysteger
Copy link

Thanks to all which already gave the solution with position: fixed

Here is a jsfiddle with the solution (overwrites chosen CSS classes):
http://jsfiddle.net/jwbL8utx/1/ ;)

I still have 1 problem, when scrolling down (using max-height) the chosen has an offset, as you can see here when scrolling down and opening the second chosen:

http://jsfiddle.net/jwbL8utx/2/

@typologist
Copy link

This is how I solved it:

http://jsfiddle.net/0w4a4dq5/1/

This fix doesn't require you to change any other elements besides the chosen menu itself. You'll notice It hides the menu again if you 'un-hover' it, but this is as per my requirement. If you want to keep it on top all the time, you can bind a scroll event to your div container and trigger the 'chosen:close.chosen' event.

@gradatz
Copy link

gradatz commented Jun 23, 2016

@typologist Thanks for your excellent solution.
There are two minor bugs in your JS I would like to mention though:
In line 51, it should be

'top': y - $(document).scrollTop()

otherwise the popup can be displaced under certain conditions

In line 23, instead of using

$('.chosen-container')

to bind the events, I think it would be better to use

$chosenSelect.next('.chosen-container')

in order to avoid multiple binds if the function is called more than once with different chosen() Widgets to fix.

@danhnguyeen
Copy link

please tell me is there any solution for Chosen v1.4.2?

@AgelxNash
Copy link

.chosen-container.chosen-with-drop .chosen-drop {
    position: relative;
}

@SaqibQhan
Copy link

SaqibQhan commented Nov 18, 2016

overflow-y: visible

Add this to the parent div which is containing the layout. In my case it was a Modal dialog sub div which had overflow-y: auto and replacing it with overflow-y: visible worked for me.

@rchaserr
Copy link

Is there a solution to this problem yet?

@jSerenity
Copy link

This project have your response:
http://jsbin.com/finufihaji/edit?html

<style> .table-responsive.foo { overflow-x: visible !important; overflow-y: visible !important; } </style>

Looking for a little and doing tests is the most basic solution.

@CJX3M
Copy link

CJX3M commented Jul 7, 2017

I had to override the .chosen-drop and .chosen-results and set a fixed height to both in order that all options as selectable and not affected by the parent div overflow directive

At least this works for me and most of my chosen field only have 3 or 4 options. Only 1 (the one being hidden) has around 12 and can grow in the near future.

@doowruc
Copy link

doowruc commented Aug 2, 2018

I applied the following to the parent div that had the overflow: hidden

.profile-content { /* Hack to stop profile-content from cropping Chosen dropdown */ padding-bottom: 100px; margin-bottom: -100px; }

Source: Stack Overflow

@shlgug
Copy link

shlgug commented Sep 14, 2018

@doowruc Great hack!

@mcarpenterjr
Copy link

Is there a method for attaching the chosen dropdown to a specific target, so we could attach it to the document body instead of a dialog? this way chosen flows out of the dialog and is not contained by it?

@GitSahib
Copy link

GitSahib commented Sep 4, 2019

.ui-dialog-content{
    overflow:visible !important;
 }

Worked for me.

@philayres
Copy link

I know that I was still struggling with this. Here is a Fiddle that shows an option for moving the element into the body and setting absolute positioning reliably, even with scrolling.

https://jsfiddle.net/phil_ayres/gvn8bkaL/

@R1p8p8e8r
Copy link

https://github.com/R1p8p8e8r/chosen
I think my solution will help you

@Xinatorus
Copy link

If anyone is still looking for fixed position solution, here is mine. Also works if parent is fixed.
Only thing missing is repositioning dropdown while scrolling.

.chosen-container .chosen-drop {
    position: fixed;
    top: auto;
    left: auto;
    bottom: auto;
    right: auto;
    z-index: 110;
    width: 100px;
}

In chosen.jquery.js add folowing into Chosen.prototype.results_show after first if...

var { left: left, top: top } = this.container[0].getBoundingClientRect();
this.dropdown.width((this.container.width() - 2) + 'px');
this.dropdown.css({top: this.container.height() + top + 'px', left: left + 'px'});

...so it looks like this

Chosen.prototype.results_show = function() {
    if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
        this.form_field_jq.trigger("chosen:maxselected", {
            chosen: this
        });
        return false;
    }

    const { left: left, top: top } = this.container[0].getBoundingClientRect();
    this.dropdown.width((this.container.width() - 2) + 'px');
    this.dropdown.css({top: this.container.height() + top + 'px', left: left + 'px'});

    this.container.addClass("chosen-with-drop");
    this.results_showing = true;
    this.search_field.focus();
    this.search_field.val(this.get_search_field_value());
    this.winnow_results();
    return this.form_field_jq.trigger("chosen:showing_dropdown", {
        chosen: this
    });
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests