Is there any way to animate transform: translate, height and width at same time in Safari? I have a bug. After transition is finished, element will jump a few pixels away. Here is fiddle.
div {
background-color: green;
height: 100px;
left: 200px;
position: absolute;
top: 200px;
transition: transform 1s, height 1s, width 1s;
width: 100px;
}
div:hover {
height: 150px;
width: 150px;
transform: translate(-50%, -50%);
}
<div></div>
The jump happens because your height- and width values are pixel-based, and your transform is percentages, which results in sub-pixels. Try changing your approach by animating scale instead (it's always a good idea to try to keep your animations restricted to transforms and opacity anyway. See this article for reference). Use transform-origin to define the origin point of the transformation.
div {
background-color: green;
height: 100px;
left: 200px;
position: absolute;
top: 200px;
transition: transform 1s;
width: 100px;
transform-origin: right bottom;
}
div:hover {
transform: scale(1.5);
}
<div></div>
I think the problem is caused by the absolute positioning of your element to the body. After the transition is done, the browser recalculate the absolute position to the parent element and translate is coming in the way. The solution might be easier than you think.
Create an outer container which "safes" the place for the inner container to grow in left/top direction. I think the example below will explain the rest. (tested in safari aswell!)
body {
/* just for better looks */
margin: 2rem;
}
/* out container zone */
.outer {
border: 1px solid #222;
width: 150px;
height: 150px;
position: relative;
}
/* inner element aligned to the right */
.inner {
background-color: green;
width: 100px;
height: 100px;
transition: all .5s;
position: absolute;
right: 0;
bottom: 0;
}
/* no translate, no problems */
.inner:hover {
width: 150px;
height: 150px;
}
<div class="outer">
<div class="inner">
</div>
</div>
Try this. I changed the definition of the transition.
div {
background-color: green;
height: 100px;
left: 200px;
position: absolute;
top: 200px;
transition: all 1s;
width: 100px;
}
div:hover {
height: 150px;
width: 150px;
transform: translate(-50%, -50%);
}
<div></div>
It's working on Safari
You need to use -webkit- with transition and transform
div {
background-color: green;
height: 100px;
left: 200px;
position: absolute;
top: 200px;
-webkit-transition: all 1s;
width: 100px;
}
div:hover {
height: 150px;
width: 150px;
height: 150px;
width: 150px;
-webkit-transform: translate(-50%, -50%);
}
<div></div>
Related
I am working a project on my favorite science stories animated using HTML. While I was working on it By just changing the position to fixed or nothing position of all my objects was changing. If you remove the position property from #Guy, you will notice that the image of Galileo will shift drastically. I just want to know why this happens.
:root {
--initX: 280px;
--initY: 70px;
--finalY: 600px;
}
body {
background-color: aqua;
padding: 0px;
margin: 0px;
}
#Guy {
z-index: 4;
height: 200px;
position: fixed;
width: auto;
transform: translate(800px, 450px);
}
#Galilo {
height: 50px;
width: auto;
z-index: -1;
transform: translate(290px, 5px) rotateZ(4deg);
}
#tower {
height: 650px;
width: 150px;
z-index: 0;
transform: translate(250px, 50px) rotateZ(4deg);
position: absolute;
background-color: grey;
}
#Lball {
height: 40px;
width: 40px;
z-index: 2;
border-radius: 50%;
transform: translate(var( --initX), var(--initY));
background-color: blue;
position: absolute;
animation: lite 2s linear 1s infinite forwards;
}
#Hball {
height: 50px;
width: 50px;
z-index: 3;
transform: translate(calc(var( --initX) + 75px), var(--initY));
border-radius: 50%;
background-color: red;
position: absolute;
animation: heavy 2s linear 1s infinite forwards;
}
#floor {
height: 25%;
width: 100%;
background-color: green;
position: absolute;
z-index: -1;
transform: translate(0px, 565px);
}
#hide {
height: 12%;
width: 100%;
background-color: green;
position: absolute;
z-index: 1;
transform: translate(0px, 650px);
}
#keyframes lite {
0% {
transform: translate(var( --initX), var(--initY))
}
90% {
transform: translate(var(--initX), calc(var(--finalY) + 12.5px))
}
100% {
transform: translate(var(--initX), calc(var(--finalY) + 12.5px))
}
}
#keyframes heavy {
0% {
transform: translate(calc(var( --initX) + 75px), var(--initY))
}
90% {
transform: translate(calc(var( --initX) + 75px), var(--finalY))
}
100% {
transform: translate(calc(var( --initX) + 75px), var(--finalY))
}
}
<div id="tower"></div>
<div id="Hball"></div>
<div id="Lball"></div>
<div id="floor"></div>
<div id="hide"></div>
<img src="stick fidure.png" alt="Dude thinking" id="Guy">
<img src="galileo-galilei.png" alt="gallilo" id="Galilo">
P.S.
The link for the image of Galileo is https://cdn.images.express.co.uk/img/dynamic/109/590x/galileo-galilei-819977.jpg and the stick figure was made in Paint 3D
position: fixed takes the element out of the document flow and places it in relation to the viewport/window. Usually that also causes this element to overlap other elements. The other elements however will be rearranged in a way like the fixed element wouldn't be there (it's not in the document flow). So adding/removing position: fixed to/from an element will have all these effects on the overall document.
I want to achive a simple animation on hover in css, but while hovering off, the animation jumps and makes it look silly. Is there a way to avoid that?
My wish would be that it is colapsing the same way it originaly transformed.
Codepen: https://codepen.io/misah/pen/abzRXvL
.item {
width: 20%;
height: 0;
padding-top: 20%;
background-color: blue;
position: relative;
transition: 800ms;
}
.item::after {
position: absolute;
bottom: 0;
height: 30%;
width: 100%;
content: "";
background-color: grey;
transition: transform 800ms ease-in-out;
}
.item:hover::after {
transform: scaleY(2);
transform-origin: bottom;
}
<div class="item">
</div>
This happens because the transform-origin: bottom; is only applied when the item is hovered. When not hovered it falls back to the default - center. Move the rule to the declaration of the ::after.
.item {
width: 20%;
height: 0;
padding-top: 20%;
background-color: blue;
position: relative;
transition: 800ms;
}
.item::after {
position: absolute;
bottom: 0;
height: 30%;
width: 100%;
content: "";
background-color: grey;
transition: transform 800ms ease-in-out;
transform-origin: bottom;
}
.item:hover::after {
transform: scaleY(2);
}
<div class="item"></div>
I've been trying to create a simple css spinner which is shown while my page is loading by using a pseudo element overlaying a div where content will be shown.
It uses border-radius and transform: rotate() to achieve this effect but as you can see it wobbles strangely while rotating. The effect is more or less obvious depending on the screen size, zoom level and browser. I find it's most visible in MS Edge.
Example fiddle
.loading {
width: 75vh;
height: 100vh;
margin: auto;
background: white;
position: relative;
}
.loading::after {
border: 6vmin solid lightblue;
border-top: 6vmin solid darkblue;
position: absolute;
margin-top: 5vmin;
margin-left: 5vmin;
width: 15vmin;
height: 15vmin;
content: "";
border-radius: 50%;
animation: spin .5s linear infinite;
}
#keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
<div class="loading"></div>
There's some weird cut going on with the border-radius
Change it to border-radius: 1000px and see what happens
Changing the width and height to a pixel value seems to fix the issue. It may not be the best solution, but hey, it works.
To make this appropriate for all screen sizes, you need to use #media. In the bottom of the css I have added one that changes the size if the screen size is smaller than 700px just to show you how to do it, and if you want to change the numbers around or something, you at least know how #media can be used :)
Here is the code for changing the size depending on the screen-size of the users device.
#media (max-width: 700px){
.loading::after {
width: 100px;
height: 100px;
}
}
If you want to make it different on large screens too, just swap out "max-width: 700px" with "min-width: 1500px" or a value of your choice :)
http://jsfiddle.net/hfsqebsn/5/
Again, there are probably better ways, but this works :)
Edit: I think I may have changed around some other stuff in the fiddle I linked for testing purposes, so just beware of that :P
This issue was driving me crazy all day. I was able to solve it personally by making the ring thicker than desired and then masking over its inner and outer portions to hide the wobble from the viewer.
Solution.
https://codepen.io/corbinmosher/pen/GRWmYjy
Solution with background coloring to help with understanding it.
https://codepen.io/corbinmosher/pen/bGqWmEj
<div class="spinner__container">
<div class="spinner__ring"></div>
<div class="spinner__outline"></div>
</div>
.spinner__container {
position: relative;
width: 58px;
height: 58px;
background-color: white;
}
.spinner__ring {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: calc(100% - 8px);
height: calc(100% - 8px);
border-radius: 50%;
}
.spinner__ring:before {
position: absolute;
top: -1px;
left: -1px;
width: calc(100% + 2px);
height: calc(100% + 2px);
border: 10px solid lightblue;
border-top: 10px solid blue;
box-sizing: border-box;
content: '';
border-radius: 50%;
animation: rotate-spinner 1s linear infinite;
}
.spinner__ring:after {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: calc(100% - 8px);
height: calc(100% - 8px);
box-sizing: border-box;
content: '';
border-radius: 50%;
background-color: white;
}
.spinner__outline {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: calc(100% - 8px);
height: calc(100% - 8px);
border-radius: 50%;
border: solid 2px white;
}
#keyframes rotate-spinner {
0% {
transform: rotate(405deg);
}
100% {
transform: rotate(765deg);
}
}
#-webkit-keyframes rotate-spinner {
0% {
transform: rotate(405deg);
}
100% {
transform: rotate(765deg);
}
}
I see a white line between skewed HTML divs on Chrome browser. Below is a screenshot of the issue:
Here's the code :
.abc {
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
backface-visibility: hidden;
width: 200px;
height: 200px;
background: green;
position: absolute;
left:0px;
transform: skewX(-10deg);
transform-origin: 0% 100%;
}
.def {
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
backface-visibility: hidden;
width: 200px;
height: 200px;
background: green;
position: absolute;
left:200px;
transform: skewX(-10deg);
transform-origin: 0% 100%;
}
A debug sample is available at : https://jsbin.com/dijazit/2/edit?html,css,output
How do we remove this white line? Appreciate any help here.
This is kind of a known issue with respect to rendering transformed elements in Chrome. What makes it more weird is the fact that we come across many similar issues and each time the fix applied for the previous (very similar) case ends up not working for the current one.
For this particular scenario, adding a transparent 1 pixel border around the elements seems to fix it.
.abc {
position: absolute;
left: 0px;
width: 200px;
height: 200px;
background: green;
transform-origin: 0% 100%;
transform: skewX(-10deg);
border: 1px solid transparent;
}
.def {
position: absolute;
left: 200px;
width: 200px;
height: 200px;
background: green;
transform-origin: 0% 100%;
transform: skewX(-10deg);
border: 1px solid transparent;
}
<div class="abc"></div>
<div class="def"></div>
I would move the second element left by one pixel. So instead of:
left: 200px;
use:
left 199px;
See the snippet below:
NB! You could also want to increase the width of the element by 1px to keep the exact dimensions.
.abc {
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
backface-visibility: hidden;
width: 200px;
height: 200px;
background: green;
position: absolute;
left:0px;
transform: skewX(-10deg);
transform-origin: 0% 100%;
}
.def {
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
backface-visibility: hidden;
width: 200px;
height: 200px;
background: green;
position: absolute;
left:199px;
transform: skewX(-10deg);
transform-origin: 0% 100%;
}
<div class="abc"></div>
<div class="def"></div>
I'm looking to recreate an effect like this with CSS 3D Transforms:
How do I achieve this? Here's what I've got so far
body {
perspective: 400px;
transition: perspective 1s;
}
.grid {
display: flex;
justify-content: center;
align-items: center;
background-image: url("http://i.imgur.com/3ACizko.jpg");
background-size: cover;
height: 400px;
width: 400px;
transform: rotateX(60deg);
margin: 0 auto;
transition: transform 1s;
perspective: 400px;
}
.grid p {
transition: transform 1s;
transform: rotateX(-60deg);
}
<div class="grid">
<p>Hello</p>
</div>
I thought that if I rotated the background surface 60 degrees and rotated the text -60 degrees it would cancel out the effect but apparently not?
Anyway, thanks in advance.
Yes, ther solution to your problem is using transform-style: preserve-3d.
But the problem with this is that IE does not support this property
A way to make it work in IE is to use a pseudo element on the p
.grid {
font-size: 30px;
position: relative;
left: 100px;
top: 200px;
perspective: 200px;
perspective-origin: 0% 50%;
}
.grid:after {
content: "";
position: absolute;
width: 300px;
height: 200px;
top: -100px;
left: -100px;
transform: rotateX(30deg);
background-image: repeating-linear-gradient(0deg, transparent 0px, transparent 47px, black 47px, black 50px),
repeating-linear-gradient(90deg, transparent 0px, transparent 47px, black 47px, black 50px);
}
<p class="grid">Hello</p>
After a bit of research, I am confident to post my own answer.
This effect can be achieved using the transform-style property, and setting it to preserve-3d. This would be set to the parent element (in this case, .grid). I also use transform-origin:bottom to raise the text from inside the grid. Here's the snippet:
body {
perspective: 400px;
transition: perspective 1s;
}
.grid {
display: flex;
justify-content: center;
align-items: center;
background-image: url("http://i.imgur.com/3ACizko.jpg");
background-size: cover;
height: 400px;
width: 400px;
transform: rotateX(60deg);
margin: 0 auto;
transition: transform 1s;
perspective: 400px;
transform-style:preserve-3d;
}
.grid p {
transition: transform 1s;
transform-origin:bottom;
transform: rotateX(-60deg);
}
<div class="grid">
<p>Hello</p>
</div>