Примечание: это предложение, которое я недавно написал для Yahoo. Он был отредактирован для внешней аудитории.
Порядок, в котором дерево рендеринга нарисовано на холсте, описывается в терминах стековых контекстов.
Ситуация усложняется, когда авторы не знакомы с контекстами стекирования страницы или просто не замечают своего состояния.
TL: DR; Предложение — Демо
Руководство по интерактивному рекламному бюро z-index
С точки зрения IAB все довольно просто. У них есть целая таблица, в которой указаны диапазоны z-index
практически для всех типов контента , а не только для рекламы.
Диапазон Z-индекса | Тип содержимого | Детали |
---|---|---|
<0 | Фоновые элементы | |
0 — 4,999 | Основное содержание, стандартные объявления | Стандартные рекламные теги на месте с обычным содержанием. Включает сообщение саморегулирования OBA (объявление CLEAR) |
5000 — 1 999 999 | Расширение рекламы | Весь расширяемый рекламный блок должен быть установлен в этом диапазоне |
2 000 000 — 2 999 999 | Плавающая реклама | Над страницей объявлений (OTP’s) |
3 000 000 — 3 999 999 | Всплывающие элементы | Окна чата, уведомления о сообщениях |
4 000 000 — 4 999 999 | Не закрепленные плавающие элементы | Обзорные панели набора |
5 000 000 — 5 999 999 | Расширение элементов навигации по сайту | Раскрывающаяся навигация, предупреждения сайта и т. Д. На этом уровне должна быть включена только расширяющаяся часть элементов навигации. |
6,000,000+ | Наложения на всю страницу | Полноэкранные рекламные объявления (OTP) и межстраничные объявления, если они охватывают контент страницы |
Источник: IAB Display Advertising Guidelines
Насколько большим может быть z-index
В спецификациях CSS не указан верхний предел для z-index
существует максимальное значение из-за типа переменной, используемой для хранения этого значения (32-разрядное целое число со знаком); таким образом, ограничение в современных браузерах составляет 2,147,483,647
Несмотря на это, есть рекомендации по рекламе, которые рекомендуют использовать 2,147,483,648
Что происходит, когда используются большие значения, например, то, что я однажды нашел на странице?
<div id="fresco-thirdparty-tag" style="position: absolute;
z-index: 10000000000; display: none; top: 0; left: 0;
width: 970px; height: 250px;">
Современные браузеры рассматривают такие значения как верхний предел. Другими словами, использование 100,000,000,000
2,147,483,647
Имеет ли это какое-либо значение?
Краткий ответ: нет, это не имеет значения, один бит .
И это потому, что контексты стека являются атомарными:
Контексты стека могут содержать дополнительные контексты стека. Контекст стекирования является атомарным с точки зрения его родительского контекста стекирования; ящики в других контекстах стекирования не могут находиться между любыми из них.
Другими словами, никакое значение z-index
. Вот почему невозможно управлять стеками предсказуемым образом, не зная о дереве документа и контекстах стека на странице.
Так для чего нужны директивы z-index
На чем основаны эти рекомендации? Порядок исходного кода, а также z-порядок предков играют слишком большую роль, когда дело доходит до рисования дерева рендеринга, поэтому простая установка диапазонов z-index
не может быть решением.
Например, если вы посмотрите на динамическую демонстрацию рекомендаций IAB Z-Index, вы увидите, что все работает хорошо, потому что они были разработаны с учетом определенного набора требований ; но на самом деле это довольно хрупкая конструкция, поскольку даже простые изменения могут потребовать переосмысления большинства стековых контекстов на этой странице.
Во-первых, представьте, что стилизуете «Заголовок» этой демонстрационной страницы с помощью position: fixed
какое значение z-index
Поскольку заголовок должен отображаться поверх «300 × 250 базовых объявлений», его z-index
2,000,000
Но обратите внимание, что все, что выше этого значения, заставляет заголовок конкурировать с «плавающими объявлениями», для которых диапазон z-index
2,000,000 - 2,999,999
Теперь представьте, что у нас есть окно поиска над левой / правой навигацией с выпадающим меню « Search Assist »; какое значение z-index
Поскольку раскрывающийся список должен отображаться поверх nav, его значение z-index
6,000,000
Но обратите внимание, что все, что выше этого значения, заставляет выпадающий список конкурировать с «Наложением полной страницы», для которого диапазон z-index
6,000,000+
Конечно, есть и вопросы, связанные с «государством». Для любого данного ящика может потребоваться, чтобы он располагался по-разному в стеке в зависимости от его поведения или поведения окружающих ящиков (выпадающие списки, всплывающие подсказки, всплывающие подсказки, расширение рекламы и т. Д.). В таких случаях значения z-index
Рецепт катастрофы
Как показывает демонстрация IAB, ящики, которые не принадлежат стеку, могут быть расположены в любом месте относительно других стеков . По этой причине управление «гранулярными» стеками требует централизации значений z-index
обязательно приведет к сбою в многопрофильной среде, где разработчики могут не иметь доступа ни к данным, ни к инструменту ( т.е. переменные в файле препроцессора ).
Предложение
Речь идет о реализации защитного механизма для управления контекстами стекирования через страницу. Нам нужно решение, которое позволит нам позиционировать блок относительно других блоков в том же стеке или даже блоков вне стека, к которому он принадлежит.
Явные контексты
Идея состоит в том, чтобы стилизовать основные блоки страницы для создания явного порядка стеков «верхнего уровня» (см. Демонстрацию ). Это использует атомарную природу контекстов суммирования и обеспечивает сдерживание на самом высоком уровне. Затем мы можем предсказать поведение вложенных блоков независимо от их собственных значений z-index
.
Динамические стеки
Когда у нас есть контексты стека верхнего уровня, достаточно переместить основной блок вверх и вниз по стеку, чтобы и его вложенные блоки перемещались через этот стек.
Возможность изменения контекста стека имеет решающее значение, потому что бывают случаи, когда блоки должны располагаться по-разному в стеке (см. «Подсказки» и «реклама» в демонстрационной версии ).
При взгляде на демонстрацию обратите внимание на число, которое отображается в черном круге в верхней части правой направляющей . Это число является значением z-index
столбца . Значение изменяется, когда пользователи взаимодействуют с элементами внутри столбца. Это изменение позволяет блокам переключаться между контекстами стеков (боксы могут перемещаться через разные стеки).
Декларативный переключатель
Мы используем атрибуты data-*
z-index
Пример кода ниже ).
Таким образом, мы можем управлять порядком блоков в стеке, ничего не зная о самой странице (ее дереве DOM или контекстах стека).
Тот же механизм можно использовать для сброса z-index
демонстрационной версии ).
Более явные контексты
Удаление блока из основного контекста стека позволяет его вложенным контекстам стекирования стать частью более высокого стека. Это означает, что z-index
Например, в демоверсии , когда запускается модальный режим, удаление правой направляющей из контекста наложения верхнего уровня позволяет объявлению конкурировать с другими основными блоками на странице. Другими словами, если бы у объявления был z-index
10+
в верхней части заголовка .
Из-за риска, связанного со сбросом z-index
z-index
Это могут быть объявления или другие модули, которые не контролируются владельцами страниц. «Песочница» этих элементов предотвращает появление ящиков в любом месте на оси «z». Таким образом, мы все еще можем контролировать эти блоки, даже если их предок стилизован с помощью z-index: auto
Чтобы лучше понять эту проблему, посетите эту демонстрационную страницу, где ни песочница, ни правая рейка, ни ее модули. Прокрутите страницу немного и наведите указатель мыши на объявление. Вы должны увидеть объявление, перекрывающее заголовок и «кнопку» для модального окна, просматривающего объявление.
Обе проблемы связаны с идентичными значениями z-index
Заголовок отображается за объявлением, потому что оно идет первым. Модальная кнопка отображается перед рекламой, потому что она идет последней.
Реализация
Это решение требует совместного использования простой настройки и общего словаря между сетками (когда задействованы различные сетки, как, например, для сайтов Yahoo — Финансы, Спорт, Домашняя страница, Ответы и т. Д.).
«Четырехступенчатая программа»:
- Все основные поля на странице должны располагаться и иметь стиль с
z-index
auto
- Каждый из этих блоков должен быть идентифицирован с помощью общего класса:
stacking-context
- Эти же блоки должны иметь
data-zindex-max
data-zindex-top
z-index
- Класс
inner-stack
любого модуля, который может быть стилизован с высоким значениемz-index
Например:
<div id="right-rail" class="stacking-context"
data-zindex-max="5" data-zindex-top="10">
<div class="inner-stack">
<div id="fresco-thirdparty-tag"
style="position: absolute; z-index: 10000000000;">
Данные-ZIndex-макс
Этот атрибут используется для объявления наивысшего z-порядка, с которым допускается стилизовать блок. Например, это может быть столбец, который должен всегда отображаться за заголовком.
Данные-ZIndex-топ
Этот атрибут используется для объявления самого высокого z-порядка, установленного на странице. Например, это будет позиция заголовка внутри стека. Любой элемент, стилизованный под это значение z-index
.inner-стек
Этот класс используется для контроля модулей, предотвращая вступление в действие их собственного z-index
Это значение z-index
Преимущества этого решения
Снижает риск поломки
Используя атомарную природу контекстов стекирования, мы можем изолировать модули-песочницы, делая их значения z-index
Это предсказуемо
Нет больше угадайку; авторам не нужно ничего знать о дереве документа или его контекстах суммирования, чтобы иметь возможность перемещать блоки через стеки.
Централизует обязанности
Все находится в руках команды, ответственной за саму страницу — команды, которая знает все о документе — его дереве, его стековом контексте и т. Д.
Дальнейшее мышление
В проектах, которые используют одну сетку, а также в проектах, которые используют общую сетку, вещи можно сделать более декларативными с помощью предустановки правил для замены z-index
Например:
-
.coverTheHeader {...}
-
.coverAllColumns {...}
-
.coverTheRightRail {...}
-
.coverTheLeftRail {...}
-
.coverTheMainContent {...}
- и т.п.
Пример кода
Ниже приведен код JavaScript, используемый на главной демонстрационной странице . Этот скрипт отвечает за переключение значения z-index
Он также «освобождает» эти элементы, сбрасывая значение z-index
Именно сочетание обоих этих стилей позволяет этим элементам вести себя так, как ожидается, даже если к ним применяется очень высокий z-index
(function(document) {
function findAncestor(el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el;
}
// constants
var AUTO = 'auto',
CSS_MODAL_ON = 'modal-on',
CSS_INNER_STACK = 'inner-stack',
DOC = document,
WIN = DOC.defaultView,
HTML = DOC.documentElement,
// elements
theAd = DOC.getElementById('ad'),
theAncestorStack = findAncestor(theAd, 'stacking-context'),
theInnerStack = DOC.getElementsByClassName(CSS_INNER_STACK)[0],
theModal = DOC.getElementById('modal'),
theStackUpdate = DOC.getElementById('stackUpdate'),
// globals
theInnerStackAncestor,
zIndexAncestor = WIN.getComputedStyle(theAncestorStack, null).zIndex,
zIndexCurrent, // will be assigned
zIndexInnerStack = WIN.getComputedStyle(theInnerStack, null).zIndex,
zIndexMax = theAncestorStack.getAttribute('data-zindex-max'),
zIndexTop = theAncestorStack.getAttribute('data-zindex-top');
function switchStackingContext (e) {
// we move the ancestor through the stack according to zIndexMax value (highest value allowed for that ancestor box)
if (WIN.getComputedStyle(theAncestorStack, null).zIndex === zIndexMax) {
theAncestorStack.style.zIndex = zIndexAncestor;
} else {
theAncestorStack.style.zIndex = zIndexMax;
}
// we get the ancestor that wraps boxes with potential high/crazy z-index
theInnerStackAncestor = findAncestor(e.target, CSS_INNER_STACK);
// we check for the actual value before we change it
zIndexCurrent = WIN.getComputedStyle(theInnerStackAncestor, null).zIndex;
// we reset the z-index from the parent ancestor allowing the box to move up (wherever it wants to)
if (zIndexCurrent !== AUTO) {
theInnerStackAncestor.style.zIndex = AUTO;
} else {
theInnerStackAncestor.style.zIndex = zIndexInnerStack;
}
// we update the value on the page
theStackUpdate.innerText = theAncestorStack.style.zIndex;
}
function resetStackingContext (e) {
// we reset the z-index of the ancestor to free the inner box
if (WIN.getComputedStyle(theAncestorStack, null).zIndex === AUTO) {
theAncestorStack.style.zIndex = zIndexAncestor;
} else {
theAncestorStack.style.zIndex = AUTO;
}
// we get the ancestor that wraps boxes with potential high/crazy z-index
theInnerStackAncestor = findAncestor(e.target, CSS_INNER_STACK);
// we check for the actual value before we change it
zIndexCurrent = WIN.getComputedStyle(theInnerStackAncestor, null).zIndex;
// we reset the z-index from the parent ancestor allowing the box to move up (wherever it wants to)
if (zIndexCurrent !== AUTO) {
theInnerStackAncestor.style.zIndex = AUTO;
} else {
theInnerStackAncestor.style.zIndex = zIndexInnerStack;
}
// we toggle this class to contextually style the modal (nothing to do with the solution per se)
HTML.classList.toggle(CSS_MODAL_ON);
// we update the value on the page
theStackUpdate.innerHTML = theAncestorStack.style.zIndex;
}
theAd.addEventListener('mouseenter', switchStackingContext, false);
theAd.addEventListener('mouseleave', switchStackingContext, false);
theModal.addEventListener('click', resetStackingContext, false);
}(document));
Для справки ниже приведены две демонстрационные ссылки, упомянутые в статье. Первый (упоминаемый в статье несколько раз) — это JavaScript, который «управляет» стеком, когда пользователи взаимодействуют с рекламой или «модальным». Второй тоже самое без сценария. Он включен, чтобы показать проблемы, с которыми мы столкнулись бы, если бы полагались на третьих лиц для управления стеками.