How to solve the select overlap bug in IE6? - html

When using IE, you cannot put an absolutely positioned div over a select input element. That's because the select element is considered an ActiveX object and is on top of every HTML element in the page.
I already saw people hiding selects when opening a popup div, that leads to pretty bad user experience having controls disappearing.
FogBugz actually had a pretty smart solution (before v6) of turning every select into text boxes when a popup was displayed. This solved the bug and tricked the user eye but the behavior was not perfect.
Another solution is in FogBugz 6 where they no more use the select element and recoded it everywhere.
Last solution I currently use is messing up the IE rendering engine and force it to render the absolutely positioned <div> as an ActiveX element too, ensuring it can live over a select element. This is achieved by placing an invisible <iframe> inside the <div> and styling it with:
#MyDiv iframe
{
position: absolute;
z-index: -1;
filter: mask();
border: 0;
margin: 0;
padding: 0;
top: 0;
left: 0;
width: 9999px;
height: 9999px;
overflow: hidden;
}
Does anyone have an even better solution than this one?
EDIT: The purpose of this question is as much informative as it is a real question. I find the <iframe> trick to be a good solution, but I am still looking for improvement like removing this ugly useless tag that degrades accessibility.

I don't know anything better than an Iframe
But it does occur to me that this could be added in JS by looking for a couple of variables
IE 6
A high Z-Index (you tend to have to set a z-index if you are floating a div over)
A box element
Then a script that looks for these items and just add an iframe layer would be a neat solution
Paul

Thanks for the iframe hack solution. It's ugly and yet still elegant. :)
Just a comment. If you happen to be running your site via SSL, the dummy iframe tag needs to have a src specified, otherwise IE6 is going to complain with a security warning.
example:
<iframe src="javascript:false;"></iframe>
I've seen some people recommend setting src to blank.html ... but I like the javascript way more. Go figure.

As far as I know there are only two options, the better of which is the mentioned usage of an iframe. The other one is hiding all selects when the overlay is shown, leading to an even weirder user experience.

try this plugin http://docs.jquery.com/Plugins/bgiframe , it should work!
usage: $('.your-dropdown-menu').bgiframe();

I don't think there is. I've tried to solve this problem at my job. Hiding the select control was the best we could come up with (being a corporate shop with a captive audience, user experience doesn't usually factor into the PM's decisions).
From what I could gather online when looking for a solution, there's just no good solution to this. I like the FogBugz solution (the same thing done by a lot of high-profile sites, like Facebook), and this is actually what I use in my own projects.

I do the same thing with select boxes and Flash.
When using an overlay, hide the underlying objects that would push through. It's not great, but it works. You can use JavaScript to hide the elements just before displaying an overlay, then show them again once you're done.
I try not to mess with iframes unless it's absolutely necessary.
The trick of using labels or textboxes instead of select boxes during overlays is neat. I may use that in the future.

Mootools has a pretty well heshed out solution using an iframe, called iframeshim.
Not worth including the lib just for this, but if you have it in your project anyway, you should be aware that the 'iframeshim' plugin exists.

There's this simple and straightforward jquery plugin called bgiframe. The developer created it for the sole purpose of solving this issue in ie6.
I've recently used and it works like a charm.

When hiding the select elements hide them by setting the "visibility: hidden" instead of display: none otherwise the browser will re-flow the document.

I fixed this by hiding the select components using CSS when a dialog or overlay is displayed:
selects[i].style.visibility = "hidden";
function showOverlay() {
el = document.getElementById("overlay");
el.style.visibility = "visible";
selects = document.getElementsByTagName("select");
for (var i = 0; i < selects.length; i++) {
selects[i].style.visibility = "hidden";
}
}
function hideOverlay() {
el = document.getElementById("overlay");
el.style.visibility = "hidden";
var selects = document.getElementsByTagName("select");
for (var i = 0; i < selects.length; i++) {
selects[i].style.visibility = "visible";
}
}

Related

Is there any other way to fix this problem besides using !importand after every line css

