CSS3 Translate across an Arc - css

Is it at all possible with current CSS3 to translate an object (specifically a DIV) along an arc or curve? Here's an image to help illustrate.

You can use nested elements and make the wrapper and inner element rotate in opposite directions so that the rotation of the inner element compensates for the rotation of the wrapper.
If you don't need to keep the nested element horizontal, you can omit the inner rotation.
Here is a Dabblet. Stack Snippet:
/* Arc movement */
.wrapper {
width: 500px;
margin: 300px 0 0;
transition: all 1s;
transform-origin: 50% 50%;
}
.inner {
display: inline-block;
padding: 1em;
transition: transform 1s;
background: lime;
}
html:hover .wrapper {
transform: rotate(180deg);
}
html:hover .inner {
transform: rotate(-180deg);
}
<div class="wrapper">
<div class="inner">Hover me</div>
</div>
Also, Lea Verou wrote an article on this issue with a way that use only one element: http://lea.verou.me/2012/02/moving-an-element-along-a-circle/

Yes, that animation can be created using the transform-origin CSS3 property to set the rotation point in the far right so it moves like that.
Check it out: http://jsfiddle.net/Q9nGn/4/ (put your mouse over)
#c {
border: 1px solid black;
height: 400px;
}
#c:hover #m {
-webkit-transform: rotate(180deg);
-webkit-transition: all 1s ease-in-out;
-moz-transform: rotate(180deg);
-moz-transition: all 1s ease-in-out;
-o-transform: rotate(180deg);
-o-transition: all 1s ease-in-out;
-ms-transform: rotate(180deg);
-ms-transition: all 1s ease-in-out;
transform: rotate(180deg);
transition: all 1s ease-in-out;
}
#m {
width: 60px;
height: 60px;
position: absolute;
background: green;
border-radius: 30px;
top: 270px;
left: 20px;
-webkit-transform-origin:300px 30px;
-moz-transform-origin:300px 30px;
-o-transform-origin:300px 30px;
-ms-transform-origin:300px 30px;
transform-origin:300px 30px;
}
<div id="c">
<div id="m"></div>
</div>

An alternative to moving the transform origin, is to use a double nested element where an x-transform is applied to the outer container, and a y-transform with an appropriate easing curve is applied to the inner container.

Related

Safari CSS transition on scale with border radius

I came across a strange issue on Safari. Please take a look at: https://codepen.io/enguerranws/pen/PomzqWe
If you go hover the lightly red box, you'll notice a transition on an element inside.
If you test it in Chrome or Firefox, the animation runs as expected: it's a small black circle that scales up.
On Safari, it goes weird: it's a black square with some kind of transparency that goes round and fully opaque when the transition ends.
Here's the relevant part of code:
#test:hover #circle {
transform: scale(200);
}
#circle {
position: absolute;
transition: -webkit-transform .5s ease-in-out;
transition: transform .5s ease-in-out;
/* transition: all 1s ease; */
width: 2px;
height: 2px;
top: 30px;
border-radius: 10px;
mix-blend-mode: difference;
background-color: #000;
}
Does anyone as quick and dirty hack for this?
EDIT:
Actually, I found a way to get around this issue using width and height values for transform.
Try to use will-change: transform;. Added to your code:
#test {
width: 400px;
height: 400px;
position: relative;
overflow: hidden;
padding: 40% 10px;
background: rgba(255,0,0,.1);
}
#test:hover #circle {
transform: scale(1);
}
#circle {
position: absolute;
transition: transform .5s ease-in-out;
will-change: transform;
transform: scale(.005); /* point */
transform-origin:left top;
width: 2px;
height: 2px;
top: 30px;
border-radius: 400px;
width: 400px;
height: 400px;
background-color: #000;
}
<div id="test">
<div id="circle"></div>
Text here
</div>

Z-Index in combination with position: fixed and transitions (CSS)

