Make child element unaffected by rotation of parent element - html

I have two div elements: one parent element, which is rotated, and one child element that I need to be unaffected by the rotation of the parent element.
To achieve this, I have attempted to rotate the child element in the opposite direction of the parent element. This works in some cases. For instance, if I rotate the elements like this ...
.parent {
transform: rotate(30deg);
}
.child {
transform: rotate(-30deg);
}
... the child element will appear straight and undistorted. But if I rotate them with rotateX ...
.parent {
transform: rotateX(30deg);
}
.child {
transform: rotateX(-30deg);
}
... the child element still looks rather distorted.
The actual code uses both rotateX and rotateZ in order to make the parent element appear isometric. It currently looks like this:
.happy_parent {
width: 100px;
height: 100px;
background-color: green;
transform: rotate(30deg);
}
.happy_child {
width: 50px;
height: 50px;
background-color: yellow;
transform: rotate(-30deg);
}
.sad_parent {
width: 100px;
height: 100px;
background-color: green;
transform: rotateX(-60deg) rotateZ(45deg);
}
.sad_child {
width: 50px;
height: 50px;
background-color: yellow;
transform: rotateX(60deg) rotateZ(45deg);
}
<div class="happy_parent">
<div class="happy_child"></div>
</div>
<div class="sad_parent">
<div class="sad_child"></div>
</div>
Notice that the upper divs are both rendered correctly, but the lower child-div is still distorted.
What am I missing here?

It is not possible to have the innerElement (childElement) to remain in initial state when rotated in 3D by rotating back in -ve deg.
It will work when rotation takes place in 2D .
But you can give a try to transform-style: preserve-3d to see the shapes in 3D effect when rotated with Z coordinate also and preserve the shape instead of just showing in 2D .
You have to reverse the order of rotation too in 3D rotation
You can try to remove the transform-style: preserve-3d and see the effect
.happy_parent {
width: 100px;
height: 100px;
background-color: green;
transform: rotate(30deg);
}
.happy_child {
width: 50px;
height: 50px;
background-color: yellow;
transform: rotate(-30deg);
}
.sad_parent {
width: 100px;
height: 100px;
background-color: green;
transform: rotateX(-60deg) rotateZ(45deg);
transform-style: preserve-3d;
}
.sad_child {
width: 50px;
height: 50px;
background-color: yellow;
transform: rotateZ(-45deg) rotateX(60deg);
}
<div class="happy_parent">
<div class="happy_child"></div>
</div>
<br><br><br><br>
<div class="sad_parent">
<div class="sad_child"></div>
</div>

Related

How to lay out with z-index positioned elements in a third level hierarchy

I have a problem with z-index property. I have some absoluted positioned elements (div in the code)one inside each other. The first div inside (red div) naturally would be in front of its parent (aliceblue element), thus I give a negative z-index to the red div inside and it's ok. But the aqua div (inside the red div) is in front of red element too (instead I would lay out the aqua element behind the red element), to lay out it behind I give it z-index:-5 for example but it doesn't work because I created a new stacking context different from stacking context of its father
div {
width: 300px;
height: 300px;
text-align: center;
position: absolute;
}
.a {
background-color: aliceblue;
position: relative;
}
.a1 {
background-color: red;
left: 20px;
top: 20px;
z-index: -1;
}
.a11 {
background-color: aqua;
left: 10px;
top: 10px;
/* z-index: -5; This doesn't work*/
}
.a2 {
background-color: yellow;
top: 40px;
z-index: -2;
}
<div class="a">
A
<div class="a1">
A1
<div class="a11">A11</div>
</div>
<div class="a2">A2</div>
</div>
So far we haven't found a way to do this using z-index.
The following method may or may not be suitable for your particular use case/overall context but it does solve the problem for the code given in the question.
This snippet uses 3d transforms rather than z-index to position the elements in relation to the viewer who is looking head on to the screen.
Of course we don't actually want to introduce perceptible perspective so the snippet uses a small shift back (0.1px). This seems enough to get the system to position elements on top of each other in the required order but small fractions were ignored (at least on my Windows10 Edge).
div {
width: 300px;
height: 300px;
text-align: center;
position: absolute;
transform-style: preserve-3d;
}
.a {
background-color: aliceblue;
position: relative;
transform: translate3d(0, 0, 0);
}
.a1 {
background-color: red;
left: 20px;
top: 20px;
transform: translate3d(0, 0, -0.1px);
}
.a11 {
background-color: aqua;
left: 10px;
top: 10px;
transform: translate3d(0, 0, -0.2px);
}
.a2 {
background-color: yellow;
top: 40px;
transform: translate3d(0, 0, -0.4px);
}
<div class="a">
A
<div class="a1">
A1
<div class="a11">A11</div>
</div>
<div class="a2">A2</div>
</div>

