Efekt przejścia CSS sprawia, że ​​obraz jest rozmyty / przesuwa obraz o 1 piksel w przeglądarce Chrome?

150

Mam trochę CSS, które po najechaniu myszą, efekt przejścia CSS przesunie div.

Problem, jak widać na przykładzie, polega na tym, że translateprzejście ma okropny efekt uboczny polegający na tym, że obraz w elemencie div przesuwa się o 1 piksel w dół / w prawo (i może nawet nieznacznie zmienia rozmiar?), Aby wyglądał na nie na miejscu i nieostry ...

Ta usterka wydaje się występować przez cały czas stosowania efektu najechania, a z procesu prób i błędów mogę śmiało powiedzieć, że pojawia się tylko wtedy, gdy przejście translacji przesuwa element div (cienie pola i krycie są również stosowane, ale nie mają znaczenia błąd po usunięciu).

Problem wydaje się występować tylko wtedy, gdy strona zawiera paski przewijania. Tak więc przykład z tylko jednym wystąpieniem elementu div jest w porządku, ale po dodaniu kolejnych identycznych elementów div i strona wymaga paska przewijania, problem pojawia się ponownie ...

Chwytak
źródło
1
Jestem w Chrome 27 na OSX i wszystko w porządku. Uważam, że kiedy treść zostanie umieszczona w warstwie, zamieni się w bitmapę podczas animacji, a na starszych wersjach / starszych kartach graficznych nie wygląda to dobrze. Wypróbuj nowszą wersję i zobacz, czy została naprawiona.
Rich Bradshaw
Wszystko w porządku na Chrome 25 OS X. Przy okazji: sugerowałbym inne podejście do tekstury gradientu tła niż obraz 300KB!
Paolo
Dzięki @Paolo - obraz tła służył tylko do demonstracji, nie jest to obraz używany w rzeczywistej witrynie!
Lewis
2
Problem pojawia się, gdy animacja jest obsługiwana przez GPU, wygląda na to, że zaokrąglenia bitmapy są trochę nieprawidłowe. Jest odtwarzany w wersji Canary, ale działa dobrze, jeśli wyłączysz akcelerację GPU
vals
Możesz wypróbować to rozwiązanie w każdej klatce ... stackoverflow.com/a/42256897/1834212
Miguel

Odpowiedzi:

247

Aktualizacja 2020

  • Jeśli masz problemy z rozmytymi obrazami, sprawdź również odpowiedzi poniżej, zwłaszcza image-renderingwłaściwość CSS.
  • Aby uzyskać najlepsze praktyki w zakresie ułatwień dostępu i pod kątem SEO, możesz zastąpić obraz tła <img>tagiem za pomocą właściwości CSS dopasowanej do obiektu.

Oryginalna odpowiedź

Spróbuj tego w swoim CSS :

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

To powoduje, że podział zachowuje się „bardziej w 2D”.

  • Backface jest rysowany domyślnie, aby umożliwić odwracanie rzeczy z obrotem i tym podobne. Nie ma takiej potrzeby, jeśli poruszasz się tylko w lewo, w prawo, w górę, w dół, skalujesz lub obracasz (przeciwnie) zgodnie z ruchem wskazówek zegara.
  • Przekształć oś Z, aby zawsze miała wartość zerową.
  • Chrome obsługuje teraz backface-visibilityi transformbez -webkit-prefiksu. Obecnie nie wiem, jak to wpływa na renderowanie w innych przeglądarkach (FF, IE), więc ostrożnie używaj wersji bez prefiksu.
sampoh
źródło
27
Mogło nic nie wyjaśnić, ale wystarczyło, aby rozwiązać ten problem.
McNab,
@Class Stacker - co wyjaśnić? Wystarczy skopiować, wkleić kod do problematycznego elementu. Przy okazji to działa bardzo ładnie!
easywee
1
proponuję to rozwiązanie stackoverflow.com/a/42256897/1834212 zamieszczam link, aby uniknąć powielania
Miguel
1
Czy ktoś może potwierdzić, czy to nadal działa, ponieważ za każdym razem, gdy dodam `-webkit-backface-visibility` i -webkit-transformtak naprawdę nie widzę zmiany, i kiedy otwieram konsolę programisty Chromes. Widzę, że te 2 właściwości css są przekreślane, jakby zostały nadpisane, ale tak nie jest (puste css i html). To tak, jakby chrom już ich nie akceptował.
Kevin M
1
@KevinM spróbuj bez prefiksów -webkit-, są to teraz standardowe CSS.
sampoh
91

