I have a simple game that I am developing (just a simple pairs matching game), which has tiles that swivel around in 3d to reveal pictures on the other side of them. It all works fine, apart from now I've come to do some additional animation work I'm having a problem with the background images on the tiles disappearing. I've reduced the code down to a much simpler test case. There's still quite a lot in there, but it's mostly down to having the 3d rotation on the tile. The weird thing I can't work out is that it works fine without using opacity in the keyframe animation. As soon as I try to add opacity in there my div with the background image instantly disappears, even with opacity values of 1. I'm stumped as to why that is ... any help would be appreciated. I've tried on firefox and Edge (edge is my target browser) and they are both behaving the same. The code below is with the opacity values left in, so it's in it's broken state. Removing those will show it working as I intend without the fade at the end - the tile shows and rotates in 3d exactly as I expect with the background image showing.
#keyframes tileComplete {
0% {
transform: rotate3d(0, 1, 0, 0deg);
}
50% {
transform: rotate3d(0, 1, 0, 180deg) scale(1);
opacity: 1;
}
100% {
transform: rotate3d(1, 1, 0, 540deg) scale(3);
opacity: 0;
}
}
div.tiles {
transform-style: preserve-3d;
transform-origin: center;
perspective: 800px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
div.tiles div.tile {
transform-style: preserve-3d;
transform-origin: center;
width: 150px;
height: 150px;
margin: 5px;
background-color: #000066;
transition-property: opacity;
transition-duration: 1s;
opacity: 1;
transform: rotate3d(0, 1, 0, 0deg);
position: relative;
cursor: pointer;
}
div.tiles div.tile div.tile-image {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-image: url("images/test.jpg");
background-position: center;
background-size: cover;
transform: rotate3d(0, 1, 0, 180deg);
z-index: 5;
-webkit-backface-visibility: hidden;
}
div.tiles div.complete {
animation-delay: 1s;
animation-name: tileComplete;
animation-duration: 2s;
animation-delay: 0s;
pointer-events: none;
}
<!doctype html>
<div>
<div class="tiles">
<div id="tile_0" class="tile complete">
<div class="tile-image" style="background-image: url(images/memory_game/1.jpg);"></div>
</div>
</div>
</div>
After taking a good look at your project, I think I understood what you meant. You want the square to turn around and show the image correct? Since you are changing the opacity on the parent, it will also hide the child. In this case, the child is the image. I have added a background-color: red to the image container for visual purposes. I have changed the opacity of the parent within the background-color this changes the opacity of the parent, but doesn't change it for the child as well.
#keyframes tileComplete {
0% {
transform: rotate3d(0, 1, 0, 0deg);
}
50% {
transform: rotate3d(0, 1, 0, 180deg) scale(1);
opacity: 1;
}
100% {
transform: rotate3d(1, 1, 0, 540deg) scale(3);
visibility: hidden;
opacity: 0;
}
}
#keyframes tileCompleteImg {
50% {
-webkit-backface-visibility: visible;
}
100% {
-webkit-backface-visibility: visible;
}
}
div.tiles {
transform-style: preserve-3d;
transform-origin: center;
perspective: 800px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
div.tiles div.tile {
transform-style: preserve-3d;
transform-origin: center;
width: 150px;
height: 150px;
margin: 5px;
background-color: #000066;
transition-property: background-color;
transition-duration: 1s;
opacity: 1;
transform: rotate3d(0, 1, 0, 0deg);
position: relative;
cursor: pointer;
}
div.tiles div.tile div.tile-image {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-image: url("https://refuzion.nl/uploads/stock.jpeg");
background-position: center;
background-size: cover;
transform: rotate3d(0, 1, 0, 180deg);
z-index: 99;
-webkit-backface-visibility: hidden;
}
div.tiles div.complete {
animation-delay: 1s;
animation-name: tileComplete;
animation-duration: 2s;
animation-delay: 0s;
pointer-events: none;
}
div.tiles div.img-complete {
animation-delay: 1s;
animation-name: tileCompleteImg;
animation-duration: 2s;
animation-delay: 0s;
pointer-events: none;
}
<!doctype html>
<div>
<div class="tiles">
<div id="tile_0" class="tile complete">
<div class="tile-image img-complete"></div>
</div
</div>
</div>
I'm not sure if this is what you want. I change the opacity for div.tile
#keyframes tileComplete {
0% {
transform: rotate3d(0, 1, 0, 0deg);
}
50% {
transform: rotate3d(0, 1, 0, 180deg) scale(1);
opacity: 1;
}
100% {
transform: rotate3d(1, 1, 0, 540deg) scale(3);
opacity: 0;
}
}
div.tiles {
transform-style: preserve-3d;
transform-origin: center;
perspective: 800px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
div.tiles div.tile {
transform-style: preserve-3d;
transform-origin: center;
width: 150px;
height: 150px;
margin: 5px;
background-color: #000066;
transition-property: opacity;
transition-duration: 1s;
opacity: 0;
transform: rotate3d(0, 1, 0, 0deg);
position: relative;
cursor: pointer;
}
div.tiles div.tile div.tile-image {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-image: url("images/test.jpg");
background-position: center;
background-size: cover;
transform: rotate3d(0, 1, 0, 180deg);
z-index: 5;
-webkit-backface-visibility: hidden;
}
div.tiles div.complete {
animation-delay: 1s;
animation-name: tileComplete;
animation-duration: 2s;
animation-delay: 0s;
pointer-events: none;
}
<div class="tiles">
<div id="tile_0" class="tile complete">
<div class="tile-image" style="background-image: url(images/memory_game/1.jpg);"></div>
</div>
</div>
Related
Using CSS animation, I am adding a 'wobble' effect to each letter in a word. Each letter is made up of an SVG group <g>. However, as you can see in the example, the effect gets more extreme with each letter, whereas I want a consistent 'wobble' per letter (the same effect on each letter). How can this be acheived?
Note: I have not included the SVG source code, to keep the question tidy. It can be seen in the example if needed.
Thanks.
SCSS
// Logo
.logo {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
z-index: 1;
width: 260px;
display: block;
// SVG
svg {
display: block;
width: 100%;
overflow: visible;
g {
fill: transparent;
transition: all 300ms ease-in-out;
#keyframes wobble {
0% { transform: rotate(0) translate3d(0, 0, 0) }
25% { transform: rotate(2deg) translate3d(1px, 0, 0) }
50% { transform: rotate(-1deg) translate3d(0, -1px, 0) }
75% { transform: rotate(1deg) translate3d(-1px, 0, 0) }
100% { transform: rotate(-2deg) translate3d(-1px, -1px, 0) }
}
animation-duration: 400ms;
animation-iteration-count: infinite;
animation-fill-mode: none;
animation-name: wobble;
animation-timing-function: ease-in-out;
path {
fill: red;
}
}
}
}
Example
I could not figure out how to do it with SVGs - I did manage to come up with something similar to your requirement.
Part of the solution involved using a center point for the rotation:
transform-origin: center;
See demo below
#my-logo div {
display: inline-block;
color: red;
font-size: 60px;
font-family: arial;
font-weight: bolder;
text-transform: uppercase;
fill: transparent;
transition: all 300ms ease-in-out;
transform-origin: center;
animation-duration: 400ms;
animation-iteration-count: infinite;
animation-fill-mode: none;
animation-name: wobble;
animation-timing-function: ease-in-out;
}
#keyframes wobble {
0% {
transform: rotate(0) translate3d(0, 0, 0);
}
25% {
transform: rotate(2deg) translate3d(1px, 0, 0);
}
50% {
transform: rotate(-1deg) translate3d(0, -1px, 0);
}
75% {
transform: rotate(1deg) translate3d(-1px, 0, 0);
}
100% {
transform: rotate(-2deg) translate3d(-1px, -1px, 0);
}
}
<div id="my-logo">
<div>o</div>
<div>u</div>
<div>t</div>
<div>r</div>
<div>a</div>
<div>g</div>
<div>e</div>
<div>
<!-- also works with images -->
<img src="http://placekitten.com/100/100" />
</div>
</div>
I have borrowed a Venn animation from elsewhere and would like to place icons (ionicons via CSS class) within the Venn so that they animate in accordance with it.
I've tried numerous approaches, but the closest I've come so far to succeeding is to basically run two sets of animations, using the same parameters, one after the other in the code.
Whilst the animation is now the same for the symbols as well as the CSS circles, they do not occupy the same space and so do not overlay as I want. How can I achieve this, within the existing code set up? I've tried padding, margin etc but that skews the circular graphic.
Thank you.
The animation won't run in the Stack Overflow editor so please view on Codepen:
Link to animation on Codepen.
* {
box-sizing: border-box;
}
body {
background-image: radial-gradient(#fff 25%, #bbb 75%);
height: 100vh;
width: 100vw;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.box {
height: 50vh;
width: 50vh;
}
[class^='c'] {
background-color: #0ff;
border-radius: 50%;
height: 50vh;
width: 50vh;
mix-blend-mode: multiply;
position: absolute;
}
.circle1 { /*blue*/
background-color: rgba(0,255,255,0.5);
animation: c1 2.5s ease 4 forwards;
}
/*.ion-code{
animation: code-symbol 2.5s ease 4 forwards;
transform: translate(15%, -12%);
}*/
.circle2 { /*yellow*/
background-color: rgba(255,255,0,0.5);
animation: c2 2.5s ease 4 forwards ;
}
.circle3 {/*pink*/
background-color: rgba(255,0,255,0.5);
animation: c3 2.5s ease 4 forwards ;
}
/*---------------------------------------C1-BLUE-*/
#keyframes c1 {
0% {transform: translate(0, 0); }
100% {transform: translate(-25%, 25%); }
}
/*#keyframes code-symbol {
0% {transform: translate(0, 0); }
100% {transform: translate(-25%, 25%); }
}*/
/*---------------------------------------C2-YELLOW-*/
#keyframes c2 {
from {
transform: translate(0, 0);
}
to {
transform: translate(0, -25%);
}
}
/*---------------------------------------C3-PINK-*/
#keyframes c3 {
from {
transform: translate(0, 0);
}
to {
transform: translate(25%, 25%);
}
}
/*--------Symbol layer -----------*/
[class^='ion-'] {
border-radius: 50%;
height: 150vh;
width: 150vh;
mix-blend-mode: multiply;
position: absolute;
}
.ion-code { /*blue*/
/*background-color: rgba(0,255,255,0.5);*/
animation: ion-code 2.5s ease 4 forwards;
font-size: 4rem;
}
.ion-arrow-graph-up-right { /*yellow*/
/* background-color: rgba(255,255,0,0.5); */
animation: ion-arrow-graph-up-right 2.5s ease 4 forwards;
font-size: 4rem;
}
.ion-ios-settings-strong {/*pink*/
/* background-color: rgba(255,0,255,0.5); */
animation: ion-ios-settings-strong 2.5s ease 4 forwards;
font-size: 4rem;
}
/*---------------------------------------C1-BLUE-*/
#keyframes ion-code {
from {transform: translate(0, 0); }
to {transform: translate(-25%, 25%); }
}
/*---------------------------------------C2-YELLOW-*/
#keyframes ion-arrow-graph-up-right {
from {transform: translate(0, 0);}
to {transform: translate(0, -25%);}
}
/*---------------------------------------C3-PINK-*/
#keyframes ion-ios-settings-strong {
from {transform: translate(0, 0);}
to {transform: translate(25%, 25%);}
}
<body>
<div class="box">
<div class="circle1 ion-code" ></div>
<div class="circle2 ion-arrow-graph-up-right"></div>
<div class="circle3 ion-ios-settings-strong"></div>
</div>
</body>
You just need to target the :before pseudo element where the icons live in this example
SEE CODEPEN
.circle1:before, .circle2:before, .circle3:before {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
}
Cheers.
Personally, I like to use flexbox for this kind of centering:
[class*='ion-']:before {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
https://codepen.io/anon/pen/xydGzK
I have the following HTML and CSS code to draw the top of a cube. So it moves down and I want it to animate as if it is opening up. I am unable to figure out how to transform the top so that it appears to open up.
I have included the entire code for the cube. With respect to this, I want the top to open up.
.pers500 {
perspective: 500px;
-webkit-perspective: 500px;
-moz-perspective: 500px;
}
/* Define the container div, the cube div, and a generic face */
.container {
width: 25%;
margin: 0 auto;
margin-top: 2em;
border: none;
animation-name: moveDown;
animation-duration: 2s;
animation-timing-function: linear;
transform: translate(0px, 110px);
}
.cube {
width: 70%;
height: 70%;
backface-visibility: visible;
perspective-origin: 150% 150%;
transform-style: preserve-3d;
-webkit-backface-visibility: visible;
-webkit-perspective-origin: 150% 150%;
-webkit-transform-style: preserve-3d;
}
.face {
display: block;
position: absolute;
border: none;
line-height: 100px;
font-family: sans-serif;
font-size: 60px;
color: white;
text-align: center;
}
/* Define each face based on direction */
.front {
width: 3.64em;
height: 3.43em;
background-color: rgba(0, 255, 0, 0.7);
transform: translateZ(50px) translateX(171px) translateY(222px);
-webkit-transform: translateZ(50px) translateX(171px) translateY(222px);
-moz-transform: translateZ(50px) translateX(171px) translateY(222px);
}
.left {
width: 2em;
height: 3.4em;
background-color: rgba(0, 0, 255, 0.7);
margin: 70px;
transform: skewY(40deg) translateZ(50px);
-webkit-transform: skewY(40deg) translateZ(50px) translateY(65px) translateX(-20px);
-moz-transform: skewY(40deg) translateZ(50px) translateY(62px) translateX(-20px);
}
.top {
width: 3.65em;
height: 1.7em;
background-color: rgba(255, 0, 0, 0.7);
margin: 100px;
transform: skewX(50deg) translateZ(50px) translateX(-14px) translateY(20px);
-webkit-transform: skewX(50deg) translateZ(50px) translateX(-14px) translateY(20px);
;
-moz-transform: skewX(50deg) translateZ(50px) translateX(-14px) translateY(20px);
;
animation-name: openTop;
animation-duration: 2s;
animation-timing-function: linear;
}
#-webkit-keyframes moveDown {
0% {
transform: translate(0px, 10px);
}
50% {
transform: translate(0px, 55px);
}
100% {
transform: translate(0px, 110px);
}
}
#keyframes moveDown {
0% {
transform: translate(0px, 10px);
}
50% {
transform: translate(0px, 55px);
}
100% {
transform: translate(0px, 110px);
}
}
#keyframes openTop {
/*0% {transform:rotateX(30deg);}
50% {transform:rotateX(30deg);}
100% {transform:rotateX(30deg);} commented code here doesn't work*/
}
<div class="container">
<div class="cube pers500">
<div class="face front"></div>
<div class="face top"></div>
<br>
<br>
<br>
<div class="face left"></div>
</div>
</div>
To make the cube open up, you first need to set the transform-origin property (as mentioned in the other answer) to top. This setting would make the top side of the .face.top remain fixed when the rotation is being performed. Then you need to add the rotation using rotateX(). This would rotate the top face to produce the opening effect. Note that the transform property should contain the entire list of transforms for it to open correctly. You cannot just add the rotateX() alone within the animation.
.pers500 {
perspective: 500px;
}
/* Define the container div, the cube div, and a generic face */
.container {
width: 25%;
margin: 0 auto;
margin-top: 2em;
border: none;
animation-name: moveDown;
animation-duration: 2s;
animation-timing-function: linear;
transform: translate(0px, 110px);
}
.cube {
width: 70%;
height: 70%;
backface-visibility: visible;
perspective-origin: 150% 150%;
transform-style: preserve-3d;
}
.face {
display: block;
position: absolute;
border: none;
line-height: 100px;
font-family: sans-serif;
font-size: 60px;
color: white;
text-align: center;
border: 1px solid brown; /* just for testing */
}
/* Define each face based on direction */
.front {
width: 3.64em;
height: 3.43em;
background-color: rgba(0, 255, 0, 0.7);
transform: translateZ(50px) translateX(171px) translateY(222px);
}
.left {
width: 2em;
height: 3.43em;
background-color: rgba(0, 0, 255, 0.7);
margin: 70px;
transform: skewY(40deg) translateZ(50px) translateY(64px) translateX(-20px);
}
.top {
width: 3.65em;
height: 1.69em;
background-color: rgba(255, 0, 0, 0.7);
margin: 100px;
transform: skewX(50deg) translateZ(50px) translateX(-74px) translateY(20px) rotateX(0deg);
transform-origin: top;
animation-name: openTop;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
}
#-webkit-keyframes moveDown {
0% {
transform: translate(0px, 10px);
}
50% {
transform: translate(0px, 55px);
}
100% {
transform: translate(0px, 110px);
}
}
#keyframes moveDown {
0% {
transform: translate(0px, 10px);
}
50% {
transform: translate(0px, 55px);
}
100% {
transform: translate(0px, 110px);
}
}
#keyframes openTop {
0% {
transform: skewX(50deg) translateZ(50px) translateX(-74px) translateY(20px) rotateX(0deg);
}
100% {
transform: skewX(50deg) translateZ(50px) translateX(-74px) translateY(20px) rotateX(200deg);
}
}
<div class="container">
<div class="cube pers500">
<div class="face front"></div>
<div class="face top"></div>
<br>
<br>
<br>
<div class="face left"></div>
</div>
</div>
Note:
Setting a transform-origin will affect the position of the top face in the demo and so the values that you've used for translateX() and translateY() on the top face need to be modified a bit like in the above demo.
The vendor prefixed versions of properties should always be added before the standard property in order to be future proof.
I have removed the vendor prefixed versions in the above snippet just to keep it simple.
Set the transform origin to tbe edge of the cube with
transform-origin: 0 50% 0;
Then rotate it around the z axis:
transform: rotateZ(90deg);
I hope this works for you, I didn't have the chance to test it.
I've got a problem with "nested" backface-visibility.
I would like to have a flipping div, with content on both sides. For that, I use two div flipping, each one representing a face of my "two-faces" div (.face and .back).
The rotation works well.
Now, I want to hide their container, and reveal it when the page is loaded with another flip. But as you can see, my .face div is visible.
How could I avoid .face to be visible before my animation?
Here's the shorten working example I could made (Chrome favor):
.flip {
position: relative;
backface-visibility: hidden;
transform: rotateX(180deg);
animation: init 1s ease 2s 1 normal forwards;
}
.flip div {
backface-visibility: hidden;
transition: 1s;
margin: 0;
padding: 20px;
border: 1px solid;
width: 200px;
text-align: center;
}
.back {
position: absolute;
top: 0;
left: 0;
}
.face,
.flip:hover .back {
transform: rotateX(0deg);
}
.flip:hover .face,
.back {
transform: rotateX(180deg);
}
#keyframes init {
from { transform: rotateX(180deg); }
to { transform: rotateX(0deg); }
}
<div class="flip">
<div class="face">FACE</div>
<div class="back">BACK</div>
</div>
If you want it to work in a nested way, you need the property
transform-style: preserve-3d;
in he parent:
.flip {
position: relative;
backface-visibility: hidden;
transform: rotateX(180deg);
transform-style: preserve-3d;
animation: init 1s ease 2s 1 normal forwards;
}
.flip div {
backface-visibility: hidden;
transition: 1s;
margin: 0;
padding: 20px;
border: 1px solid;
width: 200px;
text-align: center;
}
.back {
position: absolute;
top: 0;
left: 0;
}
.face,
.flip:hover .back {
transform: rotateX(0deg);
}
.flip:hover .face,
.back {
transform: rotateX(180deg);
}
#keyframes init {
from { transform: rotateX(180deg); }
to { transform: rotateX(0deg); }
}
<div class="flip">
<div class="face">FACE</div>
<div class="back">BACK</div>
</div>
I have a few divs in a container:
<div class="waves-container" id="waves_container">
<div class="wave-wrapper wave-back">
<img src="static/images/waves/sea_back.png" class="wave-top" />
<div class="wave-bottom"></div>
</div>
<div class="wave-wrapper wave-front">
<img src="static/images/waves/sea-front.png" class="wave-top" />
<div class="wave-bottom" id="wave_bottom_front">Some additional divs are created here dynamically with JS</div>
</div>
<div class="play-button" id="play_button">
<img src="static/images/ccs_shake_waves/play.png" />
</div>
</div>
Their CSS:
.waves-container {
width: 100%;
height: 50%;
position: absolute;
bottom: -35%;
-webkit-transition: bottom 0.4s ease-in-out;
}
.wave-wrapper {
width: 105%;
height: 130%;
position: absolute;
left: -5%;
}
.wave-top {
width:100%;
height: auto;
position:relative;
bottom: 0;
left: 0;
float: left;
}
.wave-bottom {
width: 100%;
height: 130%;
position: relative;
clear:both;
float: left;
background-color: #fd51df;
}
.wave-back {
-webkit-animation: wave 3s 1s infinite linear;
top: 1.5%;
}
.wave-front {
top: -12%;
-webkit-animation: wave 3s infinite linear;
}
.play-button {
width: 70%;
height: auto;
position: relative;
margin: 0 auto;
top: 50%;
-webkit-transform: translateY(-50%) scale(0, 0);
z-index:1;
display: none;
}
With JS on a certain event I'm attaching an animation class to #play_button:
.pop-play {
-webkit-animation: flipInY 1s 1 forwards ease-out, play 3s 1s infinite linear;
}
In flipInY I'm animating this div on Y axis:
#-webkit-keyframes flipInY {
0% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg) translateY(-50%);
-webkit-transition-timing-function: ease-in;
opacity: 0;
}
40% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg) translateY(-50%);
-webkit-transition-timing-function: ease-in;
}
60% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg) translateY(-50%);
opacity: 1;
}
80% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg) scale(1.05, 1) translateY(-50%);
}
100% {
-webkit-transform: perspective(400px) scale(1.1, 1) translateY(-50%);
-webkit-transition-timing-function: ease-out;
}
}
In Android I see it just fine. However in iOS the play_button div overlaps with underlying div when it flips on Y axis, so every time I see 50% of the image, the rest of that div is "under" another div.
I tried to add -webkit-transform: translate3d(0,0,0); to every underlying div, tried to change z-indexes, tried to combine it, tried to use
-webkit-perspective: 1000;
-webkit-transform-style: preserve-3d;
on the waves-container div and all the child divs, but they're still overlapping, until the flipping animation finishes and the other begins.
Why is it happening and how can I fix it?