Why is my CSS Flip-Card back-face input getting focus on click?

Viewed 529

I've built a simple CSS Flip card; everything works as expected except for one thing, I notice that if I flip the card, there's a zone (about half of the visible input) where the click triggers a focus on the input in the back face of the card.

This causes some issues since autocomplete will fill the back facing inputs, and I can't type in the current input since it doesn't get focus unless I click on the other half of it.

Here's the stackblitz example. It will open up with the card showing the "Log In" face, if you click on "Forgot Password?" the card will flip and show the other face with a single input, you can see here the behavior described above.

https://stackblitz.com/edit/angular-h8pca9

Also you can see if you inspect with DevTools that half of the input inspects the backfacing control, and the other half the current input:

Inspecting left half of the input Notice here the inspector shows the #username input

enter image description here

Here it shows the #email input when I hover over the right side of the same input

3 Answers

Testing

I tested your code on both Firefox and Chrome. Here are the problems present respectively.

  • Firefox. In Firefox, the input field on .card-face__back works as expected: when you click on the input field, focus is given to the intended field. However, the problem present here is that backface-visibility does not work with Firefox if the element has preserve-3d but does not have any sort of transform applied to it.
  • Chrome. In Chrome, the problem is that the input field on .card-face__back has a weird interaction. As you've mentioned, clicking on the first half (left side) of the input field causes the input field on .card-face__front to receive focus. Clicking on the second half (right side) of the input field causes the focus to be given as intended. However, backface-visibility works perfectly in Chrome even without transform applied to the element.

I am not sure what exact procedures each browser runs to achieve the two different results, so I cannot cite any official sources and/or algorithms to show why they run differently. However, I have a logical explanation to why it isn't working on Chrome (the buggy click behaviour).


backface-visibility

backface-visibility simply hides the item from being seen visually. By this logic, there is nothing preventing us from interacting with this element if we can click it (which we can't, because visually, the item isn't there!). Chrome, for some reason, allows us to interact with the element in your specific scenario. Why this is happening exactly, I don't know. Logically speaking, the hidden element shouldn't be able to be clicked, but we can.


Solution

Real-life 3D cards have a front and back. In your current code, the front and back of the card share the same space (in 3D space). In real-life cards, the front and back of cards have a separator (the thickness of the card, e.g. 1mm). We can imitate this behavior by adding translateZ to mimic real-life cards 3D space separation.

Adding translateZ(1px) to the front and back of the card in your code works. Logically, this is because when you flip the card, the front of the card is located 2px behind the back of the card (which is currently in front). This ensures that the items on the front of the card (which is hidden) can't be interacted with at all (like an element that is absolutely positioned but is located behind something because its z-index is set to -1); thus, you can focus on your email input field on .card-face__back correctly. The same logic works for when the front of the card is indeed facing the user.

We add translateZ(1px) to both the front and back of the card and not translateZ(1px) and translateZ(-1px) respectively because the back of the card is rotated by 180 degrees on the Y axis first; thus, we need to inverse the -1px value to 1px. Alternatively, you can apply the translateZ(1px) first before rotateY(180deg) on the back of the card.

Simply add this CSS to your .card-face__front and .card-face__back. The solution works for both Firefox and Chrome. Here's the code for you to run: https://angular-krh29n.stackblitz.io.

.scene .flip-card .card-face__front {
   transform: translateZ(1px);
 }
.scene .flip-card .card-face__back {
     transform: translateZ(-1px) rotateY(180deg);
}

If I get it right you can add *ngIf="!isFlipped" To your Username input. to hide unnecessary input in the back of your card.

Add this CSS to your app component, it will help you.

.is-flipped>section:nth-last-child(2) {
    transition: transform 1s;
    transform-style: preserve-3d;
    transform: scale(0);
}

Explanation :-

When your card is flipped i am setting height and width of div with login controls as 0 by scaling it to 0.

Related