IronWaffleMan
IronWaffleMan

Reputation: 2702

Making border-image work with gradients

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.

Upvotes: 1

Views: 2430

Answers (2)

Ivan Bondarenko
Ivan Bondarenko

Reputation: 1

I managed to fix such problem by adding 1 / 1 / 0 stretch by myself to the inline-style so it looks like this:

var borderImage = `linear-gradient(to right, #1A80AC 0%, #1A80AC ${position.x / 3}%,
#8798AD ${ position.x / 3 }%, #8798AD 100%) 1 / 1 / 0 stretch`

Upvotes: 0

Harry
Harry

Reputation: 89760

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 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

Upvotes: 5

Related Questions