CSS animation causes images to flicker - css

I'm learning how to use transition: in CSS. But for some reason, my images keep flickering instead of giving me smooth animation. I'm developing in Windows 10 with the latest version of Chrome. Here is my code, which is very simple:
function toggleClass() {
var box = document.getElementById('box');
box.className = box.className.match(/active/) ? '' : 'active';
}
#box {
width:200px;
height:200px;
background-color:#999;
opacity:0;
transform:translate(0,30px);
transition:background-color 0.6s ease, opacity 0.6s ease, transform 0.6s ease;
}
#box.active {
opacity:1;
transform:translate(0,0);
}
img {
width:100%;
display:block;
filter: grayscale(100%) brightness(120%);
mix-blend-mode:multiply;
}
#box:hover {
background-color:red;
}
<button type="button" onClick="toggleClass()">Toggle Image</button>
<div id="box" class="">
<img src="https://i.stack.imgur.com/GwYD1.jpg" alt="">
</div>
What I want to do is when I press the Toggle Image button, I want a grey scale to fade in. Then when I mouse over the image, I want it to turn red since it is using the mix-blend-mode and the #box should have a red background color.
The problem is that every time I add the active to #box.active, the image doesn't "gradually fade in". Instead, a solid grey box scrolls up and fades in. Once the grey box completes animation, the image then "snaps" into view as if animation duration is 0 seconds. I don't want the image to "snap" into view...I want the image to fade in smoothly just like the grey box.
I want both the grey box and the grey picture to animate in smoothly together.
How do I make this happen?
EDIT
I noticed that if I add the line #box.active {background-color:transparent;}, then the image fades in. But the image is too bright. Applying a #box-active {background-color:#999;} had the same problem as the original question.
EDIT 2
I noticed that if I add these lines, it almost does what I need
#box { background-color:rgba(155,155,155,1); }
#box.active { background-color:rgba(155,155,155,0.9);}
For some unusual reason using rgba along with an alpha of 1 before the active class and an alpha of 0.9, seems to help a little. Now I see the browser "trying" to animate things in smoothly, it's just very choppy now.

Try adding transform: translateZ(0) on the child element img.
function toggleClass() {
var box = document.getElementById('box');
box.className = box.className.match(/active/) ? '' : 'active';
}
#box {
width:200px;
height:200px;
background-color:#999;
opacity:0;
transform:translate(0,30px);
transition:background-color 0.6s ease, opacity 0.6s ease, transform 0.6s ease;
}
#box.active {
opacity:1;
transform:translate(0,0);
}
img {
width:100%;
display:block;
filter: grayscale(100%) brightness(120%);
mix-blend-mode:multiply;
transform: translateZ(0); // this rules forces a new layer
}
#box:hover {
background-color:red;
}
<button type="button" onClick="toggleClass()">Toggle Image</button>
<div id="box" class="">
<img src="https://i.stack.imgur.com/GwYD1.jpg" alt="">
</div>
Theoretically your code is correct, this has been a bug in chrome for quite some time.
The translateZ(0) workaround forces chrome to draw seperate layers for the GPU to toy with. You can find more about layers here.
Also note that if you're going for visual consistency, you might have to go with some additional vendor prefixed styling.
As of now, Chrome, Firefox and Edge don't agree on what a blend should look like

Related

CSS hover over image and text

