css z-index perdu après la transformation webkit translate3d

98

J'ai deux éléments div absolument positionnés qui se chevauchent. Les deux ont défini des valeurs d'index z via css. J'utilise la translate3dtransformation Webkit pour animer ces éléments hors de l'écran, puis les remettre à l'écran. Après la transformation, les éléments ne respectent plus leurs z-indexvaleurs définies .

Quelqu'un peut-il expliquer ce qui arrive au z-index / stack-order des éléments div une fois que j'effectue une transformation webkit sur eux? Et expliquez ce que je peux faire pour conserver l'ordre de pile des éléments div?

Voici quelques informations supplémentaires sur la façon dont je fais la transformation.

Avant la transformation, chaque élément obtient ces deux valeurs de transition webkit définies via css (j'utilise jQuery pour faire les .css()appels de fonction:

element.css({ '-webkit-transition-duration': duration + 's' });
element.css({ '-webkit-transition-property': '-webkit-transform' });

L'élément est ensuite animé à l'aide de translate3d -webkit-transform:

element.css({ '-webkit-transform': 'translate3d(' + hwDelta + 'px, 0, -1px)' });

Btw, j'ai essayé de définir le 3ème paramètre de translate3dsur plusieurs valeurs différentes pour essayer de reproduire l'ordre de la pile dans l'espace 3D, mais sans succès.

En outre, les navigateurs iPhone / iPad et Android sont mon navigateur cible sur lequel ce code doit fonctionner. Les deux prennent en charge les transitions Webkit.

Rafe
la source
Pouvez-vous publier un lien pour voir l'exemple?
Littlemad
1
J'ai rencontré le même problème. J'ai une balise <iframe> avec le style d'élément intérieur "-webkit-transform: translate3d (0,0,0)" pour forcer l'accélération 3D. Il s'avère que le cadre extérieur avec un z-index plus élevé est toujours masqué par l'élément iframe intérieur. Juste visuel caché, je peux "cliquer" sur l'élément extérieur invisible. Cela ne se produit que dans Mobile Safari.
Morgan Cheng
J'ai passé 10h à comprendre que c'était ce qui empêchait mon code de fonctionner. Ugh
Dikeneko

Réponses:

52

Cela pourrait être lié à: https://bugs.webkit.org/show_bug.cgi?id=61824

En gros, lorsque vous appliquez une transformation 3D sur l'axe z, l'index z ne peut plus être pris en compte (vous êtes maintenant dans un plan de rendu en 3 dimensions, utilisez des valeurs z différentes). Si vous souhaitez revenir au rendu 2D pour les éléments enfants, utilisez transform-style: flat;.

samy-delux
la source
13
En gros, lorsque vous appliquez une transformation 3D sur l'axe z, l'index z ne peut plus être pris en compte (vous êtes maintenant dans un plan de rendu en 3 dimensions, utilisez des valeurs z différentes). Si vous souhaitez revenir au rendu 2D pour les éléments enfants, utilisez transform-style: flat;.
samy-delux
2
Donc, en mode "préserver-3d", nous devons utiliser l'axe z de la transformation pour définir l'ordre, et en mode plat, nous devons utiliser l'index z. Le bogue est que z-index sur safari est cassé en combinaison avec des transformations accélérées HW.
Steven Lu
1
ne fonctionne pas. Ne fonctionne que si je supprime les styles animés par classe.
fdrv le
44

Ceci est très certainement lié au bogue noté par samy-delux. Cela ne devrait affecter que les éléments positionnés comme absolus ou relatifs. Afin de remédier au problème, vous pouvez appliquer l'instruction css suivante à chaque élément qui est positionné de cette façon et cause des problèmes:

-webkit-transform: translate3d(0,0,0);

Cela appliquera la transformation à l'élément sans réellement effectuer de transformation, mais affectant son ordre de rendu afin qu'il soit au-dessus de l'élément à l'origine du problème.

divCe
la source
En utilisant Chrome (35.0.1916.114 m), j'ai trouvé que si je n'avais pas cette règle, après que l'élément a été retourné [transform: rotateY (180deg)], que les gestionnaires de clics jQuery ne fonctionnaient plus pour cet élément. De plus, après un retournement, il y a des problèmes avec les artefacts laissés à l'écran et surtout si leur opacité a été modifiée, sauf si le translate3d est présent! Cet article a aidé sitepoint.com/fix-chrome-animation-flash-bug
Philip Murphy
2
Cela vient de résoudre un problème très collant pour moi impliquant deux éléments fixes, l'un contenant un élément transformé en 3D. L'élément transformé en 3D déborderait et se placerait au-dessus de l'autre élément jusqu'à ce que le correctif ci-dessus soit appliqué.
Collin James
1
ne fonctionne pas. Ne fonctionne que si je supprime les styles animés par classe.
fdrv le
12

Un peu tard, mais essayez de mettre les éléments qui ont perdu leur Z-index en plaçant ce qui suit, j'ai eu un problème en faisant des trucs de parallaxe récemment et cela a énormément aidé.

transform-style: preserve-3d;

Cela évite de mettre

transform: translate3d(0,0,0);

Sur d'autres éléments qui mettent plus de pression sur le GPU

RouilléCollins
la source
1
Lorsque vos éléments sont en 3D, je ne m'attendrais pas à ce qu'une transformation exerce une pression supplémentaire sur le GPU. Les calculs doivent quand même être effectués. Sur quoi vous basez-vous?
Micros
7

En attendant de voir l'exemple

Avez-vous essayé de faire une échelle de transformation (1)? Je me souviens avoir eu un problème similaire, et j'ai dû réorganiser l'ordre html des éléments et utiliser une transformation dont je n'en avais pas besoin simplement parce que le z-index de l'utilisation de transform avait changé.

Si je ne suis pas dans l'erreur, chaque fois que vous utilisez une transformation, elle devient le z-index le plus élevé disponible, et il est ordonné par l'élément html le plus proche au début de la balise. Donc de haut en bas.

J'espère que cette aide

Littlemad
la source
6

z-index fonctionnera avec les divs transformés en 3D si vous stylisez l'élément empilable avec -webkit-transform: translateZ(0px);

Extrait sur codepen -> http://codepen.io/mrmoje/pen/yLIul

Dans l'exemple, les boutons stack upet stack downmontent et abaissent l'index z du pied de page (+/- 1) contre l'élément pivoté (une image dans ce cas).

Mrmoje
la source
on ne peut plus cliquer sur le stack up
clevertension
Hey @Moje, je m'interroge également sur ce problème. La pile ne peut toujours pas être cliquée à nouveau.
alchuang
Pourquoi n'ai-je pas pensé à ajouter un z-index négatif à l'élément traduit? Merci
Will
3

Je n'ai pas pu reproduire le problème que vous décrivez ici. Indépendamment de ce que je fais, la valeur z-index est conservée dans toutes les transformations. Je teste avec Chromium (Google Chrome).

Le troisième argument de la fonction translate3d manipule l'axe z de l'élément. Le concept est similaire, mais pas exactement le même que, l'indice z ... Les éléments avec un axe z inférieur sont sous les éléments avec une valeur plus élevée.

Je sais que vous avez essayé les valeurs du troisième argument pour correspondre à votre z-index prévu, mais le problème est que l'axe z ne semble pas changer pendant l'animation CSS3. Dans l'exemple suivant, l'élément survolé doit être en haut, mais #element_a reste en haut.

Si j'ajoute un z-index à la fois au sélecteur régulier et au sélecteur: hover, cela semble fonctionner et permettre à l'élément survolé d'être le plus haut.

Bien que ce ne soit pas exactement ce que vous recherchiez, ce comportement offre une solution. Il vous suffit d'utiliser translate3d et z-index pour définir l'ordre du rendu initial.

<style>
    div {
        width: 300px;
        height: 150px;
        background-color: white;
        border: 5px outset gray;
        float: left;
        margin: 20px;
        -webkit-transition: 2s;
    }

    #element_a {
        -webkit-transform: translate3d(0, 0, 50px);
    }
    #element_b {
        -webkit-transform: translate3d(0, 0, 100px);
    }

    #element_a:hover {
        -webkit-transform: translate3d(100px, 0, 60px);
    }

    #element_b:hover {
        -webkit-transform: translate3d(-100px, 0, -60px);
    }
</style>
<body>
    <div id="element_a">
        <img src="http://www.google.com/intl/en_com/images/srpr/logo3w.png">
    </div>
    <div id="element_b">
        <img src="http://www.google.com/intl/en_com/images/srpr/logo3w.png">
    </div>
</body>

la source
2
Cela a fonctionné pour moi - merci! J'ai ajouté ce qui suit à l'élément que je veux être «devant»: -webkit-transform: translate3d (0, 0, 1px);
Sam Dutton le
0

Une autre façon de contourner cela est de créer un élément parent et d'appliquer toutes les autres transitions qui lui sont liées:

# Apply transitions to a parent div
<div>
  # This image z-index -1 
  <img src="foo"/>

  # This image z-index -3
  <img src="bar"/>

  #This image z-index -2
  <img src="gg"/>
</div>

JsFiddle

Rouille
la source