L'effet de transition CSS rend l'image floue / déplace l'image de 1px, dans Chrome?

150

J'ai du CSS qui, en survolant, un effet de transition CSS déplace un div.

Le problème, comme vous pouvez le voir dans l'exemple, est que la translatetransition a pour effet secondaire horrible de faire bouger l'image dans le div de 1px vers le bas / droite (et peut-être redimensionner légèrement?) De sorte qu'elle semble déplacée et flou...

Le pépin semble s'appliquer tout le temps où l'effet de survol est appliqué, et à partir d'un processus d'essais et d'erreurs, je peux dire en toute sécurité que cela ne semble se produire que lorsque la transition de traduction déplace le div (l'ombre et l'opacité de la boîte sont également appliquées mais ne font aucune différence pour l'erreur une fois supprimée).

Le problème ne semble se produire que lorsque la page a des barres de défilement. Donc, l'exemple avec une seule instance du div est bien, mais une fois de plus des div identiques sont ajoutés et la page nécessite donc une barre de défilement, le problème se produit à nouveau ...

Lewis
la source
1
Je suis sur Chrome 27 sur OSX, et ça va. Je crois que lorsque le contenu est placé dans une couche, il est transformé en une image bitmap pendant l'animation, et que sur les anciennes versions / anciennes cartes graphiques, cela n'a pas l'air génial. Essayez une version plus récente et voyez si elle est corrigée.
Rich Bradshaw
Tout va bien sur Chrome 25 OS X. BTW: Je suggérerais une approche différente pour la texture du dégradé d'arrière-plan qu'une image de 300 Ko!
Paolo
Et merci @Paolo - l'image de fond était pour la démonstration uniquement, ce n'est pas l'image utilisée sur le site actuel!
Lewis
2
Le problème survient lorsque l'animation est gérée par le GPU, on dirait que les arrondis bitmap sont un peu décalés. Est reproduit dans Canary, mais cela fonctionne bien si vous désactivez l'accélération GPU
vals
Vous pouvez essayer cette solution à chaque image ... stackoverflow.com/a/42256897/1834212
Miguel

Réponses:

247

Mise à jour 2020

  • Si vous rencontrez des problèmes avec des images floues, assurez-vous de vérifier également les réponses ci-dessous, en particulier la image-renderingpropriété CSS.
  • Pour des meilleures pratiques en matière d'accessibilité et de référencement, vous pouvez remplacer l'image d'arrière-plan par une <img>balise utilisant la propriété CSS adaptée à l' objet .

Réponse originale

Essayez ceci dans votre CSS :

.your-class-name {
    /* ... */
    -webkit-backface-visibility: hidden;
    -webkit-transform: translateZ(0) scale(1.0, 1.0);
}

Cela fait que la division se comporte "plus 2D".

  • La face arrière est dessinée par défaut pour permettre le retournement des choses avec rotation et autres. Cela n'est pas nécessaire si vous vous déplacez uniquement vers la gauche, la droite, le haut, le bas, l'échelle ou la rotation (anti-horaire).
  • Traduire l'axe Z pour toujours avoir une valeur nulle.
  • Chrome gère désormais backface-visibilityet transformsans le -webkit-préfixe. Je ne sais actuellement pas comment cela affecte le rendu des autres navigateurs (FF, IE), alors utilisez les versions non préfixées avec prudence.
sampoh
la source
27
Je n'aurais peut-être rien expliqué, mais cela suffisait pour résoudre ce problème pour moi.
McNab
@Class Stacker - que faut-il expliquer? Vous venez de copier-coller le code dans votre élément problématique. Btw cela fonctionne très bien!
easwee
1
Je suggère cette solution stackoverflow.com/a/42256897/1834212 im postant le lien pour éviter la duplication
Miguel
1
Quelqu'un peut-il confirmer si cela fonctionne toujours, parce que chaque fois que j'ajoute `-webkit-backface-visibilité` et -webkit-transform, je ne peux pas vraiment voir un changement, et quand j'ouvre la console développeur chromes. Je vois que ces 2 propriétés css sont barrées, comme si elles étaient écrasées, mais elles ne le sont pas (css et html vides). C'est comme si Chrome ne les acceptait plus.
Kevin M
1
@KevinM essaie sans les préfixes -webkit-, ce sont maintenant des CSS standard.
sampoh
91

Vous devez appliquer une transformation 3D à l'élément afin qu'il obtienne son propre calque composite. Par exemple:

.element{
    -webkit-transform: translateZ(0);
    transform: translateZ(0);
}

ou

.element{
    -webkit-transform: translate3d(0,0,0);
    transform: translate3d(0,0,0);
}

En savoir plus sur les critères de création de couches, vous pouvez lire ici: Rendu accéléré dans Chrome


