O efeito de transição CSS torna a imagem embaçada / move a imagem 1px, no Chrome?


150

Eu tenho alguns CSS que, ao passar o mouse, um efeito de transição CSS move uma div.

O problema, como você pode ver no exemplo, é que a translatetransição tem o horrível efeito colateral de fazer com que a imagem na div se mova 1px para baixo / direita (e possivelmente redimensione levemente?) Para que ela pareça deslocada e fora de foco...

A falha parece se aplicar o tempo todo em que o efeito de foco é aplicado e, a partir de um processo de tentativa e erro, posso dizer com segurança que apenas parece ocorrer quando a transição de conversão move a div (a sombra e a opacidade da caixa também são aplicadas, mas não fazem diferença para o erro quando removido).

O problema parece acontecer apenas quando a página possui barras de rolagem. Portanto, o exemplo com apenas uma instância da div é bom, mas mais uma vez divs idênticas são adicionadas e a página requer uma barra de rolagem, o problema ocorre novamente ...


1
Estou no Chrome 27 no OSX, e está tudo bem. Acredito que quando o conteúdo é colocado em uma camada, ele se transforma em um bitmap durante a animação, e que em versões mais antigas / placas gráficas mais antigas isso não parece ótimo. Experimente uma versão mais recente e veja se está corrigida.
Ricos Bradshaw

Tudo bem no Chrome 25 OS X. BTW: sugiro uma abordagem diferente para a textura de gradiente de fundo que uma imagem de 300 KB!
Paolo

E obrigado @Paolo - a imagem de plano de fundo era apenas para demonstração, não é a imagem em uso no site real!
21413 Lewis Lewis

2
O problema surge quando a animação é tratada pela GPU, parece que os arredondamentos de bitmap estão um pouco fora. É reproduzido em Canary, mas funciona ok se você desativar a aceleração de GPU
Vals

Você pode tentar esta solução em cada quadro ... stackoverflow.com/a/42256897/1834212
Miguel

Respostas:


247

Atualização 2020

  • Se você tiver problemas com imagens borradas, verifique também as respostas abaixo, especialmente a image-renderingpropriedade CSS.
  • Para melhores práticas de acessibilidade e SEO, você pode substituir a imagem de plano de fundo por uma <img>tag usando a propriedade CSS de ajuste ao objeto .

Resposta original

Tente isso em seu CSS :

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

O que isso faz é fazer com que a divisão se comporte "mais em 2D".

  • A face posterior é desenhada como padrão para permitir que as coisas sejam giradas e rotacionadas. Não é necessário que você se mova apenas para a esquerda, direita, para cima, para baixo, dimensione ou gire (no sentido anti-horário).
  • Traduzir eixo Z para sempre ter um valor zero.
  • O Chrome agora lida com backface-visibilitye transformsem o -webkit-prefixo. No momento, não sei como isso afeta a renderização de outros navegadores (FF, IE); portanto, use as versões não prefixadas com cautela.

27
Pode não ter explicado nada, mas explicou o suficiente para corrigir esse problema para mim.
28413 McNab

@ Stacker Stack - o que há para explicar? Você acabou de copiar e colar o código no seu elemento problemático. Btw isso funciona muito bem!
easwee

1
eu sugiro que esta solução stackoverflow.com/a/42256897/1834212 im postar o link para evitará a duplicação
Miguel

1
Alguém pode confirmar se isso ainda funciona, porque sempre que adiciono `-webkit-backface-visible` e -webkit-transform, não consigo realmente ver uma alteração, e quando abro o console do desenvolvedor do chromes. Vejo que essas 2 propriedades css são traçadas, como se fossem substituídas, mas não são (css e html vazias). É como se o cromo não os aceitasse mais.
Kevin M

1
O @KevinM tenta sem os prefixos -webkit-, agora são CSS padrão.
sampoh

91

Você precisa aplicar a transformação 3d ao elemento, para que ele obtenha sua própria camada composta. Por exemplo:

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

ou

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

Mais sobre os critérios de criação de camadas, você pode ler aqui: Renderização acelerada no Chrome


Uma explicação:

Exemplos (passe a caixa verde):

Quando você usa qualquer transição no seu elemento, ele faz com que o navegador recalcule os estilos, re-layout do seu conteúdo, mesmo que a propriedade da transição seja visual (nos meus exemplos, é uma opacidade) e, finalmente, pinte um elemento:

captura de tela

O problema aqui é o re-layout do conteúdo que pode afetar os elementos "dançando" ou "piscando" na página durante a transição. Se você for para as configurações, marque a caixa de seleção "Mostrar camadas compostas" e aplique a transformação 3d a um elemento, verá que ele obtém sua própria camada, delineada com borda laranja.

captura de tela

Depois que o elemento obtém sua própria camada, o navegador só precisa compor as camadas na transição sem re-layout ou mesmo operações de pintura, para que o problema precise ser resolvido:

captura de tela


coisas legais! tenho uma causa pontual de quão detalhada foi sua resposta! qual software você está usando para captura / exibição de tela?
Kr3

Local no companheiro !! Me salvou um monte de problemas lá.

Isso fez o truque para mim. No começo, eu estava usando translateZ no pai que estava animando, mas os sprites de imagem de fundo ainda estavam embaçados. Estou usando o Velocity.js para escalar mais um contêiner dentro dele e aplicado algo como translateZ: 0.000001(algum número infinitesimal) e pronto! Imagens de fundo nítidas mais uma vez!
Notacouch