Musisz zastosować transformację 3D do elementu, aby uzyskać własną warstwę kompozytową. Na przykład:

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

lub

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

Więcej o kryteriach tworzenia warstw można przeczytać tutaj: Przyspieszone renderowanie w Chrome


Wyjaśnienie:

Przykłady (najedź na zielone pole):

Kiedy używasz dowolnego przejścia w swoim elemencie, powoduje to ponowne obliczenie stylów przez przeglądarkę, a następnie ponowne ułożenie treści, nawet jeśli właściwość przejścia jest wizualna (w moich przykładach jest to krycie) i ostatecznie pomaluj element:

zrzut ekranu

Problem polega na zmianie układu treści, co może powodować „tańczące” lub „migające” elementy na stronie podczas przejścia. Jeśli przejdziesz do ustawień, zaznacz pole wyboru „Pokaż warstwy kompozytowe”, a następnie zastosuj transformację 3D do elementu, zobaczysz, że ma on własną warstwę, która jest zaznaczona pomarańczową obwódką.

zrzut ekranu

Po tym, jak element otrzyma własną warstwę, przeglądarka musi tylko połączyć warstwy podczas przejścia bez zmiany układu lub nawet operacji malowania, więc problem musi zostać rozwiązany:

zrzut ekranu

sol0mka
źródło
niezłe rzeczy! zrozumiałem, jak szczegółowa była Twoja odpowiedź! jakiego oprogramowania używasz do przechwytywania / tworzenia zrzutów ekranu?
kroe
Spot on mate !! Zaoszczędziło mi tam wielu kłopotów.
To załatwiło sprawę dla mnie. Na początku używałem translateZ na rodzica, którego animowałem, ale obrazki tła były nadal rozmyte. Używam Velocity.js do skalowania jeszcze jednego kontenera w nim i zastosowałem coś takiego jak translateZ: 0.000001(trochę nieskończenie mały #) i voila! Jeszcze raz ostre obrazy w tle!
notacouch
Dzięki stary. To zadziałało na mój problem. Nawiasem mówiąc, mój problem polega na tym, że mam element, który jest obrócony o 90 stopni i ma przejście z efektem przejścia za pomocą krycia. podczas wyzwalania przejścia zawartość elementu przesuwa się o 1 piksel od lewej.
Lloyd Aaron
42

Miałem ten sam problem z osadzonym elementem iframe YouTube (tłumaczenia zostały użyte do wyśrodkowania elementu iframe). Żadne z powyższych rozwiązań nie działało, dopóki nie spróbowano zresetować filtrów css i nie nastąpiła magia.

Struktura:

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

Styl [przed]

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

Styl [po]

.translate {
  transform: translateX(-50%);
  -webkit-transform: translateX(-50%);
  filter: blur(0);
  -webkit-filter: blur(0);
}
xb1itz
źródło
9
filter: blur(0)zrobił to dla mnie!
Nick
3
Niewiarygodne O_o WTF z rozmyciem? Dlaczego jest domyślnie włączony?
Yuriy Polezhayev
Dla mnie to też było rozwiązanie. Zaakceptowana odpowiedź może zadziałać dla osób, które nie używają innych funkcji „translacji” w swoich właściwościach transformacji, ale dla mnie nie działała.
Edward Coyle Jr.
Czy -webkit-przedrostek nie powinien występować wcześniej? Więcej informacji
Trevor Nestman
32

Poleciłem eksperymentalny nowy atrybut CSS, który przetestowałem na najnowszej przeglądarce i jest dobry:

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

Dzięki temu przeglądarka będzie znała algorytm renderowania

Felipez
źródło
To naprawiło moje rozmyte obrócone obrazy, podczas gdy widoczność od tyłu, rozmycie (0), translateZ nie działały dla mnie. Dziękuję Ci.
Louis Ameline,
Naprawiono obrazy w niektórych przypadkach, w innych było strasznie gorzej :-) Interesujące w każdym razie!
Simon Steinberger
Zagłębione głębiej: image-rendering: -webkit-optimize-contrast;rozwiązuje problem w przeglądarce Chrome. Jednak obrazy w innych przeglądarkach, np. Firefox, są renderowane znacznie, znacznie gorzej, gdy ustawiona jest opcja renderowania. Dlatego używam tylko dyrektywy WebKit, która działa również na silniku Blink. Dzięki!
Simon Steinberger
W niektórych przypadkach powoduje to zauważalne poszarpanie obrazu. Wydaje się, że nie mogę znaleźć
idealnego
4