I'm currently working on an online code editor. (like jsfiddle codepen etc...)
I got everything working, but I ran into one problem; If a user does something like this:
button {
background-color: red;
}
It also changes the properties of my "run code" and "reset" button I made.
same thing with other things like a div;
div {
padding: 500em;
}
because this will also change the div's Im using in my own code.
I fixed the issue using !importand tags after every line in my css but I'm wordering if there is any other way to fix this? or is !importand really the only way.
As said in the comment by CBroe. To do this you can use iframe.
A more original solution would be to create a web component with a shadow root (which isolate the style too). The support for this is not too bad even if it's fairly new :
But, I've used it myself and it's a little bit harder to understand at first

Bringing a HTML element to front with z-index on overflow in CSS

I am trying to get the blue rectangle container to have a larger z-index than the other boxes when hovering over elements that overflow the container.
Game 3 here has the larger z-index, but I want to access the Loser select in the blue circle below, however I can't, unless I hover back over the blue rectangle to gain focus.
Is there a way around this where it can be handled with just CSS or do I need JQuery?
I created a Fiddle that can replicate this so ignore any JS errors as the actual page requires quite a bit of includes, however the issue is in tact. Hover over the 4th game which has three dropdowns, Source, Pools, Seeds. You can select Seeds just fine. However, hover over another game at the top then come back down to "Seeds", you can't select it unless you hover over "Pools" again. I need "Seeds" to always be selectable regardless of what the overflow is.
https://jsfiddle.net/cblaze22/qp4L15tj/8/
Current Code For Game Hover (Blue Rectangle area)
The .forward puts a large zindex on the blue rectangle area.
$(element).hover(
function () {
if (!$(this).parent().hasClass('editing')) {
$(this).addClass('forward');
}
},
function() {
$(this).removeClass('forward');
}
);
This was actually a surprisingly easy fix once you understood the structure and the actual problem. Div's covering div's. First you disable all click events on everything within .bracket-part as they aren't needed. Then you add the click events back onto the selects. To make it more generic for easier use again you can simple change select in the CSS selector a class .re-enable-events or something. The JS about z-index's wasnt actually needed.
#bracket-wrapper .bracket-part select {
pointer-events: all !important;
}
#bracket-wrapper .bracket-part {
pointer-events: none;
}
See: https://jsfiddle.net/uws8pf1y/
Pointer events has a very good compatibility rate so this solution should be fine across pretty much all devices.
To get straight to the point: There is no clean CSS-only solution to your problem.
Since all your elements are pretty much identical (and by that I mean the class for example) you will not find a solution that covers all configurations. Since they do not differ from each other they all have the same z-index but not the same stacking context. Unless you give their parents a different z-index or change the stacking context you will not be able to access the blocked element. It also comes down to how limited you are with changing the code. The code looks like it has been build by JS and you just copied it to your fiddle for us to test.
Attempt #1
Attempt #1 is to just add high z-index directly to the according parent.
#mmshr already tried to do this. However, he tried to give the whole class a high z-index which is not gonna work out of course as you've already pointed out.
You could however try to only give this element a high z-index element in its style attribute. This comes down to how limited you are with changing the code. You could theoretically use JQuery for this but the way you would select the element (e.g. by nth-child()) brings me to Attempt #2 which uses the same pseudo-class and is a CSS-only attempt so using JS is nonsense in this case. By the way if you can change your code like this you could remove your little JQuery function that adds the forward class on hover.
Attempt #2
This attempt works fine and you are not limited by the ability to change code since this is pretty much one line of CSS. As already stated in Attempt #1 you could use a pseudo-class to select this element. However, this is not valid for all configurations. If you would add one element (<div data-bind="template: { name: 'bracket-template', data: $data }">...</div>) before your blocked element you would have to change your CSS each time. But if there is no need for changing elements and configurations (or at least not the order) this is a valid solution:
#bracket-wrapper > div > div:nth-child(8) > div > div {
z-index: 2 !important;
}
In this attempt you can (and have to) remove your little JQuery function too:
$('.bracket-part').hover(
function() {
debugger;
$(this).addClass('forward');
},
function() {
$(this).removeClass('forward');
}
);
Remove the entire thing.
Attempt #3
Probably the cleanest and best attempt is to use the stacking context. The stacking context is explained right here. But to give you a simple overview (W3C):
Each box belongs to one stacking context. Each positioned box in a given stacking context has an integer stack level, which is its position on the z-axis relative other stack levels within the same stacking context. Boxes with greater stack levels are always formatted in front of boxes with lower stack levels. Boxes may have negative stack levels. Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.
Most important is this part because it applies to your structure:
Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.
If you take a look at your HTML tree you will find the following:
According to the stacking-context we should be able to give your element in the background a higher stacking-order then your element in the front by changing the order of those elements in your tree.
It is just a guess but you probably have something like an array where you store the data and some JS-file builds a tournament bracket out of it. If you could somehow change the order of those two elements (for example by changing the order of your array) you would not use CSS and would not use any additional JQuery.
What if none of these work?
Well, then I do not see any solution that requires only CSS.
I also thought about a possible JS solution but this is a tough one and I couldn't figure out a (simple) solution. Let me explain the problem:
Since your select is behind a div element JQuery would not recognize it (e.g.) on hover so you would have to use pseudo-classes again which I already covered with a CSS-only attempt.
I also thought about adding a z-index of -1 to the blocking element, because JQuery could recognize it on hover. But this leads to problems too: the blocking element is now in the background and the blocked element in the front and you can also click it. The problem is that the (former) blocking element is now behind the #bracket-wrapper. This is also not a valid solution because you would have to use a pseudo-class again to target this specific element.
Conclusion
I am gonna be honest with you: This tournament tree is poorly designed and structured. There shouldn't be overlapping elements or elements outside of a container and certainly not both in combination. If none of my attempts are suitable I do not see any CSS or JS solution. At least not a simple one. You have provided little information about how the tournament tree is build but things could change if you do.
At this state I think rebuilding this whole structure is the only really clean solution.
Edit
Solution #1 by #Deckerz
#Deckerz provided a great solution which does not focus on the z-index. Instead, it uses pointer-events. I tried this approach but failed because I forgot an important part. The logic behind it is simple:
First you disable all click events on everything within .bracket-part as they arent needed. Then you add the click events back onto the selects. To make it more generic for easier use again you can simple change select in the CSS selector a class .re-enable-events or something. The JS about z-index's wasnt actually needed.
#bracket-wrapper .bracket-part select {
pointer-events: all !important;
}
#bracket-wrapper .bracket-part {
pointer-events: none;
}
However, this is still a workaround. I still recommend restructuring your code and CSS.
If you want Seeds to always be selectable, why not always give it's bracket-part parent a high z-index?
Right now, the z-index is only high after the bracket-part is hovered. Although Seeds is technically a child of the bracket-part, it is positioned outside of it, so unless the Seeds select is hovered directly after bracket-part is hovered then it won't be selectable.
If you add z-index: 10000; to Seeds' bracket-part parent styles, Seeds will always be selectable:
<div class="part bracket-part ui-draggable ui-resizable ui-draggable-disabled ui-state-disabled" data-bind="bracketPartInit: { left: $data.left, top: $data.top, height: $data.height, width: $data.width, disabled: $root.members.bracket.disableDrag, minHeight: $data.minHeight }, css: { 'dash-top' : $data.dashedBorderTop(), 'dash-right' : $data.dashedBorderRight(), 'dash-bottom' : $data.dashedBorderBottom(), 'dash-left' : $data.dashedBorderLeft(), 'reverse-bracket' : $data.type() == 2, 'box-bracket': $data.type() == 13, 'bye': $data.bye()}" aria-disabled="true" style="top: 459px; left: 0px; height: 80px; width: 150px; z-index: 10000;">

