尝试重新创建像 Stripe 这样的抖动动画

Posted

技术标签:

【中文标题】尝试重新创建像 Stripe 这样的抖动动画【英文标题】:Trying to recreate a shake animation like Stripe 【发布时间】:2015-12-18 15:06:01 【问题描述】:

当出现一些表单填写错误时,我正在尝试重新创建负摇动动画,就像 Strike 在他们的支付框中使用的那样。

我基本上复制了它的动画关键帧,但在我的使用中它的工作方式不同。

我的版本:

http://codepen.io/FelipeMartinin/pen/NGrXvR

条纹版本:

https://stripe.com/docs/checkout(点击“刷卡支付”按钮,点击“支付”后不填输入即可查看动画)

如果你注意到,Stripe 动画有 3d 运动效果,而在我的版本中,盒子只是水平抖动。即使使用相同的关键帧。

跟随关键帧下方

@keyframes panelShakeAnimation 
  0 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  

  12.5% 
    -webkit-transform: translateX(-6px) rotateY(-5deg);
    -moz-transform: translateX(-6px) rotateY(-5deg);
    -ms-transform: translateX(-6px) rotateY(-5deg);
    -o-transform: translateX(-6px) rotateY(-5deg);
    transform: translateX(-6px) rotateY(-5deg)
  

  37.5% 
    -webkit-transform: translateX(5px) rotateY(4deg);
    -moz-transform: translateX(5px) rotateY(4deg);
    -ms-transform: translateX(5px) rotateY(4deg);
    -o-transform: translateX(5px) rotateY(4deg);
    transform: translateX(5px) rotateY(4deg)
  

  62.5% 
    -webkit-transform: translateX(-3px) rotateY(-2deg);
    -moz-transform: translateX(-3px) rotateY(-2deg);
    -ms-transform: translateX(-3px) rotateY(-2deg);
    -o-transform: translateX(-3px) rotateY(-2deg);
    transform: translateX(-3px) rotateY(-2deg)
  

  87.5% 
    -webkit-transform: translateX(2px) rotateY(1deg);
    -moz-transform: translateX(2px) rotateY(1deg);
    -ms-transform: translateX(2px) rotateY(1deg);
    -o-transform: translateX(2px) rotateY(1deg);
    transform: translateX(2px) rotateY(1deg)
  

  100% 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  


.headShake 
  -webkit-animation-duration: 400ms;
  -webkit-animation-timing-function: ease-in-out;
  -webkit-animation-name: panelShakeAnimation;
  -moz-animation-duration: 400ms;
  -moz-animation-timing-function: ease-in-out;
  -moz-animation-name: panelShakeAnimation

如何让我的动画像 Stripe 一样工作?谢谢!

【问题讨论】:

【参考方案1】:

您只需在容器元素上添加perspective 规则。这使得转换将出现在 3D 空间中。

现场演示:

$("button").on('click', function(e) 
	e.preventDefault();
  
	$(".card").toggleClass("headShake");
);
/* Basic Reset */
*,
*:after,
*:before 
  margin: 0;
  padding: 0;
  box-sizing: border-box;


html 
  font-size: 62.5%;


body 
  font-size: 1.8em;
  line-height: 1.875;
  font-family: "Roboto", sans-serif;
  font-weight: 400;
  color: #555;
  background-color: #eeeeee;


/* Basics Styles */
a 
  text-decoration: none;
  color: #2196f3;


h1, h2, h3 
  margin-bottom: 1.2rem;
  line-height: 1.5;


h1 
  font-size: 4.8rem;


h2 
  font-size: 3.2rem;


h4 
  font-size: 1.8rem;
  font-weight: 300;


.lead 
  font-size: 1.8rem;


p 
  margin-bottom: 1.5rem;


.main-title 
  font-weight: 100;
  font-size: 32px;
  text-align: center;


.main-subtitle 
  font-weight: 100;
  font-size: 18px;
  text-align: center;


.text-small 
  font-size: 75%;


.text-right 
  text-align: right;


.text-left 
  text-align: left;


.text-center 
  text-align: center;


.left 
  float: left;


.right 
  float: right;


.display__inline 
  display: inline;


/* Padding Helpers */
.padding-tb 
  padding-top: 3%;
  padding-bottom: 3%;


/* Basic Demo Styles */
.site-container 
  max-width: 320px;
  margin: 10px auto;
  padding-left: 0.6em;
  padding-right: 0.6em;

@media screen and (min-width: 60.063em) 
  .site-container 
    max-width: 400px;
  


.footer__content 
  margin-top: 1.6rem;


/* Card */
.card 
  top: 250px;
  position: relative;
  overflow: hidden;
  background-color: white;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.24), 0 1px 2px 0 rgba(0, 0, 0, 0.12);
  border-radius: 2px;
  padding: 1em;

