I have a nav-links class on which I want to have horizontal scroll effect based on changing translateX. I change translateX using CSS variable from JavaScript. Irrespective of any timing function the horizontal movement seems choppy from start point to final point. But scale operation and vertical movements is smooth. Computed values of css variables are also correctly passed.
.nav-links {
position: relative;
left: 50vw;
display: flex;
gap: clamp(1rem, 2vw, 2rem);
margin-top: clamp(2rem, 2vw, 3rem);
padding: 0rem clamp(1rem, 2vw, 2rem);
transition: all 500ms cubic-bezier(0.13, 0.53, 0.38, 0.97);
}
.nav-links[data-show-menu="false"] {
transform: translate(var(--translateX), -70%) scale(0.9);
}
.nav-links[data-show-menu="true"] {
transform: translate(var(--translateX), 0%) scale(1);
}
translateX set in percentage terms as eg: --translateX :80%
Also tried to do same with animation, but it results in same issue.
Related
I have a square wrapper with a circle inside, like on this fiddle
https://jsfiddle.net/Lazarus97/3bntmd8g/1/
<div class="card">
<div class="circle">
<p>
SOME
<br>
Text Test
</p>
</div>
</div>
<style>
body {
display: flex;
min-width: 100vw;
min-height: 100vh;
justify-content: center;
align-items: center;
margin: 0;
padding: 0;
}
.card {
width: 200px;
height: 200px;
background: #eee;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.circle {
background: red;
width: 150px;
height: 150px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
transform: translateY(80px) scale(1);
transition: transform .3s ease-in; /* SAME AS ITS CHILD */
}
.circle:hover {
transform: translateY(0px) scale(3);
}
.circle * {
transition: transform .3s ease-in; /* SAME AS ITS PARENT */
}
.circle:hover *{
transform: scale(0.333333333); /* I got this number like this --> 1 / scale(3) 1/3 = 0.333333333 */
}
</style>
but notice how the text inside the circle jumps as you hover the circle, it gets bigger then smaller again, even though I did the math correctly, and created the same transition easing motion.
it should remain the original size during the transition.
Does anybody knows why this happens and is there a way to fix this?
I tried to fix it with the different transition easing motions.
"...why this happens...":
The content of your .circle scales as the .circle scale. That means that you correctly calculated that at the end of the transition, if the circle is 3 times bigger, the content needs to be 3 times smaller to stay the original size. During the transition though, at 0.5 of the transition (0.15 seconds in your case) - the circle is 2 times bigger than it originally were, while the content is 1/3 smaller (that is 2/3=0.6̅), but ALSO 2 times bigger (so it's actually 4/3=1.3̅), as it scales with the circle.
"...is there a way to fix this...":
You either need to make those two objects independent, or find the equation to calculate how smaller does the content need to be at every point in time to be exactly the same size as originally if it scales with it's parent and then apply the results to an animation property with #keyframes at every %. But that is not perfect and would probably have stuttering effect on slower devices.
At first, when you scale the element you scale all its content, and you are doing two animations, both are initiated with :hover and both are ease-in which increase the effect, you can do it softly decreasing the max scale and turning to linear the second animation, that hides very much the effect but stills not being the best.
.circle:hover {
transform: translateY(0px) scale(2);
}
.circle * {
transition: transform .3s linear; /* SAME AS ITS PARENT */
}
You should decrease de min scale too.
.circle:hover *{
transform: scale(0.5);
}
In case you decide still using scale(3), you can use calc() to the best match.
.circle:hover *{
transform: scale(calc(1/3));
}
How can I realize a smooth transition for my mobile menu?
The transform property is working, but I want it to happen slowly..
My Sass looks like this
.mobile-nav
display: none
position: relative
width: 100%
background: $white
padding: 30px 0 20px
transform: translateY(-100%)
#media (max-width: 775px)
.mobile-nav.is-o
display: block
transform: translateY(0%)
The main obstacle you're facing is that the display property is not animatable.
Like a light switch, display: none is off and display: block is on. There's no middle ground, no fade effects, no CSS transitions.
However, there are multiple other properties you can use for transitions. Among them:
height
opacity
z-index
background-color
Here's an example:
.mobile-nav-toggle {
font-size: 2em;
cursor: pointer;
}
.mobile-nav {
display: inline-block;
overflow: hidden;
width: 0;
height: 0;
opacity: 0;
transition: width 1s, height 1s, opacity 0s 1s, background-color 0s 2s;
}
.mobile-nav-toggle:hover + .mobile-nav {
width: 150px;
height: 150px;
opacity: 1;
background-color: lightgreen;
transition: 1s;
}
<div class="mobile-nav-toggle">☰</div>
<div class="mobile-nav">
<ul>
<li><a>Item</a></li>
<li><a>Item</a></li>
<li><a>Item</a></li>
</ul>
</div>
References:
Full list of animatable properties in CSS
Transitions on the display: property
I personally use opacity combined with visibility to achieve fade effect like I would like for whole element. Remember to manipulate z-index, so you "hidden" object won't be clickable when dissapeared.
I am trying to understand what is really happening “3d” world of CSS.
I made a simple example
Particularly the code which bugs me the most is:
.back {
background-color: tomato;
transform: rotateY(180deg);
z-index: 1;
}
The thing which is not clear to me is why when you hover over .inner, its background color (gold) is not visible?? If you remove the transform property from .back or if you set the rotateY to 0deg then the gold background color of the .inner is clearly visible.
Why is the transform property of .back changing the stacking order?
Logically it makes sense that children(.front and .back) should appear in front of their parent(.inner).
Also, I would like to know what really happens when you set transform-style to flat? Does that make parent and all of its children collapse into single “unit” where element with highest stacking order takes priority/visibility?
in your code :
.outer {
display: block;
width: 200px;
height: 200px;
border: 2px solid gold;
perspective: 1000px;
padding: 10px;
margin: 0 auto;
}
.inner {
position: relative;
height: 100%;
width: 100%;
transition: transform 2s linear;
transform-style: preserve-3d;
background-color: gold;
backface-visibility: visible;
transform: rotateY(50deg);
}
.sides {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
color: white;
backface-visibility: hidden;
}
.front {
background-color: blue;
transform: translateZ(20px)
}
.back {
background-color: tomato;
transform: rotateY(180deg) translateZ(10px);
}
.inner:hover {
transform: rotateY(180deg)
}
<div class="outer">
<div class="inner">
<div class="sides front">Front Side</div>
<div class="sides back">Back Side</div>
</div>
</div>
you are using
transform: rotateY(180deg) translateZ(10px);
The transforms are applied right to left, so first it goes to the front 10px. But after that, it rotates 180deg. (around the transform-origin that is constant). That makes the previous 10px go towards the back instead of to the front.
if the order is the inverse
transform: translateZ(10px) rotateY(180deg);
now the rotation is done first, and so the translation is unafected by it and goes to the front.
and No, sorry, z-index is not a substitute for 3-d transforms, if you want to use 3d transforms, translation is the only way to go ....
In your first example, z-index is useless, as can be seen easily
codepen with z-index removed
This works because you are setting
backface-visibility: hidden;
So only the face that is facing front will be visible
I've create a button, and I want it to rotate 360deg on mouse hover, and rotate backwords 360deg on hover off. So far it work well, but if you go slowly towards it with the mouse, it flickers.
Here's the short version of the code:
.btn {
display: block;
margin: 60px auto;
width: 250px;
padding: 15px;
position: relative;
color: #3498db;
font-weight: 300;
font-size: 24px;
text-decoration: none;
border: 5px solid #3498db;
transform: rotate(360deg);
transition: all 0.5s;
transition-timing-function: cubic-bezier(1, 0.8, 0.5, 1);
}
.btn-rotate:hover {
transform: rotate(0deg);
transition-delay: 0;
transition: all 0.5s;
}
I am a button!
for full code, check the codpen demo http://codepen.io/andornagy/pen/ojBNZx
The flicker issue is happening because, when you hover on the element, the elements start to rotate. After rotating some x degree, the element would've rotated to certain degree and the mouse/cursor is not anymore on the element.
This is the reason the flicker is happening.
Comparing to the above one, I feel using wrapper (div) and analyzed how much width we may need, we set that to div. On div:hover element, we can perform the transition. It gives better result compared to now.
Here is the fiddle
.buttonHolder {
padding: 50px;
}
.buttonHolder:hover .btn-rotate {
transform: rotate(360deg);
transition-delay: 0;
transition: all 0.6s;
}
Here's an idea where it adds an extra pseudo element only when you're hovering :
Demo
.btn:after {
content: '';
width: 300px;
height: 150px;
display: none;
position: absolute;
top: 50%;
left: 50%;
border-radius: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.btn:hover:after {
display: block;
}
Gave it a bit of background color, just so it's better visible what's going on...
For the most control, I'd resort to some JavaScript though.
I have a problem in latest Firefox browser version 34 (system: Windows 7, screen width: 1600px). I made effect with zooming images (in some container) after hover on it. I am using transform: scale(1.1) with transition: transform 0.3s ease-in-out. But when I hover on image, and after image zoom in.. it make some strange 1px-shifting. Some rendering browser bug, but I hope that existing some fix for it.
Most important CSS definition and part of HTML code:
figure {
display: block;
overflow: hidden;
position: relative;
backface-visibility: hidden;
}
figure img {
width: 100%;
transform: scale(1);
transition: transform 0.3s ease-in-out;
}
figure:hover img {
transform: scale(1.1);
}
<figure>
<img class="img-responsive" src="http://lorempixel.com/600/400/fashion/7">
</figure>
Sample with bug is online here: http://templates.silversite.pl/test/jumpingimg/
I saw also that somebody can fix it, but I do not know how, e.g. box "Our recent work" on http://demo.qodeinteractive.com/bridge/
I had a similar problem on my project. All images were position: absolute; and the transform look like that:
figure img{
transform: translate( -50%, 50%) scale(1);
position: absolute;
top: 50%;
left: 50%;
}
figure img:hover{
transform: translate( -50%, 50%) scale(1.1);
}
I replace every scale with scale3d and that solved my problem.
The final styles look like that:
figure img{
transform: translate( -50%, 50%) scale3d(1, 1, 1);
position: absolute;
top: 50%;
left: 50%;
}
figure img:hover{
transform: translate( -50%, 50%) scale3d(1.1, 1.1, 1);
}
Hope that's will fix your problem
On the link that you provided, http://demo.qodeinteractive.com/bridge/ , if you actually go here: http://demo.qodeinteractive.com/bridge/portfolio/gallery-style-condensed/two-columns-grid/ , you can see that, once looking at dev tools, that they apply a margin of "1px" on left/right side
.projects_holder.hover_text.no_space article .image img {
margin: 0 1px;
}
If you disable that style, you'll see the image move as you're describing when hovering on the image.
Therefore, your CSS for the image should be:
figure img {
width: 100%;
transform: scale(1);
transition: transform 0.3s ease-in-out;
display: block; /* (or inline-block) */
margin: 0 1px;
}
I have just run into this same problem now. The solutions here didn't fix the issue, so I'm posting what I did to get this to work.
Like OP I had a container with oveflow hidden and was the same size as the image inside it. The image would scale on hover to create a 'zoom' effect - but when initially starting and ending the transition, the image was "jumping"/growing a tiny bit on the bottom and right-hand side. This made it jumpy and not smooth.
I had calculated the dimensions of my components based off of percentages, which caused them to be non-integers (Chrome). I have a feeling Scale & Scale3d round the pixel values when scaling, which caused this jump. I gave a parent container display:table, which caused all children to have their width/heights be rounded to be an integer value. This fixed the issue for me, and the images now scale smoothly!
7,5 years later it's still an issue and the now solution is will-change css property. Only IE won't get this, but others seems to be doing fine - no more px jumping (edit: on non retina screens).
figure {
display: block;
overflow: hidden;
position: relative;
backface-visibility: hidden;
}
figure img {
width: 100%;
transform: scale(1);
transition: transform 0.3s ease-in-out;
}
figure:hover img {
transform: scale(1.1);
will-change: transform;
}
I just run over the same issue and for me it looks like that the browser corrects the decimal pixel after the scaling is done. Or some how the height and the width doesn't get scaled equals and that gets corrected in the end.
So I think the solution is to use an image with a 1 x 1 ration factor.
So for me the code of the question works fine when I use a the lorempixel with a width and height of 400px.
Let me know if that solves the issue?!
figure {
display: block;
overflow: hidden;
position: relative;
backface-visibility: hidden;
}
figure img {
width: 100%;
transform: scale(1);
transition: transform 0.3s ease-in-out;
}
figure:hover img {
transform: scale(1.1);
}
<figure>
<img class="img-responsive" src="http://lorempixel.com/400/400/fashion/7">
</figure>