Which css style has least effect on an element?

Today I was trying to create a dummy css rule for testing and investigation.
.dummy {
some-style : somevalue;
}
Ideally the class should have no visible effect. I want to be able to apply the class to elements but cause the least visible effect possible on any elements it is applied to. For example
<div class="dummy"> should look and behaves as much as possible like <div>
I did not want the class to be empty. Can anyone suggest a style that I could add to the class that would have the least visible impact when applied to a general html element? I can't think of anything completely harmless.
UPDATE: I wanted to add the style to some existing html. The reason was to use the style as a marker for diagnostic purposes. It would help me see when and where styles and stylesheets were getting loaded/cached and where and why some styles were getting overridden, sometimes by the browser defaults which seemed odd. At the time I didn't have exclusive use of the system I was working on so I wanted something that was going to be invisible to other users but I could see in Developer Tools.
UPDATE 2 : the html/css wasn't written by me and I didn't have my own environment in which to work. I was trying to investigate some problems in-situ in someone else's system. I had tried using DevTools in the browser but wasn't getting anywhere with that. I wanted to be able to make some small changes to their html/css to aid my diagnostics. I didn't want them to have any obvious effect on the system for other people (except in DevTools, viewed by me).
It was a Wordpress site and they only had two environments, one for live and one for testing. I was working with the test system. There were other people testing at the time, though mainly checking content.
The real thorny problem was why was the font-size in the calendar widget much larger than everything else on the site? Inspecting using DevTools I could see the font-size style was getting overridden by the browser default style when it seemed to me there were other css selectors that should have taken precedence. It looked bizarre. In the end it turned out to be a missing !DOCTYPE tag in the html. So nothing to do with the css itself.
I didn't like this way of working, fiddling in someone's system, but there wasn't much else to do and it did help to resolve the problem for them.
Hopefully I don't have to do this again, but ever since I have been wondering what was the most harmless style that I could have used?
I thought I would ask here as there must be people who know CSS better than me.
You can use this:
.dummy{
min-width: 0;
min-height: 0;
}
If you just need anything beeing set you could assign rules that are default anyway. For block elements like div set
.block-class { display: block; }
And for inline elements like span
.inline-class { display: inline; }
Of course it could be an issue doing so in some rare cases but in general it's quite harmless I guess.
In principle, for any property you can have an arrangement like this:
div {
some-style : a-valid-value-for-some-style;
}
.dummy {
some-style : a-different-valid-value-for-some-style;
}
And .dummy's style will have an effect, no matter what some-style is.
Your best bet is to make use of CSS variables. These are custom properties and start with a double hyphen. so
.dummy {
--dummy-style: foo;
}
will make --dummy-style a property with value "foo". So long as you don't employ the variable as the value in another property, it will have no visible effect.