Une explication:

Exemples (survolez la case verte):

Lorsque vous utilisez une transition sur votre élément, le navigateur recalcule les styles, puis remodèle votre contenu même si la propriété de transition est visuelle (dans mes exemples, il s'agit d'une opacité) et peint finalement un élément:

capture d'écran

Le problème ici est la remise en page du contenu qui peut faire un effet d'éléments «dansants» ou «clignotants» sur la page pendant la transition. Si vous allez dans les paramètres, cochez la case "Afficher les calques composites" puis appliquez la transformation 3D à un élément, vous verrez qu'il obtient son propre calque qui est entouré d'une bordure orange.

capture d'écran

Une fois que l'élément a son propre calque, le navigateur a juste besoin de composer des calques lors de la transition sans re-disposition ni même des opérations de peinture, le problème doit donc être résolu:

capture d'écran

sol0mka
la source
jolies choses! obtenu une raison précise de la précision de votre réponse! quel logiciel utilisez-vous pour la capture d'écran / les flèches?
kroe
Spot on mate !! M'a sauvé beaucoup de tracas là-bas.
Cela a fait l'affaire pour moi. Au début, j'utilisais translateZ sur le parent que j'animais, mais les sprites de l'image d'arrière-plan étaient encore flous. J'utilise Velocity.js pour mettre à l'échelle un autre conteneur et j'ai appliqué quelque chose comme translateZ: 0.000001(un # infinitésimal) et le tour est joué! Des images de fond nettes une fois de plus!
notacouch
Merci mon pote. Cela a fonctionné sur mon problème. au fait, mon problème est que j'ai un élément qui pivote de 90 degrés et qui a une transition de fondu en utilisant l'opacité. lors du déclenchement de la transition, le contenu de l'élément se déplace de 1px à partir de la gauche.
Lloyd aaron
42

J'ai eu le même problème avec l'iframe youtube intégré (les traductions étaient utilisées pour centrer l'élément iframe). Aucune des solutions ci-dessus n'a fonctionné jusqu'à ce que vous essayiez de réinitialiser les filtres css et que la magie se produise.

Structure:

<div class="translate">
     <iframe/>
</div>

Style [avant]

.translate {
  transform: translateX(-50%);
  -webkit-transform: translateX(-50%);
}

Style [après]

.translate {
  transform: translateX(-50%);
  -webkit-transform: translateX(-50%);
  filter: blur(0);
  -webkit-filter: blur(0);
}
xb1itz
la source
9
filter: blur(0)l'a fait pour moi!
Nick
3
Incroyable O_o WTF avec le flou? Pourquoi est-il activé par défaut?
Yuriy Polezhayev
C'était aussi la solution pour moi. La réponse acceptée pourrait fonctionner pour les personnes qui n'utilisent pas d'autres fonctions de «traduction» dans leurs propriétés de transformation, mais cela ne fonctionnait pas pour moi.
Edward Coyle Jr.
Le -webkit-préfixe ne devrait-il pas précéder? Plus d'infos
Trevor Nestman
32

J'ai recommandé un nouvel attribut CSS expérimental que j'ai testé sur le dernier navigateur et c'est bien:

image-rendering: optimizeSpeed;             /*                     */
image-rendering: -moz-crisp-edges;          /* Firefox             */
image-rendering: -o-crisp-edges;            /* Opera               */
image-rendering: -webkit-optimize-contrast; /* Chrome (and Safari) */
image-rendering: optimize-contrast;         /* CSS3 Proposed       */
-ms-interpolation-mode: nearest-neighbor;   /* IE8+                */

Avec cela, le navigateur connaîtra l'algorithme de rendu

Felipez
la source
Cela a corrigé mes images pivotées floues alors que la visibilité de la face arrière, le flou (0), translateZ ne fonctionnait pas pour moi. Je vous remercie.
Louis Ameline du
Images fixes dans certains cas d'utilisation, aggravant les choses dans d'autres :-) Intéressant en tout cas!
Simon Steinberger
Creusé plus profondément: image-rendering: -webkit-optimize-contrast;résout le problème sur Chrome. Cependant, le rendu des images sur d'autres navigateurs, par exemple Firefox, est bien pire avec le jeu d'options de rendu. Par conséquent, je n'utilise que la directive WebKit, qui fonctionne également sur le moteur Blink. Merci!
Simon Steinberger
Dans certains cas, les images sont nettement irrégulières. Je n'arrive pas à trouver un sweet-spot entre le résultat plus flou et celui-ci ~ soupir ~
bigp
4

Je viens de trouver une autre raison pour laquelle un élément devient flou lorsqu'il est transformé. J'utilisaistransform: translate3d(-5.5px, -18px, 0); pour repositionner un élément une fois qu'il avait été chargé, mais cet élément est devenu flou.

J'ai essayé toutes les suggestions ci-dessus, mais il s'est avéré que c'était dû à l'utilisation d'une valeur décimale pour l'une des valeurs de traduction. Les nombres entiers ne causent pas le flou, et plus je m'éloignais du nombre entier, plus le flou devenait pire.

c'est-à-dire 5.5pxbrouille le plus l'élément,5.1px le moins.

Je pensais juste que je jetterais ça ici au cas où ça aiderait quelqu'un.

ashrobbins
la source
Merci, c'était le problème dans mon cas - j'utilisais translateY (-50%) qui devait être évalué à une valeur de pixel décimale.
b4tch le
3

J'ai triché le problème en utilisant la transition par étapes, pas en douceur

transition-timing-function: steps(10, end);

Ce n'est pas une solution, c'est une triche et ne peut pas être appliqué partout.

Je ne peux pas l'expliquer, mais ça marche pour moi. Aucune autre réponse ne m'aide (OSX, Chrome 63, écran non Retina).

https://jsfiddle.net/tuzae6a9/6/

Evgeny Gendel
la source
Dans votre violon tremble comme Parkinson, mais dans mon cas a fonctionné.
Tárcio Zemel
2

La mise à l'échelle pour doubler et réduire de moitié avec a zoomfonctionné pour moi.

transform: scale(2);
zoom: 0.5;
Kushagra Gour
la source
cela semble fonctionner dans le chrome pour les images. malheureusement, il modifie également le code HTML que vous le mettez.
Jack Davidson
2

J'ai essayé environ 10 solutions possibles. Mélangez-les et ils ne fonctionnaient toujours pas correctement. Il y avait toujours une secousse 1px à la fin.

Je trouve la solution en réduisant le temps de transition sur le filtre.

Cela n'a pas fonctionné:

.elem {
  filter: blur(0);
  transition: filter 1.2s ease;
}
.elem:hover {
  filter: blur(7px);
}

Solution:

.elem {
  filter: blur(0);
  transition: filter .7s ease;
}
.elem:hover {
  filter: blur(7px);
}

Essayez ceci en violon:

.blur {
  border: none;
  outline: none;
  width: 100px; height: 100px;
  background: #f0f;
  margin: 30px;
  -webkit-filter: blur(10px);
  transition: all .7s ease-out;
  /* transition: all .2s ease-out; */
}
.blur:hover {
  -webkit-filter: blur(0);
}

.blur2 {
  border: none;
  outline: none;
  width: 100px; height: 100px;
  background: tomato;
  margin: 30px;
  -webkit-filter: blur(10px);
  transition: all .2s ease-out;
}
.blur2:hover {
  -webkit-filter: blur(0);
}
<div class="blur"></div>

<div class="blur2"></div>

J'espère que ça aidera quelqu'un.

Adam Orlov
la source
1

Essayer filter: blur(0);

Ça a marché pour moi

Fred K
la source
A travaillé pour moi aussi, Chrome 63, 64 et Vivaldi 1.13
GTCrais
1

Pour moi, maintenant en 2018. La seule chose qui a résolu mon problème (une ligne blanche scintillante traversant une image en survol) était de l'appliquer à mon élément de lien contenant l'élément d'image qui a transform: scale(1.05)

a {
   -webkit-backface-visibility: hidden;
   backface-visibility: hidden;
   -webkit-transform: translateZ(0) scale(1.0, 1.0);
   transform: translateZ(0) scale(1.0, 1.0);
   -webkit-filter: blur(0);
   filter: blur(0);
}
a > .imageElement {
   transition: transform 3s ease-in-out;
}
mateostabio
la source
Oui! 'blur (0)' le corrige pour moi dans Chrome. Rend l'image très légèrement floue lors du redimensionnement mais est moins visible que le saut / redimensionnement
00-BBB
0
filter: blur(0)
transition: filter .3s ease-out
transition-timing-function: steps(3, end) // add this string with steps equal duration

J'ai été aidé en définissant la valeur des .3sétapes de synchronisation de transition égales de durée de transition.3s

j-tap
la source
-7

J'ai juste le même problème. Essayez de définir la position: par rapport à l'élément parent, cela a fonctionné pour moi.

Martin
la source
5
Avez-vous une démonstration de ce fonctionnement? Je ne sais pas comment cela aiderait
Zach Saucier
2
Si vous pouviez modifier votre réponse et expliquer ce que fait le code que vous montrez, et pourquoi / comment ce code répond à la question, cela pourrait vraiment aider. Les blocs de code en eux-mêmes ne sont généralement pas des réponses utiles.
Lea Cohen