Obrigado companheiro. Isso funcionou no meu problema. a propósito, meu problema é que tenho um elemento que é girado em 90 graus e que sofre uma transição gradual usando a opacidade. ao acionar a transição, o conteúdo do elemento se move 1px da esquerda.
Lloyd aaron

42

Teve o mesmo problema com o iframe do youtube incorporado (as traduções foram usadas para centralizar o elemento iframe). Nenhuma das soluções acima funcionou até tentar redefinir os filtros css e a mágica.

Estrutura:

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

Estilo [antes]

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

Estilo [depois]

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

9
filter: blur(0)fez isso por mim!
Nick

3
Inacreditável O_o WTF com o desfoque? Por que está ativado por padrão?
Yuriy Polezhayev

Esta foi a solução para mim também. A resposta aceita pode funcionar para pessoas que não estão usando outras funções de "conversão" em suas propriedades de transformação, mas não estava funcionando para mim.
Edward Coyle Jr.

O -webkit-prefixo não deveria vir antes? Mais informações
Trevor Nestman

32

Eu recomendei um novo atributo experimental CSS que testei no navegador mais recente e é bom:

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+                */

Com isso, o navegador conhecerá o algoritmo para renderização


Isso corrigiu minhas imagens borradas e giradas, enquanto a visibilidade da face traseira, o desfoque (0) e o translateZ não funcionaram para mim. Obrigado.
Louis Ameline

Imagens fixas em alguns casos de uso, tornaram horrivelmente pior em outros :-) Interessante em qualquer caso!
Simon Steinberger

Aprofundado: image-rendering: -webkit-optimize-contrast;resolve o problema no Chrome. No entanto, imagens em outros navegadores, por exemplo, Firefox, são renderizadas muito, muito pior com o conjunto de opções de renderização. Portanto, eu uso apenas a diretiva WebKit, que também funciona no mecanismo Blink. Obrigado!
Simon Steinberger

Em alguns casos, as imagens ficam visivelmente irregulares. Não consigo encontrar um doce local entre o resultado blurrier e este ~ sigh ~
bigp

4

Acabei de encontrar outro motivo pelo qual um elemento fica embaçado ao ser transformado. Eu estava usando transform: translate3d(-5.5px, -18px, 0);para reposicionar um elemento depois que ele foi carregado, no entanto, esse elemento ficou embaçado.

Eu tentei todas as sugestões acima, mas aconteceu que eu estava usando um valor decimal para um dos valores de conversão. Números inteiros não causam o desfoque, e quanto mais longe eu era do número inteiro, pior o desfoque se tornava.

ou seja, 5.5pxborra o elemento mais, 5.1pxmenos.

Só pensei em jogar isso aqui, caso isso ajude alguém.


Obrigado, esse foi o problema no meu caso - eu estava usando translateY (-50%), que deve ter sido avaliado para um valor de pixel decimal.
b4tch

3

Enganei o problema usando a transição por etapas, não suavemente

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

Não é uma solução, é uma trapaça e não pode ser aplicada em qualquer lugar.

Não sei explicar, mas funciona para mim. Nenhuma outra resposta me ajuda (OSX, Chrome 63, tela sem retina).

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


No seu violino está tremendo como o de Parkinson, mas no meu caso funcionou.
Tárcio Zemel

2

Escalar para dobrar e reduzir para metade com zoomfuncionou para mim.

transform: scale(2);
zoom: 0.5;

isso parece funcionar no chrome para imagens. infelizmente, ele também modifica qualquer html que você usa.
Jack Davidson

2

Eu tentei cerca de 10 soluções possíveis. Misturá-los e eles ainda não funcionaram corretamente. Havia sempre 1px shake no final.

Acho a solução reduzindo o tempo de transição no filtro.

Isso não funcionou:

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

Solução:

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

Tente isso no violino:

.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>

Espero que isso ajude alguém.


1

Experimentar filter: blur(0);

Funcionou para mim


Também funcionou para mim, Chrome 63, 64 e Vivaldi 1,13
GTCrais

1

Para mim, agora em 2018. A única coisa que resolveu o meu problema (uma linha branca intermitente que passa por uma imagem em foco) foi aplicá-la ao meu elemento de link, mantendo o elemento de imagem que possui 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;
}

Sim! 'blur (0)' corrige isso para mim no Chrome. Faz com que a imagem borrada muito ligeiramente em redimensionar embora, mas é menos perceptível do que o salto / redimensionamento
00-BBB

0
filter: blur(0)
transition: filter .3s ease-out
transition-timing-function: steps(3, end) // add this string with steps equal duration

Ajudei-me a definir o valor da duração da .3stransição com etapas iguais de tempo de transição.3s


-7

Só tenho o mesmo problema. Tente definir a posição: em relação ao elemento pai, que funcionou para mim.


5
Você tem uma demonstração desse trabalho? Eu não tenho nenhuma idéia de como isso iria ajudar
Zach Saucier

2
Se você puder editar sua resposta e explicar o que o código que você está mostrando faz, e por que / como esse código responde à pergunta, isso pode realmente ajudar. Os blocos de código por si só geralmente não são respostas úteis.
Lea Cohen
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.