J'ai un comportement quelque peu étrange dans Chrome et Safari. J'ai un conteneur mis à l'échelle (transform: scale()
) avec une vidéo et d'autres éléments à l'intérieur. À certaines échelles, les éléments de positionnement absolu avec un indice z élevé disparaissent et ne reviennent plus.
Comment puis-je résoudre ce problème? Notez que je ne peux pas attribuer d'indice z négatif à l'élément vidéo et que je dois utiliser overflow: hidden;
.
Exemple
J'ai créé un exemple permettant de monter et de descendre le conteneur le plus à l'extérieur. À une valeur d'échelle spécifik, l'élément avec la classe .on-top
(et le texte "I should always be on top."
) disparaît. Lorsque vous réduisez à nouveau, il apparaît soudainement.
Lien vers exmaple: https://jsfiddle.net/iafiawik/Lcox1ecc/
Conclusions
transform: scale(1.4)
avec CSS directement sur l'élément et le comportement est identique.Le problème n'existe pas si I:
position: absolute;
de la fratrie en .on-top
(c'est-à-dire .below
)overflow: hidden;
de .content
.on-top
pour qu'il soit placé après la balise video dans le flux de documents(Mais bien sûr, aucune de ces solutions de contournement ne fonctionne pour moi en réalité pour des raisons spécifiques au projet. Je ne peux pas non plus donner à l'élément vidéo un index z négatif et I need d'utiliser overflow: hidden;
.)
Solutions de contournement suggérées par la communauté (merci!)
overflow: hidden;
(je ne peux pas supprimer overflow: hidden;
)Navigateurs
J'ai vu ce problème dans Chrome (Mac) et Safari (Mac).
Mise à jour 1
On dirait que ce rapport de bogue couvre assez bien mon problème. Cependant, cela ne résout pas le problème.
Mise à jour 2
J'ai répondu à ma propre question en apportant ma solution à ce problème.
Mise à jour 3
Il y a beaucoup de réponses qui entrent dans ce qui modifie le z-index
de la vidéo ou ajoute translateZ
à l'élément .on-top
. Les démos ont montré que ces deux approches résolvent le problème. Cependant, comme ma structure HTML est la sortie d’un éditeur HTML visuel (histoire longue ...), je ne sais pas quels éléments seront présents ni s’ils devraient être devant, au-dessous ou à côté d’une vidéo . Par conséquent, je recherche une solution ne nécessitant pas de modification d'éléments individuels contenus dans l'élément mis à l'échelle.
Après avoir passé beaucoup de temps à chercher ce problème et à essayer différentes approches, j'en suis venu à la conclusion qu'aucune solution ne résout mon problème. Il existe des solutions qui résolvent le problème si vous êtes capable de contrôler les z-index des éléments qui disparaissent, mais je suis incapable de le faire car la structure du code HTML n'est pas connue (c'est la sortie de l'éditeur HTML ). Je cherchais une solution qui ne nécessiterait pas de modifications pour les enfants d'un parent échelonné, mais je n'en ai trouvé aucune jusqu'à présent.
Ce rapport de bogue traite assez bien de mon problème, mais il ne fournit pas de solution.
Je peux confirmer que cela se produit car l'élément est en dehors de la largeur et de la hauteur d'origine des conteneurs mis à l'échelle:
L'élément est visible à scale(1.227)
(la bordure rouge indique la taille originale de #scaled
):
... mais pas à scale(1.228)
:
Ma solution est donc d'ajouter un autre élément d'habillage en dehors de l'élément mis à l'échelle qui n'est pas mis à l'échelle mais d'obtenir ses propriétés width
et height
mises à jour conformément à ses premières valeurs d'échelle enfant. Cet élément a overflow: hidden;
et empêche les éléments d'être visibles.
Ce n’est pas une solution parfaite, car il est possible que le décalage entre l’élément mis à l’échelle et l’élément enveloppant le plus à l’extérieur (problèmes d’arrondis) soit minime, mais c’est ce que je peux faire de mieux compte tenu des circonstances.
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>
Cela ressemble à un bug dans Chrome. Notez que lorsque vous redimensionnez l'image, l'inspecteur d'élément vous répète que la taille de #scaled
est de 1024x768:
Où comme dans Firefox:
Apparemment, Chrome utilise une taille incorrecte pour conclure que .on-top
estcomplètementextérieur .content
et le cache en raison du débordement masqué (cela ne devrait pas être le cas, mais apparemment, il tente d'optimiser éloignez tout élément qui apparaît au-dessus d’une vidéo) Exemples:
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)
Malheureusement, je n'ai pas pu trouver de solution élégante. Idéalement, vous devriez réviser votre balisage HTML et CSS, en alignant éventuellement l’élément supérieur sur Edge gauche. En dernier recours, vous pouvez déplacer les éléments plus vers la gauche en utilisant une bordure transparente:
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>
Ici vous allez: https://jsfiddle.net/Lcox1ecc/423/
Vous devez juste ajouter -webkit-transform: translateZ(0);
à la classe .on-top
.
Bon codage!
Une approche, si vous pouvez modifier un peu votre html, consiste à envelopper vos éléments problématiques dans un conteneur de la même taille que la vidéo et le conteneur, avec le z-index approprié. De cette façon, vous obtenez des couches claires de la même taille et des mêmes positions, dans lesquelles vous pouvez positionner des éléments plus complexes. Comme ceci par exemple:
<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;
}
J'ai fait cette solution de contournement en mettant z-index:-1;
sur video
.
J'aime beaucoup la réponse de Salman A . La seule chose qui me vient à l’esprit, serait de réécrire avec position: relative
. Mais je ne sais pas si c’est une option.
Je suis tombé sur quelque chose de similaire à la semaine dernière en positionnant des éléments absolus et en transformant ...
Je ne sais pas si cela va vous aider, mais voici un lien.
Transformation CSS: traduire les mouvements de position: fixe div interne
Finalement, je l'ai corrigé en utilisant une transformation: translateX (none) vs translateX (0).
Super étrange comportement à coup sûr, mais le lien donne quelques liens supplémentaires pour aider à rendre les choses plus claires - comme dans son comportement par spécification.
Cela se produit parce que le débordement est caché.Voici le lien de travail
https://jsfiddle.net/Lcox1ecc/322/
.content {
overflow:visible;
}