Adding a card flip animation to this JS card game? - javascript

I am playing around with this card game and I want to add a card flip animation.
I have googled for an answer, but most solutions refer to jquery (which I don't want to implement just for 1 animation) or CSS3 (I liked this example). Not much luck there.
The js game uses the following (from cardgamecore.js):
playingCard.redrawCardImage() Forces a card to redraw
playingCard.showFace(bool: face) Sets the card to be either face up or face down, and redraws if needed. true = face up, false = face down.
playingCard.prototype.redrawCardImage = function () {
// Set or change the image showing on the card face
if( !this.faceImage || !this.cardSet.backImage ) { return; }
// Bug in Firefox - alt attributes do not change unless they are made _before_ an SRC change
this.cardImage.setAttribute('alt',this.wayup?(this.cardSet.cardNames[this.number-1]+' '+this.suit):this.cardSet.cardWord);
this.cardImage.src = this.wayup ? this.faceImage : this.cardSet.backImage;
};
playingCard.prototype.showFace = function (oWhich) {
// Used to flip a card over
if( this.redrawNewImage != oWhich ) {
this.wayup = oWhich;
this.redrawCardImage();
}
};
So when a card shows its back then playingCard.showFace = false. When you click on it, playingCard.showFace = trueand the image is redrawn. At this point the card should have a nice flip animation.
But how to do this?

What you want to google search is "css 3 flip animation"
http://davidwalsh.name/demo/css-flip.php

I was doing a card game as well...
First you could write you card like this:
<div class='card' >
<div class='faces'>
<div class='face front'> Hello</div>
<div class='face back'>Goodbye</div>
</div>
</div>
Both faces are accounted for in your html the css will only display one though:
.card {
-webkit-perspective: 800;
width: 50%;
height: 300px;
position: relative;
margin: 3px;
float:left; /*if you want more than one card in a line*/
}
.card .faces.flipped {
-webkit-transform: rotatey(-180deg); /* this style will help the card to rotate */
}
.card .faces {
width: 100%;
height: 100%;
-webkit-transform-style: preserve-3d; /* This is a 3d transformation */
-webkit-transition: 0.5s;/*the animation last 0.5secs*/
}
.card .faces .face {
width: 100%;
height: 100%;
position: absolute;
-webkit-backface-visibility: hidden ; /*hides the back of the card until transform*/
z-index: 2;
font-family: Georgia;
font-size: 3em;
text-align: center;
line-height: 200px;
}
.card .faces .front {
position: absolute;
z-index: 1;
background: black;
color: white;
cursor: pointer;
}
.card .faces .back {
-webkit-transform: rotatey(-180deg); /*allows the flip to the back of the card*/
background-image: url("image.jpg"); /*background image for the back if you want*/
background-size:100%;
color:white;
border:1px solid black;
}
The only thing left to do is add the 'flipped' class. So maybe instead of redrawing.
$(".card").on('click',function(){
$(this).children('.faces').toggleClass('flipped');
});
Here's a FIDDLE

Contacted the author of the script and he told me it is not possible in the current script without re-writing most of the code. So this question can be closed. All thanks for trying to help me.

Related

Text appear/disappear on top of image with button toggle

In mobile, I'm trying to create a toggle that appears on top of an image, that when tapped on, makes text appear on top of the image too.
I basically want to recreate how The Guardian newspaper handles the little (i) icon in the bottom right corner on mobile.
And on desktop, the the text is there by default under the image and the (i) icon is gone.
So far I've managed to find a similar solution elsewhere online but it's not quite working right as I need it to.
function toggleText() {
var text = document.getElementById("demo");
if (text.style.display === "none") {
text.style.display = "block";
} else {
text.style.display = "none";
}
}
#blog {
width: 100%;
}
#blog figure {
position: relative;
}
#blog figure figcaption {
display: none;
position: absolute;
bottom: 0;
left: 0;
box-sizing: border-box;
width: 100%;
color: black;
text-align: left;
background: rgba(0, 0, 0, 0.5);
}
#blog figure button {
position: absolute;
bottom: 0;
right: 0;
color: black;
border: 5px solid black;
}
<div id="blog">
<figure>
<img src="https://cdn2.hubspot.net/hubfs/4635813/marble-around-the-world.jpg" alt="A photo of a slab of marble for example">
<figcaption id="demo" style='display: none'>A photo of a slab of marble for example</figcaption>
<button type='button' onclick="toggleText()">(i)</button>
</figure>
</div>
Don't use IDs. Your code should be reusable!
Don't use inline JS on* handlers, use Element.addEventListener() instead
Don't use inline style attributes.
Don't use el.style.display === "something" to check for display styles. Use Element.classList.toggle() instead
This straightforward example uses JavaScript to simply toggle a className "is-active" on the button's parent, the figure Element.
Everything else (icon symbol change, caption animation etc...) is handled purely by CSS:
document.querySelectorAll("figure button").forEach(EL_btn => {
EL_btn.addEventListener("click", () => {
EL_btn.closest("figure").classList.toggle("is-active");
});
});
/* QuickReset */ * {margin: 0; box-sizing: border-box;}
img {
max-width: 100%; /* Never extend images more than available */
}
figure {
position: relative;
overflow: hidden; /* overflow hidden to allow figcaption hide bottom */
}
figure img {
display: block; /* prevent "bottom space" caused by inline elements */
}
figure figcaption {
position: absolute;
width: 100%;
bottom: 0;
padding: 1rem;
padding-right: 4rem; /* Prevent text going under the button icon */
color: #fff;
background: rgba(0, 0, 0, 0.5);
transform: translateY(100%); /* Move down, out of view */
transition: transform 0.3s; /* Add some transition animation */
}
figure.is-active figcaption {
transform: translateY(0%); /* Move into view */
}
figure button {
position: absolute;
width: 2rem;
height: 2rem;
bottom: 0.5rem;
right: 0.5rem;
border-radius: 50%;
color: #fff;
background: rgba(0, 0, 0, 0.5);
border: 0;
cursor: pointer;
}
figure button::before {
content: "\2139"; /* i icon */
}
figure.is-active button::before {
content: "\2A09"; /* x icon */
}
<figure>
<img src="https://cdn2.hubspot.net/hubfs/4635813/marble-around-the-world.jpg" alt="A photo of a slab of marble for example">
<figcaption>A photo of a slab of marble for example</figcaption>
<button type="button"></button>
</figure>
The above will work for any number of such elements on your website without the need to add any more CSS or JS.
I see a couple things that could mess this up, one is the fact that there is nothing to make your image adjust to your mobile screen, more-over there is also margin that is there by default, so I suggest these changes to the CSS:
First I'd set box-sizing to border-box and margin to 0, this should be a regular practice by the way.
*{
box-sizing: border-box;
margin: 0;
}
Then select the image and make it adjust to your page as such
#blog figure img{
height: auto;
width:100%;
}
Finally, for some styling you can add some padding to your blog div to make the image slightly smaller on your screen
#blog {
width: 100%;
padding: 35px;
}
This is the Fiddle for it.