Transform rotation does not cover the ends of layout

My code is as shown below:
.test {
position: relative;
top: 1080px;
width: 100%;
height: 100px;
background-color: black;
transform: rotate(-6deg);
}
<div class="test">this is test</div>
With this code, I get strip like this:
But I want the strip to be like this:
You can use transform: skewY instead:
.test {
position: relative;
top: 50px;
width: 100%;
height: 100px;
background-color: black;
transform: skewY(-10deg);
color: white;
}
.orange {
background:orange;
}
.orange span {
transform: skewY(10deg);
display: inline-block;
}
<div class="test">first div</div>
<div class="test orange"><span>second div</span></div>
Change the value of the top based on your need. I didn't use the 1080px so there will be no scroll in this example...
update
Also added an example on how to "align" a text back to the normal alignment inside a skewed element.

prevent children from inheriting translateZ property

I am trying to create a 3d cube effect using css3. I am using translateZ property to create the 3d cube environment when I use translateZ on parent div the child div automatically inherits the property. I have tried to use transform: none and the tried to give negative transform but of no use. Here is an example fiddle
HTML
<div class="box-big">
<div class="box">
<h1>ABCD</h1>
</div>
</div>
CSS
body{
perspective: 1000px;
}
.box-big{
transform-style: perserve-3D;
}
.box{
width: 300px;
height: 300px;
background: #FF0000;
transform: translateZ(400px);
}
h1{
font-color: white;
line-height: 300px;
text-align: center;
transform: translateZ(-400px);
}
All the children of the parent are going to be rendered according to the parent, so what you are asking is not possible. You would have to re-transform it to what you want, or probably your best bet is to use some "layering" technique (such as position: absolute or negative margins) so that the h1 can be outside of the .box element, but still appear "on top" of the .box element.
Here's a working example:
Modified HTML:
<div class="wrapper">
<div class="box-big">
<div class="box">
</div>
</div>
<h1>ABCD</h1>
</div>
Modified CSS:
body{
perspective: 1000px;
}
.wrapper {
position: relative;
}
.box-big {
transform-style: preserve-3D;
}
.box{
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 200px;
background: #FF0000;
transform: translateZ(300px);
z-index: 1;
}
h1 {
position: absolute;
top: 0;
left: 0;
width: 200px;
color: white;
line-height: 200px;
text-align: center;
z-index: 255555;
}
https://jsfiddle.net/kcobbvcL/4/
As a side note, your fiddle css has some typos. Be sure to use a good IDE or a browser tool to watch for illegal / invalid css.
every cube has 6 sides, so u should use 6 div s. As we want to move the whole cube we should include those 6 div s in one div (div#cube).
first, you should create the cube using css, as the example below, then you translate or rotate the cube, using transform in div#cube.
.container {
width: 200px;
height: 200px;
position: relative;
perspective: 1000px;
}
#cube {
width: 100%;
height: 100%;
position: absolute;
transform-style: preserve-3d;
}
#cube figure {
width: 196px;
height: 196px;
display: block;
position: absolute;
border: 2px solid black;
}
#cube .front { transform: rotateY( 0deg ) translateZ( 100px ); }
#cube .back { transform: rotateX( 180deg ) translateZ( 100px ); }
#cube .right { transform: rotateY( 90deg ) translateZ( 100px ); }
#cube .left { transform: rotateY( -90deg ) translateZ( 100px ); }
#cube .top { transform: rotateX( 90deg ) translateZ( 100px ); }
#cube .bottom { transform: rotateX( -90deg ) translateZ( 100px ); }
#cube{
transition: all 1s;
}
#cube:hover{
transform: rotateY( -20deg );
/*transform: translateZ( -100px );*/
}
<section class="container">
<div id="cube">
<figure class="front">1</figure>
<figure class="back">2</figure>
<figure class="right">3</figure>
<figure class="left">4</figure>
<figure class="top">5</figure>
<figure class="bottom">6</figure>
</div>
</section>

How to use transform:translateX to move a child element horizontally 100% across the parent