Właśnie znalazłem inny powód, dla którego element staje się rozmazany podczas transformacji. Używałem transform: translate3d(-5.5px, -18px, 0);do zmiany położenia elementu po załadowaniu, jednak ten element stał się rozmazany.

Wypróbowałem wszystkie powyższe sugestie, ale okazało się, że było to spowodowane tym, że użyłem wartości dziesiętnej dla jednej z przetłumaczonych wartości. Całe liczby nie powodują rozmycia, a im dalej oddalałem się od liczby całkowitej, tym gorsze stawało się rozmycie.

tj. 5.5pxnajbardziej, 5.1pxnajmniej rozmywa element .

Pomyślałem, że rzucę to tutaj na wypadek, gdyby komuś to pomogło.

ashrobbins
źródło
Dzięki, to był problem w moim przypadku - używałem translateY (-50%), które musiało być przeliczane na dziesiętną wartość piksela.
b4tch
3

Oszukałem problem używając przejścia krokowego, a nie płynnego

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

To nie jest rozwiązanie, to oszustwo i nie wszędzie można je zastosować.

Nie potrafię tego wyjaśnić, ale to działa dla mnie. Żadna inna odpowiedź mi nie pomaga (OSX, Chrome 63, wyświetlacz Non-Retina).

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

Evgeny Gendel
źródło
Na twoich skrzypcach trzęsie się jak Parkinson, ale w moim przypadku zadziałało.
Tárcio Zemel
2

Skalowanie do podwojenia i zmniejszenie do połowy z zoomdziałało dla mnie.

transform: scale(2);
zoom: 0.5;
Kushagra Gour
źródło
to wydaje się działać w chrome dla obrazów. niestety modyfikuje również każdy plik HTML, który go umieścisz.
Jack Davidson
2

Wypróbowałem około 10 możliwych rozwiązań. Zmieszałem je i nadal nie działały poprawnie. Na końcu zawsze był wstrząs 1px.

Znajduję rozwiązanie, skracając czas przejścia na filtrze.

To nie zadziałało:

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

Rozwiązanie:

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

Spróbuj tego na skrzypcach:

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

Mam nadzieję, że to komuś pomoże.

Adam Orłow
źródło
1

Próbować filter: blur(0);

U mnie to zadziałało

Fred K.
źródło
U mnie też
działało
1

Dla mnie teraz w 2018 roku. Jedyną rzeczą, która rozwiązała mój problem (biała glitchy-migotająca linia przebiegająca przez obraz po najechaniu kursorem), było zastosowanie tego do mojego elementu łącza, który zawiera element obrazu, który ma 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
źródło
Tak! „blur (0)” rozwiązuje to za mnie w Chrome. Obraz jest jednak bardzo lekko rozmyty podczas zmiany rozmiaru, ale jest mniej zauważalny niż skok / zmiana rozmiaru
00-BBB
0
filter: blur(0)
transition: filter .3s ease-out
transition-timing-function: steps(3, end) // add this string with steps equal duration

Pomogło mi ustawienie wartości czasu trwania .3sprzejścia równych krokom czasowym przejścia.3s

j-tap
źródło
-7

Właśnie mam ten sam problem. Spróbuj ustawić pozycję: względem elementu nadrzędnego, który działał dla mnie.

Jaskółka oknówka
źródło
5
Czy masz demo tego działania? Nie mam pojęcia, jak to by pomogło
Zach Saucier
2
Jeśli mógłbyś edytować swoją odpowiedź i wyjaśnić, co robi wyświetlany kod i dlaczego / jak ten kod odpowiada na pytanie, mogłoby to naprawdę pomóc. Same bloki kodu nie są zwykle użytecznymi odpowiedziami.
Lea Cohen,