Getting jank on CSS transform

With the following CSS, I am preparing my segment message to slide across the viewport:
.Segment {
position: absolute;
width: 100%;
overflow: hidden;
top: -5px;
top: 0;
outline: 1px solid orange;
}
.Segment__message {
display: inline-block;
margin-top: 15px;
left: 100%;
transform: translateX(0);
position: relative;
padding-left: 10px;
will-change: transform;
font-size: 30px;
}
If I apply the following styles dynamically, I am getting some very slight jank:
var message = document.querySelector(".Segment__message");
message.style = "transition: all 20s linear; transform: translateX(calc(-100vw - 100%))"
It is pretty subtle, but is much more noticeable on the 75" screen this will be displayed on.
Using Chrome's perf tools, I can see some FPS degradation, with it dropping to 8 FPS at one point. Is there anything I can do to smooth this out further?
https://codepen.io/anon/pen/OrOvdP
I removed the position property from the .Segment__message, and positioned it using only transform.
I've also used translate3d, which forces hardware acceleration and has improved animation performance for me in the past.
I don't see jank in Firefox, Chrome, or Safari with the code below.
var link = document.querySelector(".slide");
var message = document.querySelector(".Segment__message");
var styleStr = `transition: all 10s linear; transform: translate3d(-100%, 0, 0)`;
link.onclick = () => {
message.style = styleStr;
}
.Segment {
position: absolute;
width: 100%;
overflow: hidden;
top: 0;
outline: 1px solid orange;
}
.Segment__message {
display: inline-block;
margin-top: 15px;
transform: translate3d(100vw, 0, 0);
padding-left: 10px;
will-change: transform;
font-size: 30px;
}
.Segment__message::after {
content: "/";
color: blue;
display: block;
float: right;
padding-left: 15px;
}
.slide {
display: block;
margin-top: 50px;
}
<div class="Segment">
<div class="Segment__message">I am a message</div>
</div>
<a class="slide" href="#">Slide left</a>
You could do some enhancements to make sure your message will be drawn on a new, separate layer, like:
.Segment {
// ...
perspective: 600px;
z-index:2;
}
.Segment__message {
// ...
z-index:3;
will-change: transform;
transform-style: preserve-3d;
font-size: 30px;
}
But there is one little nasty trick that you can do along with will-change property, if you will apply some really small delay (like 0.1s) your animation will be prerendered before it fires, thus should be smoother:
message.style = "transition: all 10s linear .1s; transform: translateX(calc(-100vw - 100%))"
On first view, it could be the calc() section with vw and %. This mix caused sometimes trouble in my projects, for you get non-integers, which will be rounded automatically by the browser. So I changed the 100% to 100vw in your codepen. The result was a much smoother animation - at least in Chrome.
In addition to using translate3d instead of translateX as pointed out by #sol, I was able to improve the performance by using position: absolute and a fixed width for .Segment__message (plus a fixed height for the .Segment).
On my machine the performance degradation is very minor (even with 6x CPU slowdown) so it was difficult to test accurately, however my guess is that since an item is positioned using position: relative; (or position: static as per #sol's example) then it might cause some style recalculations as the item's (and the adjacent DOM element - in this cause a pseudo element) position shifts within it's parent container.
https://codepen.io/anon/pen/XoZRwr

Add line to end of h tag with CSS or jQuery [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I need to add a line to end of a h tag with CSS like this image:
Here is the html code:
<div class="titleContainer">
<h1 class="titleLeft">how We turn your</h1>
<div class="horizontalLineRight orangeLine" style="width: 213px;"></div>
</div>
I set the width of horizontalLineRight with jQuery:
jQuery( document ).ready(function($) {
$( window ).resize(function() {
$( '.titleContainer' ).each(function() {
var titleContainerWidth = $(this).width();
var titleLeftWidth = $(this).find( '.titleLeft' ).outerWidth();
var titleRightWidth = $(this).find( '.titleRight' ).outerWidth();
remainingRight = titleContainerWidth - titleLeftWidth - 2;
remainingLeft = titleContainerWidth - titleRightWidth - 2;
$(this).find( '.horizontalLineRight' ).css("width", remainingRight);
$(this).find( '.horizontalLineLeft' ).css("width", remainingLeft);
});
});
});
It works fine when the h tag doesn't fill 100% width of container.
But when I change the width, the line disappear. I think I have to put <div class="horizontalLineRight orangeLine"> inside <div class="titleContainer"> but I don't know how I can calculate remaining width (free space) with jQuery.
You can try like below:
.titleContainer {
max-width:400px;
animation:change 3s linear infinite alternate;
}
.titleLeft {
background:
/*the line placed at the bottom of the container*/
linear-gradient(orange,orange) 0 calc(100% - 0.5em)/100% 2px no-repeat;
background-color:#000;
}
.titleLeft span {
/*inherit the background-color and hide the line under the text*/
background-color:inherit;
padding:0 5px;
color:#fff;
}
#keyframes change {
to {max-width:100px }
}
<div class="titleContainer">
<h1 class="titleLeft"><span>how We turn your</span></h1>
</div>
<div class="titleContainer">
<h1 class="titleLeft" style="background-color:red;"><span>how We turn your</span></h1>
</div>
In case you want transparency you can try this:
.titleContainer {
max-width: 400px;
animation: change 3s linear infinite alternate;
overflow:hidden; /*you need to hide the extra line width*/
}
.titleLeft span {
position: relative;
padding: 0 5px;
}
/*the line*/
.titleLeft span:after {
content: "";
position: absolute;
left: 100%; /*put at the end of the text*/
width: 100vw; /*use a big width to be sure to cover the need space*/
bottom: 0.5em;
height: 2px;
background-color: blue;
}
#keyframes change {
to {max-width: 100px}
}
body {
background:linear-gradient(to right,pink,red);
}
<div class="titleContainer">
<h1 class="titleLeft"><span>how We turn your</span></h1>
</div>
If you know which word (or group of words) you want the line to be next to, you can wrap those words inside a span and use display: flex + ::after on the span to get the desired effect shown in your first image.
<h1>How we turn <span>your</span> business requirements into</h1>
<style>
h1 span {
width: 100%;
background: black;
display: flex;
justify-content: space-between;
align-items: center;
}
h1 span:after {
content: "";
background: orange;
border-radius: 4px;
display: block;
height: 6px;
min-width: 50%;
flex: 1;
margin-left: 16px;
}
</style>
Here's a sandbox with a complete example.
If you just want it to take the remaining width of the title space, you shouldn't need to do any jQuery shenanigans with this approach.
You could use an empty span with some styling to solve your issue. Try adding <span id='myLine'></span> after the h tag, with some CSS styling:
#myLine {
width: 80%; /*or any percentage that makes it look good for you*/
/*also set the border bottom to look the way you want, e.g.:*/
border-bottom: 2px solid orange;
}

