Ad

Making Border-image Work With Gradients

- 1 answer

I'm working on a webapp that uses react.js and sass for styles (so all my style files are .scss). I have a textbox with the current style:

input[type=text] {
  text-align: center;
  font: inherit;
  border: 6px solid #999999;
  padding: 5px 5px;
  font-size: 15px;
  box-shadow: 0 1px 1px #DDD;
  width: 223px;
  outline: none;
  display: block;
  color: #7B8585;
  margin: 0 auto 20px;
}

At some point, my app wants to change the border colour. This is what I have for that:

var borderStyle;
if (gradient) {
  borderStyle = {
    'borderImage': '-webkit-linear-gradient(left, #0083c5 0%, #0083c5 33%, #ec4a26 66%, #ec4a26 100%)',
  };
}

Later, the input component:

<input type="text" style={borderStyle} onChange={this.handleChange} />

Currently what I see is a white border with a tiny image of the red-blue gradient in each corner of the border. I've tried using borderColor, which doesn't work with gradients at all, apparently. Am I missing something obvious, or is it not possible to do a simple border gradient?

The desired result is a left-to-right gradient (so the left border is entirely blue, the right is entirely red, and the top and bottom borders feature the blue-to-red transition).


In response to Harry's answer, I changed to the following code:

if (gradient) {
  borderStyle = {
    borderImage: 'linear-gradient(to right, #0083c5 0%, #0083c5 33%, #ec4a26 66%, #ec4a26 100%)',
    borderImageSlice: 1
  };
}

as specified in the react docs for inline styles. However when I inspect the element, the borderImageSlice property I've defined is missing; only the borderImage one is there, and I still only have tiny gradients in the corners of the border.

Ad

Answer

You need to add a border-image-slice property also while applying the border. Doing this would give the exact output as you need.

I have added it via CSS itself in the below snippet (without the JS) but you should be able to adapt it :)

input[type=text] {
  text-align: center;
  font: inherit;
  border: 6px solid #999999;
  padding: 5px 5px;
  font-size: 15px;
  box-shadow: 0 1px 1px #DDD;
  width: 223px;
  outline: none;
  display: block;
  color: #7B8585;
  margin: 0 auto 20px;
  border-image: linear-gradient(to right, #0083c5 0%, #0083c5 33%, #ec4a26 66%, #ec4a26 100%);
  border-image-slice: 1;
}
<input type="text" />

Note: I have also modified the gradient syntax to use the standard one so that it works in all browsers that support border-image property.


Below is a snippet which applies the border image when the text in the input box is changed.

var ip = document.getElementById("inp");

ip.addEventListener("change", function() {
  this.style.borderImage = 'linear-gradient(to right, #0083c5 0%, #0083c5 33%, #ec4a26 66%, #ec4a26 100%)';
  this.style.borderImageSlice = '1';
});
input[type=text] {
  text-align: center;
  font: inherit;
  border: 6px solid #999999;
  padding: 5px 5px;
  font-size: 15px;
  box-shadow: 0 1px 1px #DDD;
  width: 223px;
  outline: none;
  display: block;
  color: #7B8585;
  margin: 0 auto 20px;
}
<input type="text" id="inp" />


It seems like ReactJS by default adds px as units to all numbers that are passed for inline styles and because of this the border-image-slice: 1 is wrongly getting set as border-image-slice: 1px. As this property is a unitless property in CSS, it is not getting appliedall numbers that are passed for inline styles and because of this the border-image-slice: 1 is wrongly getting set as border-image-slice: 1px. As this property is a unitless property in CSS, it is not getting applied properly. The solution is to wrap this value within quotes and also add a semi-colon within the quotes (like in the below code sample):

var borderStyle = {
    borderImage: 'linear-gradient(to right, #0083c5 0%, #0083c5 33%, #ec4a26 66%, #ec4a26 100%)',
      borderImageSlice: '1;' // note the quotes and the semi-colon.
  };

Big credits for finding out this problem goes to Henrik Andersson.

JSBin Demo with ReactJS

Ad
source: stackoverflow.com
Ad