All,
I'd like to be able to use translateX to animate a child element 100% of the way across it's parent (i.e., from the left edge to the right edge).
The challenge is that percentages in translateX refer to the element itself, not the parent.
So, for example, if my html looks like this:
<div id="parent">
<div id="child">
</div>
And my CSS like this (vendor-prefixes omitted):
#parent {
position: relative;
width: 300px;
height: 100px;
background-color: black;
}
#child {
position: absolute;
width: 20px;
height: 100px;
background-color:red;
transform: translateX(100%);
}
This doesn't work - the child only moves 20px (100% of itself), not all the way across the parent. (You can see this on jsfiddle):
I can do this:
#child {
position: absolute;
width: 20px;
height: 100px;
background-color:red;
-webkit-transform: translateX(300px) translateX(-100%);
transform: translateX(300px) translateX(-100%);
}
This works (seen here again on jsfiddle), because it first moves the child 300px (the full width of the parent), minus 20px (the width of the child). However, this depends on the parent having a fixed, known pixel dimension.
However, in my responsive design - I don't know the width of the parent, and it will change.
I know that I can use left:0 and right:0, but the animation performance of left/right is much worse than translateX (Thanks Paul Irish!).
Is there a way to do this?
Thanks in advance.
I didn't post my idea originally, because it involves creating an additional HTML layer, and expected better solutions to come.
Since that hasn't happened, I explain my comment. What I meant was this:
#parent {
position: relative;
width: 300px;
height: 100px;
background-color: black;
}
#wrapper {
position: absolute;
width: 100%;
height: 100px;
border: solid 1px green;
transition: all 1s;
}
#wrapper:hover {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
#child {
position: absolute;
width: 20px;
height: 100px;
background-color:red;
}
#wrapper:hover #child {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
Since the wrapper is 100% width of the parent, translating it 100% works as expected.
fiddle
Note that the wrapper is being translated 100% as you stated. However, seems that what you really want is to move the element 100% - width. To achieve this, you have to translate the child also 100% (now this applies to the child width) in the opposite direction.
Correction: the child should share the transition property of the wrapper:
#parent {
position: relative;
width: 300px;
height: 100px;
background-color: black;
}
#wrapper {
position: absolute;
width: 100%;
height: 100px;
border: solid 1px green;
transition: all 5s;
}
#wrapper:hover {
transform: translateX(100%);
}
#child {
position: absolute;
width: 50px;
height: 100px;
background-color:red;
transition: inherit;
}
#wrapper:hover #child {
transform: translateX(-100%);
}
<div id="parent">
<div id="wrapper">
<div id="child"></div>
</div>
</div>
There's a pretty cool solution to this problem using Flexbox. The key is to take advantage of the flex-grow property.
Say you have some HTML that looks like this:
<div class="flex-container">
<div class="flex-spacer"></div>
<div class="slider"></div>
</div>
First, give .flex-container the basic display: flex property, and set its flex-direction to row. Set the positioning of the child elements to relative, so they will sit next to each other inside .flex-container.
By default, the flex-grow property is set to 0, which is exactly what we want at the beginning. This means that .flex-spacer and .slider will only have their normal dimensions to begin with. We simply keep .flex-spacer empty, and it will have a width of 0.
Now for the animation. We only need two CSS rules to make it work: add a transition to .flex-spacer and set flex-grow to 1 on .flex-spacer during some event. The second rule gives all of the unused width inside .flex-container to the width of .flex-spacer, and the first rule animates the change in width. The .slider element gets pushed along to the edge of .flex-container.
The CSS looks something like this - I added a background to .flex-spacer to make its presence a little more obvious, and set flex-grow to 1 when the user hovers over .flex-container:
body * {
box-sizing: border-box;
}
.flex-container {
cursor: pointer;
display: flex;
flex-flow: row nowrap;
width: 100%;
border: 2px solid #444;
border-radius: 3px;
}
.flex-spacer,
.slider {
flex-grow: 0;
position: relative;
}
.slider {
padding: 25px;
background-color: #0DD;
}
.flex-spacer {
background-color: #DDD;
transition: all .4s ease-out;
}
.flex-container:hover .flex-spacer {
flex-grow: 1;
}
<div class="flex-container">
<div class="flex-spacer"></div>
<div class="slider"></div>
</div>
Flexbox makes this pretty configurable, too. For example, say we want .slider to move from right to left, instead. All we have to do is switch the flex-direction property in .flex-container to row-reverse, and we're done!
Feel free to play with it in this pen.
Keep in mind that things can get a little trickier if we want animations for different types of events. For example, I came across this issue when trying to animate a label when a user types in an input element. A little more HTML and CSS is needed to make it work (I used some JS, as well), but the concept is the same.
Here's another pen, this time in the context of a form with input.
With the recent addition of Size Container Queries it is now possible to do this by setting the container-type property to inline-size in the parent and then translating the child element by 100cqw - 100% where 100cqw is the full width of the parent and 100% is the width of the child.
#parent {
position: relative;
width: 300px;
height: 100px;
background-color: black;
container-type: inline-size;
}
#child {
position: absolute;
width: 20px;
height: 100px;
background-color:red;
transform: translateX(calc(100cqw - 100%));
}
<div id="parent">
<div id="child">
</div>
I implemented this using wrapper and flex-grow:1.
Here are two animations at the same time with the same duration: 1) the container (green) moves with the car at 100% of the parent's width; 2) the car moves back -100% of its width (to stay on the track at the finish line). The duration can be taken separately and distributed to the container (.track-inner) and the car (.car)
const goBtn = document.querySelector('.go');
const inner = document.querySelector('.track-inner');
const car = document.querySelector('.car');
const durationFromServerMS = '3000ms';
goBtn.addEventListener('click', ()=>{
inner.classList.add('drive');
inner.style.animationDuration = durationFromServerMS;
car.classList.add('backShift');
car.style.animationDuration = durationFromServerMS;
})
const backBtn = document.querySelector('.back');
backBtn.addEventListener('click', ()=>{
inner.classList.remove('drive');
car.classList.remove('backShift');
})
html, body {
padding: 2rem;
}
.track{
width: 50%;
display:flex;
position: relative;
background-color: gray;
width: auto;
margin-bottom: 1rem;
border: 5px dashed blue;
overflow:hidden;
}
.track-inner{
width: 100%;
border: 5px dotted green;
}
.car{
width: 3rem;
height: 1.5rem;
border: 1px solid black;
background-color: salmon;
}
.finish-line{
position:absolute;
top:0;
right: 0.5rem;
width: 3rem;
height: 1.5rem;
border-left: 6px dotted yellow;
}
button{
padding: 0.5rem 1rem;
background-color: lightblue;
outline: none;
border:none;
margin: 0.2rem
}
button:hover{
pointer:cursor;
background-color: salmon;
}
.backShift {
animation-name: car-back;
/* animation-duration: 5s; */
animation-timing-function: ease-in;
animation-fill-mode: forwards;
}
.drive {
animation-name: driving;
/* animation-duration: 5s; */
animation-timing-function: ease-in;
animation-fill-mode: forwards;
}
#keyframes driving {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(100%);
}
}
#keyframes car-back {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-100%);
}
}
p{
padding:0;
}
<div class="track">
<div class="track-inner">
<div class="car ">car</div>
</div>
<div class="finish-line">finish</div>
</div>
<div>
<button class='go'>Go</button>
<button class='back'>Back</button>
</div>

