How to style Stripe.js custom element like my other bootstrap floating label elements

huangapple go评论72阅读模式
英文:

How to style Stripe.js custom element like my other bootstrap floating label elements

问题

我想要为我的Stripe.js元素(卡号、CVC、有效期)添加浮动标签样式,以保持与我使用的其他bootstrap浮动标签一致。我正在使用ngx-stripe作为Stripe.js的封装器。我已经成功使它们看起来与我的其他bootstrap元素类似,但在获得焦点时它们不会浮动。Stackblitz示例。

Stripe在这里提供了有关浮动标签外观的一些信息,但在尝试不同的方法后,没有任何变化!所以我可能没有正确使用它,或者我的bootstrap类可能与Stripe的CSS发生冲突?

  1. https://stripe.com/docs/elements/appearance-api?platform=web#form-inputs---floating-labels
  2. https://stripe.com/docs/elements/appearance-api?platform=web#others

这是使用bootstrap浮动类的卡号元素示例:

<div class="form-floating mb-3">
  <div id="floatingNumber" class="form-control stripe-form-control" placeholder="例如 1111 1111 1111 1111"></div>
  <label for="floatingNumber">Card Number</label>
</div>

你可以看到标签和文本的位置是固定的,它们不会浮动。

这是我的已经设置好的Stackblitz

我尝试过的方法:

  1. 添加bootstrap浮动类
  2. 在创建Stripe元素时,在外观中添加了appearance: { labels: 'floating' }
  3. 添加"class="stripe-form-control""作为类 - 在Stripe网站的某个地方找到的
英文:

I'd like to style my Stripe.js elements (card number, Cvc, Expiry) with floating labels, to be consistent with my other bootstrap floating labels I'm using ngx-stripe as a wrapper around Stripe.js. I've been able to make them look similar to my other bootstrap elements, but they don't float when focus is given. Stackblitz here.

Stripe has some info on floating label appearances here, but after attempting different things, nothing changed! So I might not be using it correctly or my bootstrap classes might be interfering with the Stripe CSS?

  1. https://stripe.com/docs/elements/appearance-api?platform=web#form-inputs---floating-labels
  2. https://stripe.com/docs/elements/appearance-api?platform=web#others

Here is what my card number element looks like using bootstrap's floating classes:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

&lt;div class=&quot;form-floating mb-3&quot;&gt;
  &lt;div id=&quot;floatingNumber&quot; class=&quot;form-control stripe-form-control&quot; placeholder=&quot;ex. 1111 1111 1111 1111&quot;&gt;&lt;/div&gt;
  &lt;label for=&quot;floatingNumber&quot;&gt;Card Number&lt;/label&gt;
&lt;/div&gt;

<!-- end snippet -->

Image from my Stackblitz

How to style Stripe.js custom element like my other bootstrap floating label elements

You can see the positions of the label and text are fixed, they don't float.

Here is my Stackblitz that has it set up.
Here is what I tried.

  1. Added bootstrap floating classes
  2. When creating the Stripe elements I added appearance: { labels: 'floating' } in the appearance
  3. Added "stripe-form-control" as a class - found somewhere on Stripe website

答案1

得分: 1

我不是一个Angular、Bootstrap或Stripe.js的专家,但我刚刚阅读了文档。

首先,为了使Bootstrap的浮动标签起作用,需要<input><label>兄弟元素,因为浮动标签依赖于:placeholder-shown伪元素。问题在于,您挂载的Stripe元素不是一个输入,它们实际上是嵌套在iframe中的输入,因此要使Bootstrap的浮动标签正常工作,需要进行一些调整。

其次,您提到了Stripe API文档中说可以使用{ labels: 'floating' },但经过尝试后发现它只对挂载为一组的元素有效(不确定叫什么名字),其中之一是address,它有效是因为标签是在iframe内部(我在下面的Stackblitz链接中附上了证明)。然后,为了在挂载的元素上使用标签,我们必须使用此方法。不幸的是,该方法没有使标签注入到iframe内部,它仍然在外部,因此来自外观API的浮动标签不会起作用。

尽管在iframe内部,幸运的是,输入仍然可以更改iframe外部的类(它可以产生StripeElement--focusStripeElement--completeStripeElement--invalid),因此我们可以模仿Bootstrap浮动标签的行为,并将其实现到我们的自定义代码中,通过复制Bootstrap的行为。

我能想到的最简单解决方案是添加以下CSS:

...
/* 重置 #custom-inputs 的浮动标签的原始行为 */
#custom-inputs .form-floating > .form-control:focus ~ label,
#custom-inputs .form-floating > .form-control:not(:placeholder-shown) ~ label {
  opacity: 1;
  transform: scale(1) translateY(0) translateX(0);
}

/* 模仿 #custom-inputs 的Bootstrap浮动标签行为 */
#custom-inputs .form-floating > .form-control.StripeElement--focus ~ label,
#custom-inputs .form-floating > .form-control.StripeElement--complete ~ label,
#custom-inputs .form-floating > .form-control.StripeElement--invalid ~ label {
  opacity: 0.8;
  transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
}

#custom-inputs .StripeElement--focus {
  color: #212529;
  background-color: #fff;
  border-color: #86b7fe;
  outline: 0;
  box-shadow: 0 0 0 0.25rem rgb(13 110 253 / 25%);
}
...

然后清空占位符(因为我们想使用浮动标签):