I have squares with text on a website homepage and I want to add hover effect but dont know which class to choose from my website
www.justtobe.com.au homepage
the first big grid image ( beach photo), I want to add a hover effect similar to this homepage grid
<h2 id="demo12">12. Opacity #2</h2>
<div class="hover12 column">
<div>
<figure><img src="https://nxworld.net/example/css-image-hover-effects/pic01.jpg" /></figure>
<span>Hover</span>
</div>
<div>
/* Opacity #2 */
.hover
figure {
background: #1abc9c;
}
.hover12 figure img {
opacity: 1;
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
}
.hover12 figure:hover img {
opacity: .5;
}
Can someone please help?
There are a couple of things that you have to change if your picture to look the same as the one in the website you mentioned, but if you only want that hover effect then you just need to target the span
.hover12 span {
opacity: 1;
-webkit-transition: .3s ease-in-out;
transition: .3s ease-in-out;
cursor:pointer;
}
.hover12 span:hover {
opacity: .5;
display:block;
}
Example: https://jsfiddle.net/fhntLpmz/
Though, if you want it to look like the one in the website you mentioned, you need to change the structure of your html and then your css code.
<h2 id="demo12">12. Opacity #2</h2>
<div class="hover12 column">
<div class="wrapper">
<span>Hover</span>
</div>
<div>
Instead of using img to show the image, I use css to put it as a background, so that the Hover button is inside it.
.wrapper {
background-image:url(https://nxworld.net/example/css-image-hover-effects/pic01.jpg);
background-size:100%;
background-repeat:no-repeat;
width:300px;
height:200px;
}
Other than this, it's just another couple of css. Take this example: https://jsfiddle.net/0shmd21e/1/
There are multiple ways to do this, though. This is just one of them

CSS transition on background-color

I have a div with a background color and css transitions
#foo {
background-color:rgba(255,0,0,0.9);
-webkit-transition: all 3000ms ease;
-moz-transition: all 3000ms ease;
-o-transition: all 3000ms ease;
transition: all 3000ms ease;
}
I also have a button. When the button is clicked, I would like to
immediately switch the div to transparent background and a final height
create a fade-in effect on background-color property only
To accomplish this, I've created some classes for the div
#foo.transparent {
background-color:transparent;
}
#foo.final {
background-color:rgba(255,0,0,0.9);
height:400px;
}
and apply them to the div with jQuery on click
$('#start').click(function() {
$('#foo').addClass('transparent').addClass('final');
});
Unfortunately, height switches immediately to the final value (this is correct), but the background color doesn't perform the required transition from transparent to final value. What am I missing?
(fiddle)
I think an easier solution might be to use jQuery's fadeIn() effect, like this:
Html:
<button id="start">start animation</button>
<div id="foo">some content</div>
CSS:
#foo {
background-color:rgba(255,0,0,0.9);
}
#foo.final {
height:400px
}
JQuery:
$('#start').click(function() {
console.log('click');
$('#foo').addClass('final').hide().fadeIn();
});
And your updated fiddle: https://jsfiddle.net/aqw4cbss/3/
height is not animatiable. use min-height && max-height instead.
plus the backgrounds in your initial state and final state are the same, so how can it be transitioned from 2 equals state.
jsfiddle
I think you should look into JQuery .animate and .css functions.
$('#foo').css("opacity", "0");
$('#foo').animate({backgroundColor: "green"}, 500);
note: you should specify a default background-color and opacity in the css to transition from.
EDIT: You'll need the JQuery Color plugin in order to make this work (it's very small.)
https://github.com/jquery/jquery-color

How to fade in image when in view with CSS

Is there a way to fade in an image when a user scrolls the image into view using purely if not mostly CSS?
I have a bunch of images displayed and I'd like the images to appear as they scroll down as a nice effect.
If you want the image to fade in only when the user can see it (after scrolling the page), you can't do it with CSS only. To make the fade in/fade out effect on hover use opacity and transition. Example
img{
opacity: 0.6;
transition: all 1s;
}
img:hover{
opacity: 1.0;
}
If you want to use JQuery, it's possible. See this exmaple.
img
{
opacity:0.4;
}
img:hover
{
opacity:1.0;
}
The CSS3 property for transparency is opacity.The opacity property can take a value from 0.0 - 1.0\
A lower value makes the element more transparent.
img:hover {
-webkit-filter: grayscale(100%);
}
Check this link, it would be of great help for you:-
http://designshack.net/?p=36895

How to disable CSS3 transitions when zooming?