Shopping cart with hover dropdown

I'm uses a previous design of shopping cart, but can't applied the option hover shoppign cart, this its a code example.
My code
$('#cart').hover(function(e) {
$(".shopping-cart").stop(true, true).addClass("active");
}, function() {
$(".shopping-cart").stop(true, true).removeClass("active");
});
I need the contents of the cart not to disappear until the mouse pointer is out.
Example codepen
See the Pen Shopping Cart Dropdown by Eduardo (#alexd2) on CodePen.
use Multiple Selector will solve your issue.
$('#cart, .shopping-cart').hover(function(e) {
$(".shopping-cart").stop(true, true).addClass("active");
}, function() {
$(".shopping-cart").stop(true, true).removeClass("active");
});
With pure css, you could probably do something like this.
.cart {
background-color: lightblue;
float: right;
text-align: right;
position: relative;
}
.list {
background-color: lightgreen;
height: 250px;
width: 300px;
border: 2px solid red;
right: 0;
position: absolute;
transition: 1s all;
transform: scale(0) ;
transform-origin: 100% 0%;
}
.cart:hover > .list {
transform: scale(1);
}
<div>
<div class="cart">
This is a cart
<div class="list">
some long list
</div>
</div>
</div>
position: absolute is optional (along with the accompanying css), just that if you don't have it, then the cart will be as long as the child's width, which may or may not be desirable.
Just remove "active" from this
$(".shopping-cart").stop(true, true).removeClass("active");
to this one
$(".shopping-cart").stop(true, true).removeClass("");

How to add animation when page change each other?

I am looking for way to make slowly changing of pages after I press button. I want to use only JS without jQuery. Now I have script which change blocks, but I use display none; I am not sure that I can add slowly changing of pages with this. I tryied to use tramsform property but doesn't work good. I need dont have any overflow. It has to look close to this https://tympanus.net/Development/PageTransitions/
var acc = document.getElementsByClassName("btn-arrow");
for (var i = 0; i < acc.length; i++) {
acc[i].onclick = function showNext(){
var parent = this.parentElement;
var nextToOpen = parent.nextElementSibling;
nextToOpen.style.display ="block";
parent.style.display ="none";
}
}
.big{
transition-property: all;
transition-duration: 0.2s;
transition-timing-function: linear;
transition-delay: initial;
overflow: hidden;
}
.one{
background:pink;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: flex-end;
}
.two{
background:green;
width: 100vw;
height: 100vh;
display:none;
}
.icon-arrow-down2{
font-size: 60px;
color: silver;
margin-bottom: 50px;
}
.btn-arrow{
background-color : rgb(255, 238, 192);
box-shadow: none;
border: none;
}
.btn-arrow:hover{
border: none;
}
button,
button:active,
button:focus {
outline: none;
}
<div class="big">
<div class="one">
<button class="btn-arrow" onclick="showNext()">
<span class="icon-arrow-down2"></span>
</button>
</div>
<div class="two"></div>
</div>
You have to play with css animations. I have added some modifications to point you in the right direction. But basically, my recommendation is:
All your pages have the same class with common styles (.page), and then each of them have different background-color.
You need a specific class (.page-visible) that will be added to the next page you want to display, and removed from current visible page. This class just controls visibility. Please notice that the previous class (.page) has display: none;, as is the common one for all the pages.
You will need a different animation for each movement (move up, move down, from left to right, from right to left). I just added one as an example in the code snippet.
And then the magic comes listening to the animationend event: you apply the animation to both pages (the current visible and the next page), make next page visible applying the .page-visible class, and listen to endanimation event. When it happens, just hide the prev page removing .page-visible class, and remove animation classes.
The code works for just this 2 pages (one and two), but you can easily optimize it. I recommend you to take a look at the original page you posted, check their css and their js (open chrome developer tools and go to Sources, they don't have the files minified so you will see how they do everything :).
Does this make sense to you? I hope it helps and point you in the right direction. Animations are super fun! :)
(EDIT: Ah! I added some width&height to the button to be able to see it, hehe, it's up in the left corner now).
var acc = document.getElementsByClassName("btn-arrow");
for (var i = 0; i < acc.length; i++) {
acc[i].onclick = function showNext(){
var visibleElement = document.getElementsByClassName('page-visible')[0];
var nextToOpen = visibleElement.nextElementSibling;
nextToOpen.addEventListener('animationend', () => {
visibleElement.classList.remove('page-visible');
visibleElement.classList.remove('page-moveUp');
nextToOpen.classList.remove('page-moveUp');
});
visibleElement.classList.add('page-moveUp');
nextToOpen.classList.add('page-visible');
nextToOpen.classList.add('page-moveUp');
}
}
.page{
display: none;
overflow: hidden;
width: 100vw;
height: 100vh;
justify-content: center;
}
.page-moveUp {
animation: moveUp .6s ease both;
}
#keyframes moveUp {
from { }
to { transform: translateY(-100%); }
}
.page-visible {
display: block;
}
.one {
background:pink;
}
.two {
background:green;
}
.icon-arrow-down2{
font-size: 60px;
color: silver;
margin-bottom: 50px;
}
.btn-arrow{
background-color : rgb(255, 238, 192);
height: 20px;
width: 50px;
box-shadow: none;
border: none;
}
.btn-arrow:hover{
border: none;
}
button,
button:active,
button:focus {
outline: none;
}
<div class="big">
<button class="btn-arrow">
<span class="icon-arrow-down2"></span>
</button>
<div class="page page-visible one"></div>
<div class="page two"></div>
</div>

Categories