Issue with click-drag-select in text input field also scrolls parent element, webkit bug or feature?

There's a weird behavior that I've been experiencing with only the webkit browsers since last year, and it is driving me nuts.
I've tried doing searches on this, but I don't seem to be able to hit the keywords relating to this issue.
I have a html structure as below:
<div style="border: 1px solid #000; width:200px;height:200px; overflow:hidden;position:relative">
<div style="width:200px;position:absolute">
<p>long line</p>
<p><input type="text" value=""/></p>
<p>long line</p>
</div>
</div>​
You can visit the live example in the jdfiddle link:
jsfiddle
For me, using Chrome(18), when one clicks and drag-selects text in the text input field out of the input box, you are able to "scroll" the parent element, although the CSS overflow is set to hidden.
You can try it from the fiddle by click select-dragging right, top, bottom, left. Works wonders.
More complex html structure yields more bizzare scrolling behaviors. In fact, I can almost do a slide show animation with elements sliding in and sliding out in sequence, just by drag selecting.
This behavior isn't experienced in firefox, fortunately.
Is anyone experiencing this behavior as well?
Is this supposed to be a feature of webkit?
Does anyone knows how to disable this "scrolling" behavior?
Thanks!
edit:
Thanks to #PhilipK, he has found a related post with a javascript solution answered below.
As my webpage is heavy with javascript I would like to find out if there are there any possible CSS solutions.
edit2:
Thanks to #tiffon, he found another javascript solution. His solution could be implemented in CSS (but with some limitations to mouse events, so the CSS solution is kind of incomplete).
I think abusing pointer-events: none; might be another option:
Dupe question: https://stackoverflow.com/a/13897395/1888292
http://jsfiddle.net/7CuBV/21/
So this worked for me - see here - basically listen to the onscroll event and set both scrollTop and scrollLeft to 0.
I found this problem too, after a bit of experimentation I removed an overflow:hidden from one of the parent divs (the very outer div which was scrolling), and it appears to have solved it. I wasn't using any iframes.
I know this an old thread, but I've just faced the same problem.
I created this fix:
// DISABLE INPUT DRAG SCROLL (CHROME BUG FIX)
var disableScrollDrag = false;
$('input, select, textarea').unbind('mousedown').mousedown(function(e) {
disableScrollDrag = true;
$(this).css('pointer-events', 'none').addClass('disable-scroll-drag');
});
$('body').mousemove(function() {
if (disableScrollDrag === true) {
$('.disable-scroll-drag').each(function () {
$(this).css('pointer-events', 'auto');
});
disableScrollDrag = false;
}
});
Just wrestled with this strange one for the first time. I found that if I set the width of the text field to something less-than-or-equal-to the container, the parent element didn't scroll in relation to the text input value.
The example linked to above gives the basic idea, but it's about an iframe and can be a little confusing to implement on a text input within a div, which is what I (and the original poster) were facing.
Here's what I ended up doing, using jquery;
$('body').on('select', '.my_text_input', function(e) {
$('.div_that_was_moving_weirdly').scrollLeft(0);
return false;
});
This is still imperfect, as there will be a jarring scroll over and then jump back, since the select event doesn't seem to kick in until you're done selecting. I tried various events but this is the best I could do.

