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'+newDate().valueOf(),/* устанавливаем свойство "layer" для ссылки на данный слой */this.iframe.layer =this,/* создаём функцию обновления (важно для IE 6.0) */this.iframe.func =newFunction("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/
Комментариев нет:
Отправить комментарий