CSS3 Folding Animation with vertex

I need to fold a squared div with vertex. I found some examples in Internet to fold edges in a squared div. Someone know how can I make this animation? This is an example in flash but I want the same in CSS3 and HTML5.
Thanks for your help.
this is the example: Adidas
for this simple HTML
<div id="base">
<div id="clip">
<div id="image">
</div>
</div>
</div>
you set this CSS:
div {
overflow: hidden;
-webkit-transform-style: preserve-3d;
}
#base {
position: absolute;
top: 50px;
left: 50px;
width: 200px;
height: 200px;
transition: all 0.3s;
}
#clip {
width: 290px;
height: 290px;
-webkit-transform: rotateZ(-45deg);
-webkit-transform-origin: 0px 0px;
}
#image {
width: 200px;
height: 200px;
-webkit-transform: rotateZ(45deg);
-webkit-transform-origin: 0px 0px;
background-image: linear-gradient(0deg, red, blue);
}
#base:hover {
-webkit-transform: rotate3d(1,1,0,-45deg);
-webkit-transform-origin: center center;
}
Starting from a base square div, you rotate an inner div 45deg. this div will clip the other thru the diagonal.
Inside this one, you set another div with the image, counter rotated 45 deg to keep the image horizontal.
And you set in the hover the base the div to rotate in 3d around the diagonal
demo