I'm setting up a new portfolio website and use the Onepage Scroll Plugin by Pete R.
I added a fix navigation bar and now want to have elements inside a slide overlapping this navigation. Here's a code example at codepen:
http://codepen.io/terrorpixel/pen/BNxYxq
HTML
<nav></nav>
<div class="container">
<div>Bring me to the front!</div>
</div>
CSS
nav {
height: 82px;
left: 0;
position: fixed;
top: 0;
-webkit-transition: background 1.15s ease-in-out 0s;
-moz-transition: background 1.15s ease-in-out 0s;
transition: background 1.15s ease-in-out 0s;
width: 100%;
z-index: 2;
background:rgba(0,255,0,.85);
}
.container {
background:blue;
position: relative;
-webkit-transform: translate3d(0px, -1%, 0px);
-moz-transform: translate3d(0px, -1%, 0px);
transform: translate3d(0px, -1%, 0px);
-webkit-transition: all 2s ease 0s;
-moz-transition: all 2ms ease 0s;
transition: all 2ms ease 0s;
height: 5000px;
z-index:1;
width: 70%;
margin: 0 auto;
}
.container div {
padding: 250px 100px;
z-index:10;
position:absolute;
right:0;
top:0;
background:red;
}
I try to get the red box to the front. I think the failure belongs to the fact that I'm using z-index in different stacking contexts. The inside the .container hadn't worked, too.. Is there actually a possibility to realize that :/?
You need to move .container div outside of .container.
When you place a positioned element inside a positioned element, the children start a new stacking order but it starts in context with the parents value. So even if you specify a z-index value of 10000 to a child of a parent with a z-index of 2 its like the child has a z-index of 2.10000.
This example is crude but you get the idea:
nav {
height: 82px;
left: 0;
right: 0;
position: fixed;
top: 0;
-webkit-transition: background 1.15s ease-in-out 0s;
-moz-transition: background 1.15s ease-in-out 0s;
transition: background 1.15s ease-in-out 0s;
z-index: 2;
background: rgba(0, 255, 0, .85);
}
.container {
background: blue;
position: relative;
-webkit-transform: translate3d(0px, -1%, 0px);
-moz-transform: translate3d(0px, -1%, 0px);
transform: translate3d(0px, -1%, 0px);
-webkit-transition: all 2s ease 0s;
-moz-transition: all 2ms ease 0s;
transition: all 2ms ease 0s;
height: 5000px;
z-index: 1;
width: 70%;
margin: 0 auto;
}
.front {
z-index: 3;
position: absolute;
right: 15%; /* half of 30% (the left over of 70% container width) */
top: 82px;
background: red;
}
<nav></nav>
<div class="container">
</div>
<div class="front">Bring me to the front!</div>
</div>

Why is transition on 'transform: scale()' makes an element become pixelated in webkit browsers?

