Monday, November 12, 2007

IE, select, z-index: танцы с бубном

Сегодня столкнулся с офигенной корявостью Эксплорера. Задача, как казалось была тривиальной: надо было в начале загрузки файлов на сервер закрыть экран полупрозрачной пеленой, чтобы пользователь не тыкал куда не надо. Решение, упрощенно, было такое: создавался div с "position: absolute", покрывающий рабочую область, затем он выдвигался вперед за счет z-index, и устанавливалась прозрачность. Потом, при завершении загрузки элемент скрывался. Все бы не чего, но Internet Explorer, как обычно отличился. Наблюдался обалденный эфект, через "пелену" выступали все элементы select. Их невозможно было задвинуть на задний план при помощи изменения значения z-index.

Суть проблемы заключается в том, что IE по-особому работает с z-index. Он считается в пределах одного контейнера, а если элементы принадлежат разным контейнерам, то их z-index никак не будет пересекаться. Я перерыл кучу топиков в поисках решения проблемы, в основном советовали просто поместить элементы в один контейнер и расставить им нужный z-index, но этот вариант мне не подходил, так как эти элементы располагались в разных местах документа и никак не зависели друг от друга.

Спустя около четырех часов копания, я наткнулся на сногсшибательное решение! Это просто магия, шаманство, танцы с бубном. Как до такого решения можно дойти самостоятельно я не представляю, это надо перелистать весь MSDN как минимум! Вот так должен выглядеть ваш div, чтобы никакие select'ы в Эксплорере не пролезали через него:

<style>
.select-free {
position:absolute;
z-index:10;/*any value*/
overflow:hidden;/*must have*/
width:33em;/*must have for any value*/;
}
.select-free iframe {
display:none;/*sorry for IE5*/
display/**/:block;/*sorry for IE5*/
position:absolute;/*must have*/
top:0;/*must have*/
left:0;/*must have*/
z-index:-1;/*must have*/
filter:mask();/*must have*/
width:3000px;/*must have for any big value*/
height:3000px/*must have for any big value*/;
}
</style>
<div class="select-free">
your content here
<!--[if lte IE 6.5]><iframe></iframe><![endif]-->
</div>


Ребята с HedgerWow.com, респект вам и уважуха!

24 comments:

Anonymous said...

Только нужно осторожно использовать размер ифрейма. Если тупо как в примере - 3000px Х 3000px, то IE6 у клиента при отображениии вашей страницы отъест 90 мб. Если ифреймов несколько, то на машине с не очень большой памятью начнуться жуткие тормоза при отображении вашей страницы.

Satyrius said...

Обязательно учту. Большое спасибо!

Anonymous said...

Вместо 3000px можно написать 100% и памяти меньше жрет, и зависит уже от размера окна браузера.

Anonymous said...

А создать новый div через DOM с document.body как родительской веткой не вариант?
или я что-то не допонял?

Satyrius said...

Я уже не помню какие варианты я пробовал, чтобы решить эту проблему. Долго мучился, нашел вот этот вариант, он-то меня и спас.

Aleksey said...

Предыдущий пост был мой.
Я с таким эффектом столкнулся когда хотел сделать хинт над некоторыми словами. Казалось бы что сложного сделать скрытый div рядом со словом, а при наведении мыши его показать... сволочь ie с упорством прорисовывал картиночки с других div'ов поверх хинта. плюнул написал:
«body»«div id="hint"»«/div»...
...
«span onmouse...»Слово«/span»«div class="hidden"»Подсказка«/div»
...
«/body»
над нужным словом show_hint + position + hint.innerHTML=hidden.innerHTML
работает везде, результатом доволен.

Satyrius said...

А над элементами select нормально все?

Aleksey said...

На странице с хинтами у меня не было элементов select. про них не знаю, но раз у тебя они вылезали, то не вижу причины почему бы они у меня не вылезли.

Aleksey said...

А, кажется, до меня дошёл твой последний вопрос. Ты наверно не внимательно посмотрел мой пост: в результате всплывает div c id="hint" а ему передаётся текст из скрытого дива. а т.к. id="hint" имеет родителя body, то при z-index > других элементов на странице, он всегда наверху.

Aleksey said...

<html>
<body><style type="text/css">
.hint {
display: none;
}
#hint {
background: #FFFFE1;
border: 1px solid #AAAAAA;
margin-top: 1em;
margin-left: 1em;
opacity: 0.85;
* filter:alpha(opacity=85);
padding: 3px;
position: absolute;
text-align: left;
visibility: hidden;
width: 330px;
}
.h {
color:red;
}
</style>
<script type="text/javascript">
NS = ((navigator.appName=="Netscape") || (navigator.appName=="Opera")) ? true : false;
hint = false;
function show_hint(sender, hint_id, visible)
{
if (!hint)
hint = document.getElementById('hint');

if (visible)
{
var _hint = document.getElementById(hint_id);
hint.innerHTML = _hint.innerHTML;
attach_event(sender, 'mousemove', move_hint);
hint.style.visibility = 'visible';
}
else
{
hint.style.visibility = 'hidden';
hint.innerHTML = '';
detach_event(sender, 'mousemove', move_hint);
}
return true;
}

