Видео и z-индекс внутри масштабированного элемента: некоторые divs исчезают
У меня несколько странное поведение в Chrome и Safari. У меня есть масштабированный (transform: scale()
) контейнер с видео и другими элементами внутри него. При некоторых масштабирования абсолютные позиционированные элементы с высоким z-индексом исчезают и не возвращаются снова.
Как я могу это исправить? Обратите внимание: я не могу дать элементу видео отрицательный z-индекс, и мне нужно использовать overflow: hidden;
,
пример
Я привел пример, который масштабирует внешний контейнер вверх и вниз. В значении масштаба .on-top
элемент с классом .on-top
(и текст "I should always be on top."
) исчезает. При уменьшении масштаба снова появляется неожиданно.
Ссылка на exmaple: https://jsfiddle.net/iafiawik/Lcox1ecc/
Выводы
- Кажется, что размер элемента имеет значение. Чем больше я это делаю, тем больше значение шкалы перед ее исчезновением.
- Я также проверил, чтобы установить
transform: scale(1.4)
с CSS непосредственно на элемент, и поведение такое же.
Проблема не существует, если я:
- Замените тег видео на div
- Удалить
position: absolute;
от братьев и сестер до .on-top
(то есть, .below
) - Удалить
overflow: hidden;
от .content
- Если я перемещаюсь.
.on-top
поэтому он помещается после тега видео в поток документа
(Но, конечно, ни один из этих обходных решений для меня не работает на самом деле из-за особых причин проекта. Я также не могу дать элементу видео отрицательный z-индекс, и мне нужно использовать overflow: hidden;
)
Предлагаемые обходные пути сообщества (спасибо!)
- Дайте тегу видео отрицательный индекс z (не могу этого сделать, потому что иногда у меня есть элементы, размещенные за видео)
- Удалить
overflow: hidden;
(Я не могу удалить overflow: hidden;
)
Браузеры
Я видел эту проблему в Chrome (Mac) и Safari (Mac).
Обновление 1
Похоже, что этот отчет об ошибках в значительной степени охватывает мою проблему. Тем не менее, он не обеспечивает исправления.
Обновление 2
Я ответил на свой вопрос, предоставив свое решение этой проблемы.
Обновление 3
Существует много ответов, которые либо изменяют z-index
видео, либо добавляют translateZ
к .on-top
. Демонстрации показали, что оба этих подхода устраняют проблему. Однако, поскольку моя структура HTML - это результат визуального редактора HTML (длинный рассказ...), я не знаю, какие элементы будут там или если они должны быть впереди, ниже или рядом с видео. Поэтому я ищу решение, которое не требует изменений для отдельных элементов, находящихся внутри масштабированного элемента.
Ответы
Ответ 1
Проведя много времени, исследуя эту проблему и пытаясь найти множество разных подходов, я пришел к выводу, что никакое решение не устраняет мою проблему. Существуют решения, которые устраняют проблему, если вы можете управлять z-индексами исчезающих элементов, но я не могу этого сделать, поскольку структура HTML не известна (это результат редактора HTML). Я искал решение, которое не требовало бы изменения отдельных дочерних элементов для масштабируемого родителя, но я пока не нашел его.
Этот отчет об ошибках в значительной степени затрагивает мою проблему, но это не дает для этого исправления.
Я могу подтвердить, что это происходит из-за того, что элемент за пределами масштабированных контейнеров имеет оригинальную ширину и высоту:
Элемент отображается в scale(1.227)
(красная граница указывает исходный размер #scaled
):
... но не в scale(1.228)
:
Поэтому мое решение состоит в том, чтобы добавить еще один элемент упаковки за пределы масштабированного элемента, который не масштабируется, но обновлять его свойства width
и height
соответствии со своими значениями первого дочернего масштаба. Этот элемент имеет overflow: hidden;
и предотвращает видимость элементов.
Это не идеальное решение, так как может возникнуть небольшой разрыв между масштабированным элементом и внешним элементом упаковки (проблемы округления), но это лучшее, что я могу сделать, учитывая обстоятельства.
var goalScale = 140;
var startScale = 100;
var currentScale = 100;
var shouldScaleUp = true;
var container = document.getElementById("scaled");
var scaledContainer = document.getElementById("resized-container");
var scaleInfo = document.getElementById("scale-info");
function step() {
var contentWidth = 1024;
var contentHeight = 768;
container.style.transform = "scale(" + (currentScale / 100) + ")";
scaledContainer.style.width = contentWidth * ((currentScale / 100)) + "px";
scaledContainer.style.height = contentHeight * ((currentScale / 100)) + "px";
scaleInfo.innerText = "Scale: " + (currentScale / 100);
if (currentScale === goalScale) {
shouldScaleUp = false;
}
if (currentScale === startScale) {
shouldScaleUp = true;
}
if (shouldScaleUp) {
currentScale += 0.5;
} else {
currentScale -= 0.5;
}
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
#resized-container {
position: fixed;
width: 1024px;
height: 768px;
overflow: hidden;
border: 10px solid red;
top: 200px;
left: 200px;
}
#scaled {
background: #cccccc;
width: 1024px;
height: 768px;
position: absolute;
transform-origin: left top;
}
.content {
height: 100%;
position: relative;
margin-left: auto;
margin-right: auto;
background: rgba(34, 34, 56, 0.2);
}
.below {
position: absolute;
width: 300px;
height: 300px;
right: 0px;
top: 100px;
background: purple;
z-index: 1;
opacity: 0.8;
}
.below-2 {
z-index: 3;
right: 100px;
}
.below-3 {
z-index: 4;
right: 400px;
}
.on-top {
position: absolute;
width: 50px;
right: -30px;
top: 150px;
background: pink;
z-index: 5;
padding: 20px;
}
.on-top h1 {
font-size: 20px;
}
#video {
position: absolute;
z-index: 4;
width: 1024px;
height: 768px;
background: rgba(0, 0, 0, 0.4);
}
<div id="resized-container">
<div id="scaled">
<div id="scale-info">
</div>
<div class="content">
<h2 class="below below-1">
I have z-index 1
</h2>
<div class="on-top">
<h1>
I should always be on top.<br /> I have z-index 5
</h1>
</div>
<h2 class="below below-2">
I have z-index 3
</h2>
<video id="video" src="https://www.w3schools.com/html/mov_bbb.mp4"></video>
<h2 class="below below-3">
I have z-index 4
</h2>
</div>
</div>
</div>
Ответ 2
Это похоже на ошибку в Chrome. Обратите внимание, что при масштабировании изображения инспектор элементов сообщает вам, что размер #scaled
равен 1024x768:
Где, как в Firefox:
Теперь, по-видимому, Chrome использует неправильный размер, чтобы заключить, что .on-top
полностью выходит за пределы .content
и скрывает его из-за скрытого переполнения (он не должен этого делать, но, по-видимому, пытается оптимизировать любой элемент, отображающий над видео). Примеры:
Scale: 1.225
Parent width: 1254.40
Child left: 1254.40 - (100 + 90) * 1.225 = 1021.65
Result: less than 1024 (partially inside)
Scale: 1.230
Parent width: 1259.52
Child left: 1259.52 - (100 + 90) * 1.230 = 1025.82
Result: greater than 1024 (completely outside)
К сожалению, я не мог найти элегантное решение. В идеале вам следует пересмотреть HTML-разметку и CSS, возможно, выровняйте верхний элемент с левым краем. В крайнем случае вы можете перемещать элементы ближе к левому, используя прозрачную рамку:
var goalScale = 140;
var startScale = 100;
var currentScale = 100;
var shouldScaleUp = true;
var container = document.getElementById("scaled");
var scaleInfo = document.getElementById("scale-info");
function step() {
container.style.transform = "scale(" + (currentScale / 100) + ")";
scaleInfo.innerText = "Scale: " + (currentScale / 100);
if (currentScale === goalScale) {
shouldScaleUp = false;
}
if (currentScale === startScale) {
shouldScaleUp = true;
}
if (shouldScaleUp) {
currentScale += 0.5;
} else {
currentScale -= 0.5;
}
window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
.scale-info {
position: fixed;
left: 0;
top: 0;
}
#scaled {
background: #cccccc;
width: 1024px;
height: 768px;
position: fixed;
left: 200px;
top: 200px;
}
.content {
height: 100%;
overflow: hidden;
position: relative;
margin-left: auto;
margin-right: auto;
background: rgba(34, 34, 56, 0.2);
}
.below {
position: absolute;
width: 300px;
height: 300px;
right: 0px;
top: 100px;
background: purple;
z-index: 1;
opacity: 0.8;
}
.below-2 {
z-index: 3;
right: 100px;
}
.below-3 {
z-index: 4;
right: 400px;
}
.on-top {
position: absolute;
width: 50px;
right: 100px;
top: 150px;
background: pink;
z-index: 5;
padding: 20px;
/* a 200px border moves the element towards left */
border-left: 200px solid transparent;
background-clip: padding-box;
}
.on-top h1 {
font-size: 20px;
}
#video {
position: absolute;
z-index: 4;
width: 1024px;
height: 768px;
background: rgba(0, 0, 0, 0.4);
}
<div id="scale-info"></div>
<div id="scaled">
<div class="content">
<h2 class="below below-1"> I have z-index 1</h2>
<div class="on-top">
<h1> I should always be on top.<br> I have z-index 5</h1>
</div>
<h2 class="below below-2"> I have z-index 3</h2> <video id="video" src="https://www.w3schools.com/html/mov_bbb.mp4"></video>
<h2 class="below below-3"> I have z-index 4</h2>
</div>
</div>
Ответ 3
Здесь вы найдете: https://jsfiddle.net/Lcox1ecc/423/
Вам просто нужно добавить -webkit-transform: translateZ(0);
в .on-top
.
Счастливое кодирование!
Ответ 4
Один из подходов, если вы можете немного изменить свой html, обертывает ваши проблемные элементы в контейнере такого же размера, как видео и контейнер, с надлежащим z-индексом. Таким образом, у вас будут четкие слои того же размера и положения, в которые вы можете позиционировать более сложные элементы. Например, например:
<div id="top-container">
<div class="on-top">
<h1>
I should always be on top.<br /> I have z-index 5
</h1>
</div>
</div>
#top-container {
width: 100%;
height: 100%;
position: absolute;
z-index: 5;
}
https://jsfiddle.net/06oykj8o/4/
Ответ 5
Я сделал это решение, поставив z-index:-1;
на video
.
https://jsfiddle.net/Lcox1ecc/312/
Ответ 6
Мне очень нравится ответ от Салмана А. Единственное, что приходит на ум, будет переписываться с position: relative
. Но я не знаю, если это вариант.
Ответ 7
Я наткнулся на что-то похожее на эту последнюю неделю с позиционированием абсолютных элементов и преобразований...
Я не знаю, поможет ли это вам, но вот ссылка.
CSS-преобразование: перевод перемещений: фиксированный внутренний Div
В конце концов я исправил его с помощью преобразования: translateX (none) vs translateX (0).
Супер странное поведение наверняка, но ссылка дает еще несколько ссылок, чтобы помочь сделать вещи более ясными - как и в своем поведении в спецификации.
Ответ 8
Это происходит из-за переполнения скрыто. Здесь работает ссылка
https://jsfiddle.net/Lcox1ecc/322/
.content {
overflow:visible;
}