When I use CSS3 transitions on an element's width/height or top/right/bottom/left, and I adjust the page zoom using CTRL+, CTRL- or CTRL0, the browser animates the change to these attributes.
Is there a way to use these transitions, but prevent the browser from using them only when zooming?
EDIT:
Sample HTML:
<div></div>
Sample CSS:
div {
background:red;
height:200px;
width:200px;
-moz-transition:1s;
-webkit-transition:1s;
transition:1s;
}
div:hover {
height:300px;
width:300px;
}
Code also available on jsFiddle.
I've thought of a workaround that uses Javascript to disable the transition while CTRL is being pressed. It handles the keyboard shortcuts listed above, as well as CTRL+scrollwheel, but only when the document has focus.
It can't handle zooming initiated by using the menu, but its better than nothing.
HTML
<div></div>
CSS:
div {
background:red;
height:200px;
width:200px;
-moz-transition:1s;
-webkit-transition:1s;
transition:1s;
}
div:hover {
height:300px;
width:300px;
}
.zooming {
-moz-transition:0s;
-webkit-transition:0s;
transition:0s;
}
jQuery:
$(document)
.keydown(function(e) { if (e.ctrlKey) { $('div').addClass('zooming'); }})
.keyup(function(e) { $('div').removeClass('zooming'); });
Updated jsFiddle. Only tested in Chrome so far.
Try this solution:
http://jsfiddle.net/995zE/
It works by adding the transition css when you click the buttons, and when you zoom the browser window, it removes that css.
This works on Firefox, Chrome, and IE 10. On Firefox and IE, when you zoom, the transition continues as normal, and the zooming doesn't affect it. On Chrome, the transition fast-forwards to its final state.
HTML:
<button id="decrease_width">- width</button>
<button id="increase_width">+ width</button>
<div id="test"></div>
CSS:
div#test
{
width: 100px;
height: 100px;
border: 1px solid red;
}
div#test.transition
{
transition: width 2s ease;
-webkit-transition: width 2s ease;
-moz-transition: width 2s ease;
-o-transition: width 2s ease;
}
JavaScript:
var transition_class = 'transition';
var $test = jQuery('#test');
function transition_test(width) {
$test.addClass(transition_class).css('width', $test.width() + width);
}
jQuery("#decrease_width").click(function () {
transition_test(-50);
});
jQuery("#increase_width").click(function () {
transition_test(50);
});
jQuery(window).resize(function () {
$test.removeClass(transition_class);
});

CSS transition effect makes image blurry / moves image 1px, in Chrome?

