I've got a simple display that flips over on click. I want to add a little bounce to the movement by rotating a few degrees in the opposite direction before rotating the full 180 degrees to reveal the opposite side.
RotateX() will accept more than one instance inline, but it calculates the end result and does not show both directions. ie:
transform: rotateX(-10deg) rotateX(190deg)
this results in the object rotating 180deg.
I've tried comma separating them, as well as just putting two sets of degress in the parens, with similar results.
I've tried putting both steps into #keyframes, but animation doesn't seem to work with my on-click event in javascript.
I've also tried having each direction of rotation in a separate class that are both activated via classlist.toggle, but still do not see both directions of rotation.
here's a codepen with the above mocked up:
https://codepen.io/Boreetos22/pen/WNrJEvR
I'd appreciate any insight. Thanks!
Transitions probably won't get what you want since you can't fake the bounce with multiple steps. #keyframes will work but you can't simply toggle the class. You need to add one and then add another to reset it.
Also, you'll need multiple animations (forward and back) that you change on over/out and click.
let sides = document.querySelector('.sides');
sides.addEventListener( 'click', function(e) {
if(sides.classList.contains('flip-forward')){
sides.classList.remove('flip-forward');
sides.classList.add('flip-backward');
}else{
sides.classList.add('flip-forward');
sides.classList.remove('flip-backward');
}
});
* {
padding: 0;
margin: 0;
}
h2 {
margin-top: 12px;
font-size: 30px;
}
body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
display: flex;
justify-content: center;
height: 60px;
width: 400px;
perspective: 1000px;
}
#keyframes myAnimationFwrd {
/* has bounce */
24% {
transform: rotateX( -40deg)
}
36% {
transform: rotateX( 0)
}
100% {
transform: rotateX( 190deg)
}
}
#keyframes myAnimationBkwrd {
/* no bounce add more steps to enable */
0% {
transform: rotateX( 190deg)
}
100% {
transform: rotateX( 0deg)
}
}
.flip-forward {
animation: myAnimationFwrd 1s forwards;
}
.flip-backward {
animation: myAnimationBkwrd 1s forwards;
}
.sides {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
position: relative;
transform-style: preserve-3d;
cursor: pointer;
}
.red, .black {
text-align: center;
color: white;
height: 100%;
width: 100%;
border-radius: 30px;
box-shadow: 2px 2px 4px black;
position: absolute;
backface-visibility: hidden;
}
.red {
background-color: darkred;
z-index: 2;
}
.black {
background-color: black;
z-index: 1;
transform: rotateX(180deg);
}
<div class="container">
<div class="sides">
<div class="red">
<h2>PLAYER ONE'S TURN</h2>
</div>
<div class="black">
<h2>PLAYER TWO'S TURN</h2>
</div>
</div>
</div>
Related
Code sandbox link: https://codesandbox.io/s/thirsty-moon-853e2k?file=/src/App.js:0-278
I want the pink circle to move in steps but it keeps moving in continuous fashion:
I tried using steps(3) steps(3,end) but none of that is working:
.Spinner {
height: 100vh;
width: 100vw;
background-color: gray;
display: flex;
align-items: center;
justify-content: center;
}
.DotLoader {
display: flex;
flex-direction: row;
column-gap: 0.5rem;
position: relative;
}
.DotLoader section {
height: 1rem;
aspect-ratio: 1;
border-radius: 50%;
background-color: #e5e4e5;
}
.DotLoader div {
position: absolute;
height: 1rem;
aspect-ratio: 1;
border-radius: 50%;
background-color: pink;
left: 3rem;
animation: moveSpinner 1s steps(3, end) infinite;
}
#keyframes moveSpinner {
0% {
left: 0;
}
50% {
left: 1.5rem;
}
100% {
left: 3rem;
}
}
<div class="Spinner">
<div class="DotLoader">
<div></div>
<section></section>
<section></section>
<section></section>
</div>
</div>
Can someone help me understand this and fix it?
.DotLoader div {
animation: moveSpinner 1s steps(3) infinite;
}
#keyframes moveSpinner {
0% {
left: 0;
}
100% {
left: 112%;
}
}
From what I understand... If you want to make the pink circle "move and stop" on each gray circles, you can simply delete steps(3, end). There is no need for it it just smoothly slides from one dot to another.
But if the request is making pink one just jump instead of slide, then you do not need another <div> for that, just create animations for your <section> elements individually. Light them up as pink and make them gray again.
So here is my code...
I understand how to make the text disappear by making it transparent but i want it to stay gone after hovering over it so it doesnt come back - how do I accomplish this?
.disappear {
margin-top: 60px;
text-align: center;
transition: all 5s ease .3s;
font-family: Bungee Spice;
}
.disappear:hover {
color: transparent;
}
you need to use onmouseover and remove() like this
function bye() {
const dis = document.getElementById("dis");
dis.remove();
}
* {
padding: 0;
margin: 0;
/* border: 1px solid red; */
overflow-x: hidden;
}
div {
height: 50vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
font-size: xx-large;
overflow: auto;
background: lightblue;
}
<div class="div">
<h2 onmouseover="bye()" id="dis">will go on hover</h2>
</div>
I don't think it's possible to make it run smoothly with pure CSS, so far, this is what I think is close to what you want to accomplish. So before hover, the animation to make it gone is already set, but the animation is not running yet, the animation will run only if the element is hovered. The problem here is that when it's hovered then it's unhovered before it's gone, the element will be half gone as the animation is paused.
.container {
width: 100%;
height: 800px;
background: #dddddd;
}
.disappear {
margin-top: 60px;
text-align: center;
font-family: Bungee Spice;
background: yellow;
animation: example 5s linear forwards;
animation-play-state: paused;
}
.disappear:hover {
animation-play-state: running;
}
#keyframes example {
from {opacity: 1}
to {opacity: 0}
}
<div class="container">
not disappear
<div class="disappear">
DISAPPEAR
</div>
</div>
The better way would be to use javascript and use onmouseover to add the animation instead of using :hover, the difference is that when you onmouseout, the function is still executed (the animation persists). This is with JS:
function fade(elm) {
elm.style.animation = "example 5s linear forwards";
}
.container {
width: 100%;
height: 800px;
background: #dddddd;
}
.disappear {
margin-top: 60px;
text-align: center;
font-family: Bungee Spice;
background: yellow;
}
#keyframes example {
from {
opacity: 1
}
to {
opacity: 0
}
}
<div class="container">
not disappear
<div class="disappear" onmouseover="fade(this)">
DISAPPEAR
</div>
</div>
thanks for reading and offering help.
I assume my CSS code shouldn't be too complicated, however, it does not behave the way I want.
Expected result: when hovering over the button, there is a background area "folding up" (no background color to dark background color).
Actual results:
Works in Chrome (Version 88.0.4324.146), however, there is a flicker to it, like it is rebuilding again and again. This happens especially when hovering coming from the top. Looks alright when doing it from the bottom and rather slow.
I also saw that it seems to not really work in FF (Dev Edition 86.0b9). Sometimes it pops up, but if it does, it only does so once. Refreshing the browser window is not helping either.
I already tried to have a <div> around it and apply the hover animation to it, to fix it with prefixes... so far I couldn't make it work (smoothly), the issue always persisted.
So, this is the code now, which can also be found in this codepen example
html:
<button class="btn">
click
</button>
CSS:
.btn {
height: 48px;
width: 200px;
text-align: center;
text-transform: uppercase;
border: none;
border-bottom: 1px solid steelblue;
position: relative;
color: steelblue;
background: transparent;
::before {
bottom: 0;
content: "";
height: 100%;
left: 0;
opacity: 0;
position: absolute;
right: 0;
z-index: -1;
}
&:hover,
&:focus {
animation: one 0.25s linear;
background-color: steelblue;
color: whitesmoke;
opacity: 1;
transform-origin: 50% 100%;
}
#keyframes one {
0% {
transform: perspective(1000px) rotateX(90deg);
}
100% {
transform: perspective(1000px) rotateX(0);
}
}
}
If this is a duplicate, it means I didn't find the helping answer yet, will be happy for any solutions and hints.
The problem also happens in Chrome. It happens because you are changing the perspective of the button, which will change its "bounding box".
So when you mouse over the bounding box the animation will change the bounding box, and then the mouse is not over the bounding box, so the animation stops, but then the mouse is over the bounding box again, so the animation starts, and so on.
To fix this, create a container around the button, and make the countainer change the button perspective, instead of the button changing the perspective itself. The container will retain its bounding box when yo do this:
.bcg {
display: flex;
justify-content: center;
align-items: center;
background: whitesmoke;
height: 100vh;
}
.btncontainer {
display: inline-block;
}
.btncontainer:hover .btn, .btncontainer:focus .btn {
animation: one 0.25s linear;
background-color: steelblue;
color: whitesmoke;
opacity: 1;
transform-origin: 50% 100%;
}
#keyframes one {
0% {
transform: perspective(1000px) rotateX(90deg);
}
100% {
transform: perspective(1000px) rotateX(0);
}
}
.btn {
height: 48px;
width: 200px;
text-align: center;
text-transform: uppercase;
border: none;
border-bottom: 1px solid steelblue;
position: relative;
color: steelblue;
background: transparent;
}
.btn::before {
bottom: 0;
content: "";
height: 100%;
left: 0;
opacity: 0;
position: absolute;
right: 0;
z-index: -1;
}
<div class="bcg">
<div class="btncontainer">
<button class="btn">
click
</button>
</div>
</div>
I know there's a way to do marching ants with linear-gradients but it eats a huge amount of CPU (about 10% for each one). I am trying to make an alt solution but find border-image-slice confusing.
Here is the outdated tutorial I'm using: http://www.chrisdanford.com/blog/2014/04/28/marching-ants-animated-selection-rectangle-in-css/
I've removed the obsolete css but I'm not sure how to slice the image so that the ants are marching. The tut says:
We’ll start with a 10px x 10px animated gif that is composed of nine
tiles: 1×1 in the corners, 1×8 or 8×1 on the edges, and 8×8 in the
center.
body {
background-color: green;
}
.box {
width: 200px;
height: 200px;
background-color: black;
}
.marching {
border: 1px solid transparent;
border-image-source: url('https://i.imgsafe.org/e5bc19b03a.gif');
border-image-slice: 1;
border-image-repeat: stretch stretch;
}
<div class="box marching"></div>
Thanks
The background should repeat, not stretch. Is this what you're going for?
body {
background-color: green;
}
.box {
width: 200px;
height: 200px;
background-color: black;
}
.marching {
border: 1px solid transparent;
border-image-source: url('https://i.imgsafe.org/e5bc19b03a.gif');
border-image-slice: 1;
border-image-repeat: repeat repeat;
}
<div class="box marching"></div>
Here is CSS version I found, how does it compare with the others when it comes to CPU usage?
body { background: green; }
.box {
position: relative;
width: 90px;
height: 90px;
overflow: hidden;
margin: 10px;
background: black;
}
.box * {
position: absolute;
}
.box div {
width: 100%;
height: 100%;
}
.box div:nth-child(1) { transform: rotate( 0deg ); }
.box div:nth-child(2) { transform: rotate( 90deg ); }
.box div:nth-child(3) { transform: rotate( 180deg ); }
.box div:nth-child(4) { transform: rotate( 270deg ); }
.box i {
left: 0;
top: 0;
width: 200%;
border-bottom: 1px dashed white;
}
.box i {
animation: marching 4s infinite linear;
}
#keyframes marching {
from { transform: translateX( -50% ); }
to { transform: translateX( 0% ); }
}
<div class="box">
<div><i></i></div>
<div><i></i></div>
<div><i></i></div>
<div><i></i></div>
</div>
Src: https://jsfiddle.net/desandro/zm7Et/
Is there any reason why you're not using a canvas?
The Canvas element has a lineDashOffset property that is often used for marching ant effects:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
If you're planning on using a GIF it looks as though scaling isn't something you're worried about, so maybe a canvas might be a better way to do it. Buffer-canvases might also be used to improve performance.
When we use CSS3 transform: operation1(...) operation2(...), which one is done first?
The first operation done seems to be the one the most on the right., i.e. here operation2 is done before operation1. Just to be sure, is it true?
Note: I have read one thing and its contrary in some places (answers, articles on the internet), thus the question here.
Yes, the first operation done is the one the most on the right., i.e. here operation2 is done before operation1.
This MDN article states indeed:
The transform functions are multiplied in order from left to right, meaning that composite transforms are effectively applied in order from right to left.
Here is the documentation : http://www.w3.org/TR/css-transforms-1/.
Example 1
Here the scaling is done first, and then the translation of 100px vertically (if translation was done first, the scaling would make the translation of 500px!)
#container {
position: absolute;
transform: translate(0,100px) scale(5);
transform-origin: 0 0; }
<div id="container"><img src="https://i.stack.imgur.com/xb47Y.jpg"></img></div>
Example 2
Here the translation is done first, and then the scaling (the scaling done after makes that the translation looks like a 500px-translation!)
#container {
position: absolute;
transform: scale(5) translate(0,100px);
transform-origin: 0 0; }
<div id="container"><img src="https://i.stack.imgur.com/xb47Y.jpg"></img></div>
This has been mentioned in other answers and comments, but not with enough emphasis in my opinion: the short answer is both ways are valid.
It all depends whether you consider your coordinates attached to your element (left to right) or fixed to the page based on the initial element position (right to left).
Here is an article showing the difference with animations (which makes it easier to understand): Chaining transforms.
Here is a snippet showing the animations from the article:
html, body { height: 100%; }
body {
background: #aaa;
color: #000;
font-family: Calibri,Candara,Segoe,"Segoe UI",Optima,Arial,sans-serif;
overflow: hidden;
margin: 0;
}
.info {
text-align: center;
font-family: Consolas,monaco,monospace;
font-size: 20px;
font-weight: bold;
margin-bottom: 4px;
color: #fff;
}
.split { white-space: nowrap; }
.side {
display: inline-block;
width: 50%;
}
.label {
text-align: center;
font-size: 20px;
}
.container {
position: relative;
font-size: 50px;
margin: .6em auto 0;
width: 0; height: 0;
transform: translateX(-1em);
}
.ltr .object {
position: absolute;
left: 0; top: 0;
width: 1em; height: 1em;
margin: -.5em 0 0 -.5em;
background: rgb(114,34,34);
animation: ltrObj 5s infinite;
}
#keyframes ltrObj {
from, 10% { transform: rotate( 0deg) translateX(0em); }
40% { transform: rotate(45deg) translateX(0em); }
70%, to { transform: rotate(45deg) translateX(2em); }
}
.object.shadow {
animation: none;
opacity: .2;
}
.ltr .axes {
position: absolute;
left: .5em; top: .5em;
width: 1em; height: 1em;
color: #111;
box-sizing: border-box;
border-left: 2px solid;
border-top: 2px solid;
}
.ltr .axes::before, .ltr .axes::after {
content: '';
position: absolute;
width: .2em; height: .2em;
box-sizing: border-box;
border-left: 2px solid;
border-top: 2px solid;
transform-origin: top left;
}
.ltr .axes::before { top: 100%; left: 0; margin-left: -1px; margin-top: 1px; transform: rotate(225deg); }
.ltr .axes::after { top: 0; left: 100%; margin-top: -1px; margin-left: 1px; transform: rotate(135deg); }
.rtl .axes {
position: absolute;
left: 0; top: 0;
width: 2.5em; height: 2.3em;
color: #111;
box-sizing: border-box;
border-left: 2px solid;
border-top: 2px solid;
}
.rtl .axes::before, .rtl .axes::after {
content: '';
position: absolute;
width: .2em; height: .2em;
box-sizing: border-box;
border-left: 2px solid;
border-top: 2px solid;
transform-origin: top left;
}
.rtl .axes::before { top: 100%; left: 0; margin-left: -1px; margin-top: 1px; transform: rotate(225deg); }
.rtl .axes::after { top: 0; left: 100%; margin-top: -1px; margin-left: 1px; transform: rotate(135deg); }
.rtl .object {
position: absolute;
left: 0; top: 0;
width: 1em; height: 1em;
margin: -.5em 0 0 -.5em;
background: rgba(100,0,0,0.8);
animation: rtlObj 5s infinite;
}
#keyframes rtlObj {
from, 10% { transform: rotate( 0deg) translateX(0em); }
40% { transform: rotate( 0deg) translateX(2em); }
70%, to { transform: rotate(45deg) translateX(2em); }
}
.helper-mask {
position: absolute;
left: 0; top: 0;
width: 3em; height: 3em;
overflow: hidden;
}
.helper {
position: absolute;
left: 0; top: -2em;
width: 0; height: 2em;
margin-top: 2px;
box-sizing: border-box;
border: 2px solid #00c;
border-left: none;
border-radius: 0 100% 0 0;
transform-origin: bottom left;
animation: helper 5s infinite;
}
#keyframes helper {
from, 10% { width: 0em; transform: rotate( 0deg); }
40% { width: 2em; transform: rotate( 0deg);}
70%, to { width: 2em; transform: rotate(45deg);}
}
<div class="info">rotate(45deg) translateX(2em)</div>
<div class="split">
<div class="side ltr">
<div class="label">Left to Right</div>
<div class="container">
<div class="object shadow"></div>
<div class="object">
<div class="axes"></div>
</div>
</div>
</div>
<div class="side rtl">
<div class="label">Right to Left</div>
<div class="container">
<div class="axes"></div>
<div class="object"></div>
<div class="helper-mask">
<div class="helper"></div>
</div>
</div>
</div>
</div>
Whether the actual implementation uses left to right or right to left is irrelevant, both are equally valid when creating an animation, as long as you keep the difference in mind.
Transforms are performed left to right. Transforms correspond to matrix operations, and these are performed left to right.
There is intuition behind it, it's not just that this is literally in the spec as a normative rule (point 3 here: https://drafts.csswg.org/css-transforms-1/#transform-rendering)
Here's a pen to try: https://codepen.io/monfera/pen/YLWGrM
Explanation:
Each transform step establishes its own coordinate system. So
transform: translateX(500px);
establishes a new coordinate system 500px along the X axis of its parent, and the element will be rendered there.
Similarly,
background-color: blue;
transform: translateX(500px) rotate(60deg);
first establishes a new coordinate system 500px along the X axis (to the right) of its parent, and only then, within that (translated, but it's now irrelevant) coordinate system does it perform the rotation. So it'll be a shape that's 500px to the right, and rotated in place (around the so-called transform-origin which is interpreted in the local coordinate system, and the default 50% 50% for rotation means, rotation around the center of the rectangle, but it's an aside).
The reverse order
background-color: orange;
transform: rotate(60deg) translateX(500px);
first establishes a new coordinate system that's rotated 60 degrees relative to the parent, and then translates 100px along the X axis of the now rotated coordinate system, in a direction that is not actually to the right from the global viewpoint of the document (or user). So, in this case, it's as if you first rotated the paper, and then slid the shape 500 units along the side of the paper (from the origin, which is in this case the top left corner).
For a more advanced discussion, and understanding of how it's possible to intuitively understand it for both directions, check out Composing Transformations - CSS transforms follow the post-multiplication model, so look for the page with the heading "Think of transformations as transforming the local coordinate frame" (illustrations seem to be a little off though)
It applies the leftmost transformation first.
As you can see in the image above, the first transformation takes a longer distance as compared to the second. The reason is the first example undergoes scale first and then it takes the distance specified by translate based on its new width on the x-axis. Because it is wider now, 50% will cause it to take a longer distance. The measure specified by 50% is calculated by taking half of the width of itself.
the site I cited from
I just created a demo of a 3d room in HTML using CSS transforms. I made a 200x200 DIV for a back wall, leaving it in that position. Then I made a left wall starting in the same size and position, then added
transform: translate3d(-100px,0px,100px) rotateY(90deg).
Then I made a right wall and added
transform: translate3d( 100px,0px,100px) rotateY(90deg).
This created the room correctly. But this is with version 13 of Safari. Originally I tried to list the rotation step first, but the wall was in an odd position. So I'm seeing a right-to-left behavior.