Resizable frame emulation

I understand that <frameset> and <frame> tag are becoming deprecated. Is there a way to emulate resizable frames? What I want is a narrow separator separating the area either horizontally or vertically, which is movable by the user so that when one side of it becomes smaller, the other side becomes larger, and vice versa. I do not want to fill in each frame with an html page like the conventional frame, but instead with some DOM materials.
I know that CSS3 has resize attribute, but that controls only the size of itself. I am not sure if this is to be used for the solution.
I don't particularly prefer using JavaScript, but I am not excluding the possibility of using it if necessary.
Do not use frameset, please. I don't think jQuery resize will help you much, either.
The best way to do this is by using a "splitter". There are several plugins for jquery that will do this in many different way and they all are actually quite simple.
I have previously used this one: http://methvin.com/splitter/
You can find a nice demo here: http://methvin.com/splitter/3psplitter.html
From my point of view jQuery Resizable or such js things is your solution. Go for it's demos.
In case of using jQuery you'll have extra possibilities:
Maximum / minimum size
Constrain resize area
Delay start
Snap to grid
Here is a sample code for jQuery Resizable default functionality:
<style>
#resizable {
width: 150px;
height: 150px;
display: block;
border: 1px solid gray;
text-align: center;
}
</style>
<script>
$(function() {
$("#resizable").resizable();
});
</script>
<div id="resizable">
<h3>Resizable</h3>
</div>
You may like this link for YUI
http://people.ischool.berkeley.edu/~rdhyee/yui/examples/layout/panel_layout.html
Example:
http://people.ischool.berkeley.edu/~rdhyee/yui/examples/layout/panel_layout_source.html
Janus Troelsen's solution above is great if you don't mind tables.
I also found this solution by SoonDead without tables, which worked great with Chrome and FF, but had to spend a nasty amount of time for IE8. It's on StackOverflow as "Emulate Frameset Separator Behavior"
I would look into Javascript and drag and drop support.
In fact, an emulated frameset could be just two divs and a handle between them which can be grabbed to resize. JQuery has samples to demonstrate how to resize an element: http://jqueryui.com/demos/resizable/ I don't think it would be very difficult to expand that concept to fit.
Then I would load the documents via AJAX, and this could probably replace frames completely.