.card h3 
  font-weight: bold;


/* Material Design Form Inputs */
.form__wrapper 
  overflow: hidden;
  position: relative;
  z-index: 1;
  display: inline-block;
  margin-bottom: 1.6rem;
  width: 100%;
  vertical-align: top;


.form__wrapper--submit 
  padding: 1.6rem 0;


.form__input 
  display: block;
  position: relative;
  margin-top: 1em;
  padding: 0.84em 0;
  width: 100%;
  box-sizing: border-box;
  color: #444;
  font-size: 1.6rem;
  outline: 0;
  border: none;
  border-bottom: solid 1px #ddd;
  -webkit-transition: all 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  -moz-transition: all 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  -o-transition: all 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  transition: all 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 96%, #2196f3 4%);
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 96%, #2196f3 4%);
  background-position: -400px 0;
  background-size: 400px 100%;
  background-repeat: no-repeat;
  /**
   * Remove default box-shadow for required pseudo classes 
   */
  /**
   *  When input contain a class of .error 
   */

.form__input:required 
  box-shadow: none;

.form__input.error 
  -webkit-transition: all 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  -moz-transition: all 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  -o-transition: all 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  transition: all 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 96%, #f44336 4%);
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 96%, #f44336 4%);
  background-position: 0 0;
  background-size: 400px 100%;
  background-repeat: no-repeat;

.form__input:focus 
  background-position: 0 0;
  color: #444;
  -webkit-transition: transform 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  -moz-transition: transform 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  -o-transition: transform 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  transition: transform 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);


/* Form Label */
.form__label 
  position: absolute;
  bottom: 0;
  left: 0;
  padding: 0;
  width: 100%;
  height: calc(100% - 1em);
  text-align: left;
  pointer-events: none;
  color: #999;


/* Form Label Content */
.form__label-content 
  position: absolute;
  -webkit-transition: transform 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  -moz-transition: transform 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  -o-transition: transform 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);
  transition: transform 0.3s cubic-bezier(0.64, 0.09, 0.08, 1);


/**
 * 1. When input is focused move the label to top
 * 2. when the input field has a value move the label to top
 */
.form__input:focus ~ .form__label .form__label-content,
.form--filled .form__label-content 
  font-size: 1.4rem;
  -webkit-transform: translate3d(0, -65%, 0);
  -moz-transform: translate3d(0, -65%, 0);
  transform: translate3d(0, -65%, 0);


/**
 * Error Styles
 * .error class generated by jquery.validate.min.js plugin
 */
.error 
  font-size: 1.4rem;
  color: #f44336;
  display: block;


/* Basic Buttons */
.btn 
  display: inline-block;
  padding: 0.6em 1.5em;
  border-radius: 2px;
  background-color: #2196f3;
  color: #fff;
  border: 0;
  outline: none;
  cursor: pointer;
  font-family: inherit;
  font-weight: 400;
  font-size: 1.6rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.24), 0 1px 2px 0 rgba(0, 0, 0, 0.12);
  transition: all 0.2s ease;

.btn:focus, .btn:hover 
  background-color: #0d8aee;

.btn.btn-block 
  width: 100%;
  display: block;


/* Modal Styles */
.modal 
  overflow: hidden;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #fff;
  padding: 1em;
  z-index: 999;
  border-radius: 2px;
  -webkit-transform: translate3d(0, 100%, 0);
  -moz-transform: translate3d(0, 100%, 0);
  transform: translate3d(0, 100%, 0);
  -webkit-transition: transform 0.3s cubic-bezier(0, 0.795, 0, 1);
  -moz-transition: transform 0.3s cubic-bezier(0, 0.795, 0, 1);
  -ms-transition: transform 0.3s cubic-bezier(0, 0.795, 0, 1);
  -o-transition: transform 0.3s cubic-bezier(0, 0.795, 0, 1);
  transition: transform 0.3s cubic-bezier(0, 0.795, 0, 1);


/* Close icon style for model */
.modal--close 
  display: block;
  float: right;
  cursor: pointer;
  width: 32px;
  height: 32px;
  line-height: 32px;
  text-align: center;
  font-size: 1.6em;
  color: #888;


.modal--open 
  -webkit-transform: translate3d(0, 0, 0);
  -moz-transform: translate3d(0, 0, 0);
  transform: translate3d(0, 0, 0);