...
if (!this.cardNumber) {
  this.cardNumber = this.elements.create('cardNumber', {
    ...this.emptyOptions,
    placeholder: '',
  });
  this.cardNumber.mount('#floatingNumber');
}
if (!this.cardCvc) {
  this.cardCvc = this.elements.create('cardCvc', {
    ...this emptyOptions,
    placeholder: '',
  });
  this.cardCvc.mount('#floatingCvc');
}
if (!this.cardExpiry) {
  this.cardExpiry = this.elements.create('cardExpiry', {
    ...this.emptyOptions,
    placeholder: '',
  });
  this.cardExpiry.mount('#floatingExpiry');
}
...

这里是经过修改的工作Stackblitz

英文:

I'm not an expert in angular, bootstrap, or stripejs, but I just read the documentations.

Firstly, in order for bootstrap floating labels to work, it requires the &lt;input&gt; and &lt;label&gt; to be siblings, because the floating label will work because of :placeholder-shown pseudo element. The problem here is that your mounted stripe elements aren't an input, they became an input wrapped by an iframe, so bootstrap floating labels won't work without some tweak.

Secondly, you mentioned the stripe API documentation that says that we can use { labels: &#39;floating&#39; }, and after trying this, it turns out that it only works for elements that are mounted as a pack (not sure what it's called), one of that elements is address, and it works because the label is inside the iframe (I attach the proof on the Stackblitz link down below). And then, in order to use a label on a mounted element, we must use this method. Unfortunately, that method didn't make the label injected inside the iframe, it's still outside, so the floating labels from the appearance API won't work.

Despite being inside the iframe, thankfully, the inputs can still change the class outside the iframe (it could give StripeElement--focus, StripeElement--complete, and StripeElement--invalid), so we could just imitate the behavior of the bootstrap floating labels and implement it to our custom code, by copying the bootstrap behavior.

The easiest solution I could think of is by adding this CSS:

...
/* reset the original behavior of the floating labels for #custom-inputs */
#custom-inputs .form-floating &gt; .form-control:focus ~ label,
#custom-inputs .form-floating &gt; .form-control:not(:placeholder-shown) ~ label {
  opacity: 1;
  transform: scale(1) translateY(0) translateX(0);
}

/* mimic the behavior of bootstrap floating labels for #custom-inputs */
#custom-inputs .form-floating &gt; .form-control.StripeElement--focus ~ label,
#custom-inputs .form-floating &gt; .form-control.StripeElement--complete ~ label,
#custom-inputs .form-floating &gt; .form-control.StripeElement--invalid ~ label {
  opacity: 0.8;
  transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
}

#custom-inputs .StripeElement--focus {
  color: #212529;
  background-color: #fff;
  border-color: #86b7fe;
  outline: 0;
  box-shadow: 0 0 0 0.25rem rgb(13 110 253 / 25%);
}
...

And then empty the placeholder (because we want to use the floating labels):

...
      if (!this.cardNumber) {
        this.cardNumber = this.elements.create(&#39;cardNumber&#39;, {
          ...this.emptyOptions,
          placeholder: &#39;&#39;,
        });
        this.cardNumber.mount(&#39;#floatingNumber&#39;);
      }
      if (!this.cardCvc) {
        this.cardCvc = this.elements.create(&#39;cardCvc&#39;, {
          ...this.emptyOptions,
          placeholder: &#39;&#39;,
        });
        this.cardCvc.mount(&#39;#floatingCvc&#39;);
      }
      if (!this.cardExpiry) {
        this.cardExpiry = this.elements.create(&#39;cardExpiry&#39;, {
          ...this.emptyOptions,
          placeholder: &#39;&#39;,
        });
        this.cardExpiry.mount(&#39;#floatingExpiry&#39;);
      }
...

Here is the working altered Stackblitz

答案2

得分: -1

我已经稍微更改了你的代码,将div替换为input。你是想这样做吗?

这段代码中,使用input标签而不是div标签可以正常工作,因为name字段使用的是input,而不是div标签。

<h5>Working Floating name</h5>
<div class="form-floating mb-3">
   <input type="text" class="form-control" id="floatingInput" formControlName="name" placeholder="Brad Pitt">
   <label for="floatingInput">Name</label>
</div>

你可以看到,在你尝试使用的样式中,包括:focus伪类,它不适用于div标签。

.form-floating > .form-control-plaintext ~ label, .form-floating > .form-control:focus ~ label, .form-floating > .form-control:not(:placeholder-shown) ~ label, .form-floating > .form-select ~ label {
    opacity: .65;
    transform: scale(.85) translateY(-0.5rem) translateX(0.15rem);
}

div:focus 不起作用

input:focus 起作用

英文:

I have changed your code a little bit, set input instead div. Are you trying to do that?
https://stackblitz.com/edit/angular-kauqxz?file=src%2Ftest%2Fstripe%2Fstripe.component.css,src%2Ftest%2Fstripe%2Fstripe.component.html

it works with a name input, bc for name you have an input, not a div tag

   &lt;h5&gt;Working Floating name&lt;/h5&gt;
   &lt;div class=&quot;form-floating mb-3&quot;&gt;
      &lt;input type=&quot;text&quot; class=&quot;form-control&quot; id=&quot;floatingInput&quot; formControlName=&quot;name&quot; placeholder=&quot;Brad Pitt&quot;&gt;
      &lt;label for=&quot;floatingInput&quot;&gt;Name&lt;/label&gt;
   &lt;/div&gt;

here you can see that this style you are trying to use includes :focus pseudoclass and it doesn't work with div

.form-floating&gt;.form-control-plaintext~label, .form-floating&gt;.form-control:focus~label, .form-floating&gt;.form-control:not(:placeholder-shown)~label, .form-floating&gt;.form-select~label {
    opacity: .65;
    transform: scale(.85) translateY(-0.5rem) translateX(0.15rem);
}

div:focus -> it doesn't work

input:focus -> it works

huangapple
  • 本文由 发表于 2023年3月3日 17:50:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/75625511.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定