function move_hint(event)
{
hint.style.left = (NS ? event.pageX : event.x) + 'px';
hint.style.top = (NS ? event.pageY : event.y + document.documentElement.scrollTop + document.body.scrollTop) + 'px';
}

function attach_event(sender, event, func)
{
if (sender.addEventListener)
return sender.addEventListener(event, func, false);
else
return sender.attachEvent('on'+event, func);
}

function detach_event(sender, event, func)
{
if (sender.addEventListener)
return sender.removeEventListener(event, func, false);
else
return sender.detachEvent('on'+event, func);
}
</script>
<div id="hint"></div>
<p>Текст Текст Текст <span class="h" onmouseout="show_hint(this, 'hint1', 0)" onmouseover="show_hint(this, 'hint1', 1)">Текст</span><span id="hint1" class="hint">Подсказка1</span> Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст</p>
<p>Текст Текст Текст <span class="h" onmouseout="show_hint(this, 'hint2', 0)" onmouseover="show_hint(this, 'hint2', 1)">Текст</span><span id="hint2" class="hint">Подсказка2</span> Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст</p>
<p>Текст Текст Текст <span class="h" onmouseout="show_hint(this, 'hint3', 0)" onmouseover="show_hint(this, 'hint3', 1)">Текст</span><span id="hint3" class="hint">Подсказка3</span> Текст Текст Текст Текст Текст Текст Текст Текст Текст Текст</p>
</body>
</html>

Aleksey said...

Решил не разглагольствовать, а выдернуть код и отправить. Понравится оставь, не понравится - удали. Если будут вопросы - отвечу только завтра.

SatiriK(rus) said...

Для данной проблемы можно использовать библиотеку mootools.net .Весит граммы, а может сделать много полезных эффектов.
Только надо будет вынимать искусственно id дочерних элементов, если такие имеются.
Код будет выглядеть так:
//устанавливает прозрачность
new Fx.Style('tvoj_id','opacity').start(1,0.2);
//убирает прозрачность
new Fx.Style('tvoj_id','opacity').start(0.2,1);

А проще всего вынести этот div вперед всего кода до закрытия body - он будет отображаться как верхний слой.
Задать ему абсолютное положение и ширину\высоту - 100%, а там уже играться с яваскриптом.

Satyrius said...

Спасибо, SatiriK(rus). Попробую ваши рекомендация, как подвернется удобный случай.

Anonymous said...

Aleksey
если в Вашем коде некоторые слова "Текст" заменить на, скажем:
<select><option>qwer</option></select>
то, получается, суть вопроса этот код не решает...

Anonymous said...

Делаю немного по другому. просто прятаю селекты, когда надо показать див, а потом обратно ставлю им видимость.

Eugene Lamskoy said...

Огромное спасибо, как раз то что нужно! Писал аяксовый чат и столкнулся с проблемой двиганий окошек поверх основного контента сайта.

Lilli said...

This is great info to know.

Марина said...

Спасибо большое! Select-ы попрятались сразу под дивом!

Илья 'Зайко' Зыкин aka Killich said...

Спасибо! действительно помогло. теперь справиться бы с дрожанием блока. дергаться он стал. посмотрю у Темы Лебедева, вродь там что то было.
Только мин 10 потратил на обдумывание что и как работает.

НО ГЛАВНОЕ - ТЫ ОЧЕНЬ ПОМОГ!
ЕЩЕ РАЗ СПАСИБО!

compass said...

Превеликое спасибо! Великое спасение для маленьких всплывающих окошек :-)

Anonymous said...

Хотел уже просто прятать все select-ы:
$$('select').each(function(elt){
elt.style.display = 'none';
});
но погуглил "select z-index ie" и нашел решение )

// kirilloid

Anonymous said...

Хе-хе. Сейчас открыли оригинальный пример у коллеги — не работает. Хотя у него такая же версия IE, как и у меня:
6.0.2900.2180.xpsp_sp2_rtm.040803-2158

В общем, воспользуемся проверенным mootools-ом.

// снова kirilloid

Anonymous said...

Категорически благодарен автору. Угробил два часа на поиски решения пока не наткнулся на эту статью. Правда и с этим пришлось поморочиться, прикрутив к своим условиям. Я немного изменил код, т.к. у меня не полное закрывание экрана дивом, а всплывающая подсказка (соответственно, пришлось прописывать размеры).
У меня IE6.0.2900.2180.xpsp_sp2_rtm.040803-2158 Так же в 9 опере и фаерфоксе 3.5 пробовал, всё ок. А вообще, извиняюсь, может ссылки запрещены, но вот тут dynarch.com/mishoo/calendar.epl календарь при его перемещении умеет скрывать находящиеся под ним элементы... ессно, с выключенными скриптами не работает =) так-что решение с чистым css имеет право жить. Спасибо.

Anonymous said...

I found this site using [url=http://google.com]google.com[/url] And i want to thank you for your work. You have done really very good site. Great work, great site! Thank you!

Sorry for offtopic