I have some CSS that on hover, a CSS transition effect will moves a div.
The problem, as you can see in the example, is that the translate transition has the horrible side effect of making the image in the div move by 1px down/right (and possibly resize ever so slightly?) so that it appears out of place and out of focus...
The glitch seems to apply the whole time the hover effect is applied, and from a process of trial and error I can safely say only seems to occur when the translate transition moves the div (box shadow and opacity are also applied but make no difference to the error when removed).
The problem only seems to happen when the page has scrollbars. So the example with just one instance of the div is fine, but once more identical divs are added and the page therefore requires a scrollbar the problem strikes again...
2020 update
If you have issues with blurry images, be sure to check answers from below as well, especially the image-rendering CSS property.
For best practice accessibility and SEO wise you could replace the background image with an <img> tag using object-fit CSS property.
Original answer
Try this in your CSS:
.your-class-name {
/* ... */
-webkit-backface-visibility: hidden;
-webkit-transform: translateZ(0) scale(1, 1);
}
What this does is it makes the division to behave "more 2D".
Backface is drawn as a default to allow flipping things with rotate
and such. There's no need to that if you only move left, right, up, down, scale or rotate (counter-)clockwise.
Translate Z-axis to always have a zero value.
Chrome now handles backface-visibility and transform without the -webkit- prefix. I currently don't know how this affects other browsers rendering (FF, IE), so use the non-prefixed versions with caution.
You need to apply 3d transform to the element, so it will get its own composite layer.
For instance:
.element{
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
or
.element{
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
More about layer creation criteria you can read right here: Accelerated Rendering in Chrome
An explanation:
Examples (hover green box):
Problem: Transition may cause blink effect on sibling elements (OSx Lion, Chrome 30)
Solution: An element on its own composite layer
When you use any transition on your element it cause browser to recalculate styles, then re-layout your content even if transition property is visual (in my examples it is an opacity) and finaly paint an element:
The issue here is re-layout of the content that can make an effect of "dancing" or "blinking" elements on the page while transition happens.
If you will go to settings, check "Show composite layers" checkbox and then apply 3d transform to an element, you will see that it gets it's own layer which outlined with orange border.
After element gets its own layer, browser just needs to composite layers on transition without re-layout or even paint operations so problem have to be solved:
Had the same problem with embeded youtube iframe (Translations were used for centering iframe element). None of the solutions above worked until tried reset css filters and magic happened.
Structure:
<div class="translate">
<iframe/>
</div>
Style [before]
.translate {
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
}
Style [after]
.translate {
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
filter: blur(0);
-webkit-filter: blur(0);
}
I recommended an experimental new attribute CSS I tested on latest browser and it's good:
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+ */
With this the browser will know the algorithm for rendering
Just found another reason why an element goes blurry when being transformed. I was using transform: translate3d(-5.5px, -18px, 0); to re-position an element once it had been loaded in, however that element became blurry.
I tried all the suggestions above but it turned out that it was due to me using a decimal value for one of the translate values. Whole numbers don't cause the blur, and the further away I went from the whole number the worse the blur became.
i.e. 5.5px blurs the element the most, 5.1px the least.
Just thought I'd chuck this here in case it helps anybody.
I cheated problem using transition by steps, not smoothly
transition-timing-function: steps(10, end);
It is not a solving, it is a cheating and can not be applied everywhere.
I can't explain it, but it works for me. None of another answers helps me (OSX, Chrome 63, Non-Retina display).
https://jsfiddle.net/tuzae6a9/6/
Scaling to double and bringing down to half with zoom worked for me.
transform: scale(2);
zoom: 0.5;
Try filter: blur(0);
It worked for me
I've tried around 10 possibly solutions. Mixed them up and they still didn't work correctly. There was always 1px shake at the end.
I find solution by reducing transition time on filter.
This didn't work:
.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);
}
Try this in fiddle:
.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>
I hope this helps someone.
For me, now in 2018. The only thing that fixed my problem (a white glitchy-flicker line running through an image on hover) was applying this to my link element holding the image element that has 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;
}
None of this worked, what worked for me is scaling image down.
So depending on what size you want the image or what resoultion your image is, you can do something like this:
.ok {
transform: perspective(100px) rotateY(0deg) scale(0.5);
transition: transform 1s;
object-fit:contain;
}
.ok:hover{
transform: perspective(100px) rotateY(-10deg) scale(0.5);
}
/* Demo Preview Stuff */
.bad {
max-width: 320px;
object-fit:contain;
transform: perspective(100px) rotateY(0deg);
transition: transform 1s;
}
.bad:hover{
transform: perspective(100px) rotateY(-10deg);
}
div {
text-align: center;
position: relative;
display: flex;
}
h3{
position: absolute;
bottom: 30px;
left: 0;
right: 0;
}
.b {
display: flex;
}
<center>
<h2>Hover on images</h2>
<div class="b">
<div>
<img class="ok" src='https://www.howtogeek.com/wp-content/uploads/2018/10/preview-11.png'>
<h3>Sharp</h3>
</div>
<div>
<img class="bad" src='https://www.howtogeek.com/wp-content/uploads/2018/10/preview-11.png'>
<h3>Blurry</h3>
</div>
</div>
</center>
The image should be scaled down, make sure you have a big image resoultion
I had a similar problem with blurry text but only the succeeding div was affected. For some reason the next div after the one that I was doing the transform in was blurry.
I tried everything that is recommended in this thread but nothing worked.
For me rearranging my divs worked. I moved the div that blurres the following div to the end of parents div.
If someone know why just let me know.
#before
<header class="container">
<div class="transformed div">
<span class="transform wrapper">
<span class="transformed"></span>
<span class="transformed"></span>
</span>
</div>
<div class="affected div">
</div>
</header>
#after
<header class="container">
<div class="affected div">
</div>
<div class="transformed div">
<span class="transform wrapper">
<span class="transformed"></span>
<span class="transformed"></span>
</span>
</div>
</header>
filter: blur(0)
transition: filter .3s ease-out
transition-timing-function: steps(3, end) // add this string with steps equal duration
I was helped by setting the value of transition duration .3s equal transition timing steps .3s
The blurring occurred for me in Chrome only (Windows and Mac) when animating 'transform' in a keyframe animation. For me, the -webkit-optimize-contrast setting only partially helped. For best results I also had to use a "magic value" for scaleX (slightly larger than 1 instead of 1).
Here's the code that worked:
img {
image-rendering: -webkit-optimize-contrast;
}
#keyframes scale-in-left {
0% {
transform: scaleX(0);
opacity: 0;
}
100% {
transform: scaleX(1.000001);
opacity: 1;
}
}
Here's the code that didn't work (caused blurry images in Chrome):
#keyframes scale-in-left {
0% {
transform: scaleX(0);
opacity: 0;
}
100% {
transform: scaleX(1);
opacity: 1;
}
}
In the end, the "working" code removed most of the blurring, but not all of it. Safari and Firefox were still clearer without any special settings.
Note also that just resizing the browser window cleared up the unwanted blurring, suggesting perhaps that something is causing Chrome to fail to execute a final render pass (?).

Resources