@-moz-keyframes panelShakeAnimation 
  0 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  

  12.5% 
    -webkit-transform: translateX(-6px) rotateY(-5deg);
    -moz-transform: translateX(-6px) rotateY(-5deg);
    -ms-transform: translateX(-6px) rotateY(-5deg);
    -o-transform: translateX(-6px) rotateY(-5deg);
    transform: translateX(-6px) rotateY(-5deg)
  

  37.5% 
    -webkit-transform: translateX(5px) rotateY(4deg);
    -moz-transform: translateX(5px) rotateY(4deg);
    -ms-transform: translateX(5px) rotateY(4deg);
    -o-transform: translateX(5px) rotateY(4deg);
    transform: translateX(5px) rotateY(4deg)
  

  62.5% 
    -webkit-transform: translateX(-3px) rotateY(-2deg);
    -moz-transform: translateX(-3px) rotateY(-2deg);
    -ms-transform: translateX(-3px) rotateY(-2deg);
    -o-transform: translateX(-3px) rotateY(-2deg);
    transform: translateX(-3px) rotateY(-2deg)
  

  87.5% 
    -webkit-transform: translateX(2px) rotateY(1deg);
    -moz-transform: translateX(2px) rotateY(1deg);
    -ms-transform: translateX(2px) rotateY(1deg);
    -o-transform: translateX(2px) rotateY(1deg);
    transform: translateX(2px) rotateY(1deg)
  

  100% 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  


@-webkit-keyframes panelShakeAnimation 
  0 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  

  12.5% 
    -webkit-transform: translateX(-6px) rotateY(-5deg);
    -moz-transform: translateX(-6px) rotateY(-5deg);
    -ms-transform: translateX(-6px) rotateY(-5deg);
    -o-transform: translateX(-6px) rotateY(-5deg);
    transform: translateX(-6px) rotateY(-5deg)
  

  37.5% 
    -webkit-transform: translateX(5px) rotateY(4deg);
    -moz-transform: translateX(5px) rotateY(4deg);
    -ms-transform: translateX(5px) rotateY(4deg);
    -o-transform: translateX(5px) rotateY(4deg);
    transform: translateX(5px) rotateY(4deg)
  

  62.5% 
    -webkit-transform: translateX(-3px) rotateY(-2deg);
    -moz-transform: translateX(-3px) rotateY(-2deg);
    -ms-transform: translateX(-3px) rotateY(-2deg);
    -o-transform: translateX(-3px) rotateY(-2deg);
    transform: translateX(-3px) rotateY(-2deg)
  

  87.5% 
    -webkit-transform: translateX(2px) rotateY(1deg);
    -moz-transform: translateX(2px) rotateY(1deg);
    -ms-transform: translateX(2px) rotateY(1deg);
    -o-transform: translateX(2px) rotateY(1deg);
    transform: translateX(2px) rotateY(1deg)
  

  100% 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  


@-o-keyframes panelShakeAnimation 
  0 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  

  12.5% 
    -webkit-transform: translateX(-6px) rotateY(-5deg);
    -moz-transform: translateX(-6px) rotateY(-5deg);
    -ms-transform: translateX(-6px) rotateY(-5deg);
    -o-transform: translateX(-6px) rotateY(-5deg);
    transform: translateX(-6px) rotateY(-5deg)
  

  37.5% 
    -webkit-transform: translateX(5px) rotateY(4deg);
    -moz-transform: translateX(5px) rotateY(4deg);
    -ms-transform: translateX(5px) rotateY(4deg);
    -o-transform: translateX(5px) rotateY(4deg);
    transform: translateX(5px) rotateY(4deg)
  

  62.5% 
    -webkit-transform: translateX(-3px) rotateY(-2deg);
    -moz-transform: translateX(-3px) rotateY(-2deg);
    -ms-transform: translateX(-3px) rotateY(-2deg);
    -o-transform: translateX(-3px) rotateY(-2deg);
    transform: translateX(-3px) rotateY(-2deg)
  

  87.5% 
    -webkit-transform: translateX(2px) rotateY(1deg);
    -moz-transform: translateX(2px) rotateY(1deg);
    -ms-transform: translateX(2px) rotateY(1deg);
    -o-transform: translateX(2px) rotateY(1deg);
    transform: translateX(2px) rotateY(1deg)
  

  100% 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  