If I scale an element using CSS scale() it becomes pixelated while transitioning. But it becomes normal again when transition is finished (refer to the screenshot 1). However it happens only in webkit browsers (tested in Chrome and Opera)
.foo {
background: #4FC093;
display: block;
position: absolute;
width: 20px;
height: 20px;
box-shadow: 0 0 10px inset;
margin: 0 auto;
border-radius: 50%;
left: 50%;
top: 50%;
cursor: pointer;
-webkit-transition: all 3s ease;
-moz-transition: all 3s ease;
-ms-transition: all 3s ease;
transition: all 3s ease;
}
.foo:hover {
-webkit-transform: scale(20);
-moz-transform: scale(20);
-ms-transform: scale(20);
transform: scale(20);
}
<div class="foo"></div>
Screenshot 1
A possible workaround
I have also tried using scale3d() with reversing the scale of this div, as suggested here
But it caused a jagged edge around the div in Google Chrome.
.foo {
background: #4FC093;
display: block;
position: absolute;
width: 400px;
height: 400px;
box-shadow: 0 0 200px inset;
margin: 0 auto;
border-radius: 50%;
cursor: pointer;
-webkit-transition: all 3s ease;
-moz-transition: all 3s ease;
-ms-transition: all 3s ease;
transition: all 3s ease;
-webkit-transform: scale3d(0.05, 0.05, 0.05);
-moz-transform: scale3d(0.05, 0.05, 0.05);
-ms-transform: scale3d(0.05, 0.05, 0.05);
transform: scale3d(0.05, 0.05, 0.05);
}
.foo:hover {
-webkit-transform: scale3d(1, 1, 1);
-moz-transform: scale3d(1, 1, 1);
-ms-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
<div class="foo"></div>
I don't want the edges to be jagged. I have tried using -webkit-backface-visibility: hidden here but there's no luck. I know there is a property called -webkit-font-smoothing where we can set the font-smoothing as antialiased. Is there any way that we can set antialiased for a div?
Screenshot 2
Lastly, this is not a solution of my problem and I would like to avoid using this workaround as I'll have to go through and calculate the parameter values of scale3d() manually.
I am expecting the solution of first case here.
Yes, there is a fix, make the element big and scale to smaller at the initial state. Then on hover scale to 1, and now it's very smooth and not pixelated.
.foo {
background: #4FC093;
display: block;
position: absolute;
width: 200px;
height: 200px;
box-shadow: 0 0 10px inset;
margin: 0 auto;
border-radius: 50%;
left: 50%;
top: 50%;
cursor: pointer;
-webkit-transition: all 3s ease;
-moz-transition: all 3s ease;
-ms-transition: all 3s ease;
transition: all 3s ease;
-webkit-transform: scale(.20);
-moz-transform: scale(.20);
-ms-transform: scale(.20);
transform: scale(.20);
}
.foo:hover {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
It will be a little more work, but you may want to consider not using scale.
If you're planning on resizing css shapes, you may be able to get away with just transitioning the attributes you used to draw the shapes and using a wrapper div for positioning.
Working Example
html:
<div class="row"> <!-- use a parent div to create rows -->
<div class="wrap"> <!-- use a wrapper to position -->
<div class="foo"></div>
</div>
<div class="wrap">
<div class="foo"></div>
</div>
<div class="wrap">
<div class="foo"></div>
</div>
<div class="wrap">
<div class="foo"></div>
</div>
<div class="wrap">
<div class="foo"></div>
</div>
<div class="wrap">
<div class="foo"></div>
</div>
</div>
<div class="row">
<div class="wrap">
<div class="foo"></div>
</div>
<div class="wrap">
<div class="foo"></div>
</div>
<div class="wrap">
<div class="foo"></div>
</div>
</div>
css:
.wrap {
position: relative;
height:20px;
width:20px;
display: inline-block;
}
.foo {
position: absolute;
top: 190px;
left: 190px;
background: #4FC093;
display: block;
width: 20px;
height: 20px;
box-shadow: 0 0 10px inset;
border-radius: 50%;
cursor: pointer;
transition:all 3s ease;
z-index: 99;/*using an unnecessarily large z-index makes for a nicer transition in Chrome*/
}
.foo:hover {
top: 0px;
left: 0px;
width: 400px;
height: 400px;
box-shadow: 0 0 200px inset;
transition:all 3s ease;
z-index: 1;
}
I think the only solution to this is to initially scale down the element and then scaling it to normal size how Mazhar Ahmed already answered.
If you don't want to calculate the size manually, you could just use CSS variables like this:
--scale:0.1;
.element{
width: 40px * (1 / var(--scale));
height: 40px * (1 / var(--scale));
transform: scale(var(--scale));
}
.element:hover{
transform:scale(1);
}
As you can see, you only define the scale factor in a variable. CSS does the rest and sets the width and height accordingly.
So in our case the element would be 400x400px, but it's scaled down, so it appears to be 40x40px as defined in our CSS.
Just a small addition for the lazybones (like me).

Transform scale property not working in Chrome & Safari

.tricky {
width: 200px;
height: 200px;
border-radius: 50%;
border: 0px solid;
background: #2373bd;
display: inline-block;
position: relative;
overflow: hidden;
}
.tricky_image {
width: 100%;
height: 100%;
-moz-transition: all .6s ease;
-webkit-transition: all .6s ease;
-ms-transition: all .6s ease;
-o-transition: all .6s ease;
transition: all .6s ease;
opacity: 0.7;
border-radius: 50%;
filter: alpha(opacity=70);
overflow: hidden;
}
.tricky_image:hover {
opacity: 1;
filter: alpha(opacity=100);
-webkit-transform: scale(1.2);
transform: scale(1.2);
}
<!doctype html>
<html>
<head>
</head>
<body>
<div class="tricky">
<img class="tricky_image" src="location_images/sanfranciscoweb.png" alt="Example">
</div>
</body>
</html>
my desired effect is only working in Firefox and i assume IE. I am starting with a transparent image with a div wrapper around it with a blue background. When the user hovers over the image, i want it to zoom in and restore the opacity to 100% without breaking the set width and height of the div wrapper. This works perfectly in Firefox, but when i run the animation in Chrome the image exceeds the width of the blue div wrapper behind it. Here is my code and any help would be appreciated & JS Fiddle http://jsfiddle.net/yaLupdzo/1/:
<!doctype html>
<html>
<head>
<style>
.tricky {
width: 200px;
height: 200px;
border-radius: 50%;
border: 0px solid;
background: #2373bd;
display: inline-block;
position: relative;
overflow: hidden;
}
.tricky_image {
width: 100%;
height: 100%;
-moz-transition: all .6s ease;
-webkit-transition: all .6s ease;
-ms-transition: all .6s ease;
-o-transition: all .6s ease;
transition: all .6s ease;
opacity: 0.7;
border-radius: 50%;
filter: alpha(opacity=70);
overflow: hidden;
}
.tricky_image:hover {
opacity: 1;
filter: alpha(opacity=100);
-webkit-transform: scale(1.2);
transform: scale(1.2);
}
</style>
</head>
<body>
<div class="tricky">
<img class="tricky_image" src="location_images/sanfranciscoweb.png" alt="Example">
</div>
</body>
</html>
This is a known issue as filed here: https://code.google.com/p/chromium/issues/detail?id=157218
In Webkit, with hardware acceleration, animated layers get promoted to a different rendering surface during animation, and then demoted once the animation is complete.
Turns out there is a simple solution. Have the container element 'promoted' to the same rendering layer as the hardware accelerated child by adding a lightweight animation to it:
.tricky {
width: 200px;
height: 200px;
border-radius: 50%;
border: none;
background: #2373bd;
display: block;
overflow: hidden;
-webkit-transform:scale(1.0);
}
.tricky_image {
width: 200px;
height: 200px;
-webkit-transition: all .6s ease;
opacity: 0.7;
}
.tricky:hover {
-webkit-transform:scale(1.0);
}
.tricky:hover .tricky_image {
opacity: 1;
-webkit-transform:scale(1.2);
}
See: http://jsfiddle.net/yaLupdzo/3/
Note that I've also added a simple animation to the parent container's default state, so that the same issue doesn't happen when hovering out.
-webkit-transform: scale(1.2);
-moz-transform: scale(1.2);
-o-transform: scale(1.2);
transform: scale(1.2);
You can repeat your code like that for browser compatibility..

prevent children from inheriting transformation css3

I have a div that i'm tranforming (scale and translate), but inside that div i have another div. Now i would to see that the inner div isnt affected by the transformation of its parent, in other words. I would like for the inner div to not scale like his parent does.
Here is the html:
<div id="rightsection">
<div class="top"></div>
<div class="middle">
<div class="large">
<img src="assets/images/rightpanel_expanded.png" alt="map" title="map"/>
</div>
</div>
<div class="bottom">
<p>Check if your friends are going!</p>
</div>
</div>
Here is my css:
#rightsection:hover {
-moz-transform:scale(2.16,2.8) translate(-80px,-53px);
-webkit-transform:scale(2.16,2.8) translate(-80px,-53px);
-o-transform:scale(2.16,2.8) translate(-80px,-53px);
-ms-transform:scale(2.16,2.8) translate(-80px,-53px);
transform:scale(2.16,2.8) translate(-80px,-53px)
}
So the problem is, when i scale #rightsection, the img gets scaled to, but i would like to keep the image on its original size.
Any help is appreciated.
Here is it what worked for me..
I used opposite transition for children. Then it was stable
.logo {
background: url('../images/logo-background.png') no-repeat;
width: 126px;
height: 127px;
margin-top:-24px;
z-index: 10;
display: block;
}
a.logo span{
display: block;
width: 126px;
height: 127px;
background: url('../images/logo-bismi.png') no-repeat;
z-index: 20;
text-indent: -9999px;
text-transform: capitalize;
-webkit-transition: -webkit-transform 0.4s ease-out;
-moz-transition: -moz-transform 0.4s ease-out;
transition: transform 0.4s ease-out;
}
a.logo:hover span{
-webkit-transform: rotateZ(-360deg);
-moz-transform: rotateZ(-360deg);
transform: rotateZ(-360deg);
}
a.logo {
-webkit-transition: -webkit-transform 0.4s ease-out;
-moz-transition: -moz-transform 0.4s ease-out;
transition: transform 0.4s ease-out;
}
a.logo:hover{
-webkit-transform: rotateZ(360deg);
-moz-transform: rotateZ(360deg);
transform: rotateZ(360deg);
}
Do as usual. Set "transform: none" to all of children.
.children1,
.children2,
.childrenN {
-moz-transform: none;
-webkit-transform: none;
-o-transform: none;
-ms-transform: none;
transform: none;
}
.parent {
position: relative;
background-color: yellow;
width: 200px;
height: 150px;
margin: 70px;
-webkit-transform: rotate(30deg);
-moz-transform: rotate(30deg);
-o-transform: rotate(30deg);
-ms-transform: rotate(30deg);
transform: rotate(30deg);
}
.child {
position: absolute;
top: 30px;
left: 50px;
background-color: green;
width: 70px;
height: 50px;
-webkit-transform: rotate(-30deg);
-moz-transform: rotate(-30deg);
-o-transform: rotate(-30deg);
-ms-transform: rotate(-30deg);
transform: rotate(-30deg);
}
<div class="parent">
<div class="child"></div>
</div>
First you can make the children of the parent positioned in the 3D-space by set transform-style: preserve-3d; in parent, then you can apply transform-functions in reverse order of parent to children elements that want to keep front.
.parent {
transform: rotateX(33deg) rotateY(66deg) rotateZ(99deg);
/* Notice! You should make the children of the parent positioned in the 3D-space. */
transform-style: preserve-3d;
position: relative;
width: 300px;
height: 300px;
margin: 50px auto;
border: 4px solid darkblue;
}
.child {
/* Notice! You should apply the opposite order of rotations (transform functions) from the parent element. */
transform: rotateZ(-99deg) rotateY(-66deg) rotateX(-33deg);
position: absolute;
width: 80px;
height: 80px;
background: aqua;
}
<div class="parent">
<div class="child">
I'am a child want keep front.
</div>
</div>
See: css - How to prevent children from inheriting 3d transformation CSS3? - Stack Overflow
This should work as a general rule in most cases.
You can apply the same rule to the other transform methods.
.parent {
transform: rotate(-90deg);
}
.parent > * {
/* to cover elements like <span> */
display: block;
transform: rotate(90deg);
}

Resources