UPD [08.06.2009] ie-iframe-substrate 1.0.2
UPD [10.04.2009] ie-iframe-substrate 1.0.1
Введение
Как известно, Internet Explorer версий 5.5 и 6.0 содержит ошибку (aka "z-index issue"), которая заключается в том, что элементы SELECT "пробивают" любые другие элементы (например, позиционированные DIV-ы), размещённые над ними.Единственный элемент, с которым этого не происходит — IFRAME. Именно на использовании его в качестве "прокладки" и основываются все методы устранения описанной выше ошибки IE [^]. Как правило, в них применяется один из двух вариантов. Либо, IFRAME вставляется внутрь (первым потомком) необходимого элемента, делается прозрачным, и стиль
z-index
устанавливается в -1
. Либо, IFRAME добавляется в DOM, позиционируется непосредственно под необходимым элементом и делается равным ему по размеру.
При кажущейся простоте, у первого варианта два серьёзных недостатка. Во-первых, изменяются "внутренности" элемента, что может привести к конфликтам при динамической обработке контента javascript-ом. Во-вторых, "прикрыть", например, элементы с
overflow
:auto
или overflow
:scroll
весьма проблематично. Второй вариант не имеет данных недостатков, т.к. IFRAME ни коим образом не связан с элементом, который он "прикрывает". Однако, существует проблема изменения позиции или размера элемента, которым IFRAME постоянно должен соответствовать.
В описываемом ниже решении для борьбы с «просвечивающими» SELECT-ами используется второй вариант размещения IFRAME.
"IFRAME-подложка"
Теперь собственно о главном. Предлагаемое решение основано на применении javascript-expressions в CSS стилях. Используется оно следующим образом:- Скачиваем последнюю версию ie-iframe-substrate.css (~1.3 KB)
- Подключаем его на страницу при помощи тэга LINK или в любой CSS-файл при помощи
@import
- Прямо в этом же файле переписываем селекторы для элементов, которым необходима "подложка" (обязательно с
* html
).
Например:* html div
.some-layer
,* html
#someLayer
{...}
Протестировать можно вот на этих страницах: тест 1, тест 2, тест 3.
К сведению: протестированный для сравнения bgIframe (плагин для jQuery) часть приведённых выше тестов пройти не смог.
Некоторые ограничения и особенности:
- "Прикрываемый" элемент не должен использовать стиль
behavior
- У каждого "прикрываемого" элемента создаётся и используется свойство "_i" (
element._i
) - Для "IFRAME-подложки" используется CSS-класс "ie-substrate" (
iframe
.ie-substrate
)
[Скачать этот код в виде файла: ie-iframe-substrate.1.0.0.src.ru.css]/** * Селектор слоёв (позиционированных элементов), * которым нужно создать "IFRAME-подложку". */
* html div
.layer
{/* Скрываем от IE 7+ в "standards-compliant" режиме */
behavior
:expression(
/* Если документ загружен и распаршен */
document.readyState=='complete'
? (/* и браузер не IE 7+ (в "quirks" режиме) */
parseFloat(navigator.appVersion.split('MSIE'
)[1
])<7
/* и "IFRAME-подложка" ещё не создана */
&&this
.iframe==null
? (/* создаём IFRAME и вставляем его прямо перед данным элементом (слоем) */
this
.iframe =this
.parentNode.insertBefore( document.createElement('iframe'
),this
),/* устанавливаем свойство "src" (важно для HTTPS соединения) */
this
.iframe.src ='javascript:false'
,/* устанавливаем свойство "id" (для функции обновления) */
this
.iframe.id ='_ie_sub'
+new
Date
().valueOf(),/* устанавливаем свойство "layer" для ссылки на данный слой */
this
.iframe.layer =this
,/* создаём функцию обновления (важно для IE 6.0) */
this
.iframe.func =new
Function
("var iframe = document.getElementById('"
+this
.iframe.id +"'); iframe.allowTransparency=true; iframe.allowTransparency=false;"
),/* устанавливаем соответствующее имя класса */
this
.iframe.className ='ie-substrate'
,/* сбрасываем ссылку на IFRAME и устанавливаем флажок */
this
.iframe =true
,/* отключаем "behavior" для данного элемента */
this
.style.behavior ='none'
/* иначе - отключаем "behavior" для данного элемента */
) :this
.style.behavior ='none'
/* иначе - ничего не делаем */
) :null
)
; }/** * Стили для "IFRAME-подложки" */
iframe
.ie-substrate
{position
:absolute
;/* Делаем IFRAME прозрачным */
filter
:Mask()
;/* Отслеживаем позицию и размеры "прикрываемого" слоя */
behavior
:expression(
/* Если IFRAME в DOM-е (т.е. не удален) */
this
.parentNode ? (/* Если "прикрываемый" слой в DOM-е (т.е. не удален) */
this
.layer.parentNode ? (/* и IFRAME вставлен в DOM-е перед "прикрываемым" слоем */
this
.nextSibling==this
.layer ? (/* перехватываем свойства "прикрываемого" слоя */
this
.style.pixelWidth =this
.layer.offsetWidth,this
.style.pixelHeight =this
.layer.offsetHeight,this
.style.pixelLeft =this
.layer.offsetLeft,this
.style.pixelTop =this
.layer.offsetTop,this
.offsetTop>0
? (/* только если IFRAME виден */
this
.style.zIndex =this
.layer.currentStyle.zIndex,this
.style.visibility =this
.layer.currentStyle.visibility,this
.style.display =this
.layer.currentStyle.display ) :null
/* иначе */
) : (/* вставляем IFRAME перед "прикрываемым" слоем в DOM-е */
this
.layer.parentNode.insertBefore(this
,this
.layer) )/* иначе */
) : (/* удаляем IFRAME */
this
.removeNode(true
) )/* иначе - ничего не делаем */
) :null
)
;/* Обновляем IFRAME-ы периодически, чтобы решить проблему в IE 6.0 * (SELECT-ы всё ещё могут перекрывать слои после скроллинга). */
refresh
:e\xpression(
/* Скрываем от IE 5.5 */
/* Если IFRAME виден */
this
.offsetTop>0
? (/* включить обновление */
this
.timer ?null
:this
.timer = window.setInterval(this
.func,300
)/* иначе */
) : (/* выключить обновление */
this
.timer ?this
.timer = window.clearInterval(this
.timer) :null
))
; }
Достоинства:
- Простота и прозрачность в использовании
- Корректно работает с любыми элементами как в "standards-compliant", так и в "quirks" режимах, а также при любых динамических манипуляциях с "прикрытыми" элементами
- Не требует внесения изменений в ваш CSS- или javascript-код
- Небольшой объём библиотечного файла (всего 1 KB без комментариев)
- Нет привязки к каким-либо фрэймворкам
- Не оказывает никакого влияния на другие браузеры (в том числе IE 7+)
- Легко отключается не оставляя следов (например, при отказе от поддержки IE 6 или от использования SELECT-ов)
- Снижение быстродействия при увеличении количества "прикрытых" элементов
- Утечка памяти в IE 5.5 при большом количестве "прикрытых" элементов и при интенсивных манипуляциях с DOM-ом
- Некорректное позиционирование "IFRAME-подложки", если "прикрываемый" элемент имеет относительное позиционирование и расположен внутри элемента TD со значением стиля
vertical-align
отличным отtop
Ссылки по теме:
- http://docs.jquery.com/Plugins/bgiframe
- http://docs.prototype-ui.com/rc0/Util/IframeShim
- http://www.hedgerwow.com/360/bugs/css-select-free.html
- http://habrahabr.ru/blogs/webdev/21913/
- http://www.macridesweb.com/oltest/IframeShim.html
- http://rmcreative.ru/news/id/1185444438/