@-ms-keyframes panelShakeAnimation 
  0 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  

  12.5% 
    -webkit-transform: translateX(-6px) rotateY(-5deg);
    -moz-transform: translateX(-6px) rotateY(-5deg);
    -ms-transform: translateX(-6px) rotateY(-5deg);
    -o-transform: translateX(-6px) rotateY(-5deg);
    transform: translateX(-6px) rotateY(-5deg)
  

  37.5% 
    -webkit-transform: translateX(5px) rotateY(4deg);
    -moz-transform: translateX(5px) rotateY(4deg);
    -ms-transform: translateX(5px) rotateY(4deg);
    -o-transform: translateX(5px) rotateY(4deg);
    transform: translateX(5px) rotateY(4deg)
  

  62.5% 
    -webkit-transform: translateX(-3px) rotateY(-2deg);
    -moz-transform: translateX(-3px) rotateY(-2deg);
    -ms-transform: translateX(-3px) rotateY(-2deg);
    -o-transform: translateX(-3px) rotateY(-2deg);
    transform: translateX(-3px) rotateY(-2deg)
  

  87.5% 
    -webkit-transform: translateX(2px) rotateY(1deg);
    -moz-transform: translateX(2px) rotateY(1deg);
    -ms-transform: translateX(2px) rotateY(1deg);
    -o-transform: translateX(2px) rotateY(1deg);
    transform: translateX(2px) rotateY(1deg)
  

  100% 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  

  
@keyframes panelShakeAnimation 
  0 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  

  12.5% 
    -webkit-transform: translateX(-6px) rotateY(-5deg);
    -moz-transform: translateX(-6px) rotateY(-5deg);
    -ms-transform: translateX(-6px) rotateY(-5deg);
    -o-transform: translateX(-6px) rotateY(-5deg);
    transform: translateX(-6px) rotateY(-5deg)
  

  37.5% 
    -webkit-transform: translateX(5px) rotateY(4deg);
    -moz-transform: translateX(5px) rotateY(4deg);
    -ms-transform: translateX(5px) rotateY(4deg);
    -o-transform: translateX(5px) rotateY(4deg);
    transform: translateX(5px) rotateY(4deg)
  

  62.5% 
    -webkit-transform: translateX(-3px) rotateY(-2deg);
    -moz-transform: translateX(-3px) rotateY(-2deg);
    -ms-transform: translateX(-3px) rotateY(-2deg);
    -o-transform: translateX(-3px) rotateY(-2deg);
    transform: translateX(-3px) rotateY(-2deg)
  

  87.5% 
    -webkit-transform: translateX(2px) rotateY(1deg);
    -moz-transform: translateX(2px) rotateY(1deg);
    -ms-transform: translateX(2px) rotateY(1deg);
    -o-transform: translateX(2px) rotateY(1deg);
    transform: translateX(2px) rotateY(1deg)
  

  100% 
    -webkit-transform: translateX(0);
    -moz-transform: translateX(0);
    -ms-transform: translateX(0);
    -o-transform: translateX(0);
    transform: translateX(0)
  


.headShake 
  -webkit-animation-duration: 400ms;
  -webkit-animation-timing-function: ease-in-out;
  -webkit-animation-name: panelShakeAnimation;
  -moz-animation-duration: 400ms;
  -moz-animation-timing-function: ease-in-out;
  -moz-animation-name: panelShakeAnimation;


.site-container 
  -webkit-perspective: 800px;
  perspective: 800px;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 class="main-title">Head Shake Animation</h1>
<h2 class="main-subtitle">An amazing animation for negative feedbacks</h2>

	<section class="site-container padding-tb">
		
		<section class="card" style="opacity: 1; transition: none; transform: translateY(0px) scale(1); margin-top: -244px;">
			
			<h3 >Login Form</h3>

			<form action="#" class="form" method="post">
			    <div class="form__wrapper">
			        <input type="email" class="form__input" id="email" name="email">
			        <label class="form__label" for="email">
						<span class="form__label-content">Email</span>
					</label>
			     </div>

			    <div class="form__wrapper">
			        <input type="password" class="form__input" id="password"  name="password">
			        <label class="form__label" for="password">
						<span class="form__label-content">Password</span>
					</label>
			       
			     </div>

			    <div class="form__wrapper--submit">
			    	<div class="form__input-submit">
			        	<button  class="btn btn-block">Submit to run</button>
			        </div>
			    </div>
			</form>
			 

		</section><!-- /card -->


			</section><!-- /site-container -->

【讨论】:

【参考方案2】:

为容器添加透视图,以获得 3-d 效果

.site-container 
  max-width: 320px;
  margin: 10px auto;
  padding-left: 0.6em;
  padding-right: 0.6em;
  perspective: 400px;

【讨论】:

以上是关于尝试重新创建像 Stripe 这样的抖动动画的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:输入无效时文本字段抖动动画

AEJoy —— 使用 js 脚本创建非平滑抖动动画

如何创建带有发票的 Stripe 订单?

没有这样的令牌:'btok_1JGm2oKFR93cFUSYN2bui4Yb' 当我尝试为 Stripe 客户创建银行账户时

iphone - 创建像用户位置蓝色大理石水滴这样的动画

在创建 Stripe 客户时,在 Android 中使用与在 iOS 中相同的云功能