Making border-image work with gradients - javascript

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.

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

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`

Related

mix blending mode not working on white image

I am trying to apply this code find online to change the image color according to the user selection. here is the code I find https://codepen.io/smashtheshell/pen/wvzwMLO
using img and mix blend mode apply the color on image like by the user
:root {
box-sizing: border-box;
}
*,
*::after,
*::before {
box-sizing: inherit;
margin: 0;
padding: 0;
}
.product img {
max-width: 100%;
min-width: 20rem;
}
.container {
display: grid;
place-items: center;
height: 100vh;
width: 100vw;
padding: 0 2.5rem;
background-color: hsl(30, 50%, 75%);
}
.product::after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: hsl(30, 50%, 75%);
/* opacity: 0.5; */
mix-blend-mode: hue;
}
.product-nav {
position: relative;
}
.product-nav label {
display: inline-block;
width: 5vmin;
height: 5vmin;
background-color: hsl(30, 50%, 75%);
border-radius: 50%;
cursor: pointer;
box-shadow: 0 0 0 0.5em #fff, 0.5em 0.5em 1em -0.15em rgba(0, 0, 0, 0.25);
transition: 200ms all ease-in-out;
}
.product-nav label + label {
margin-left: 2.5em;
}
.product-nav label:nth-of-type(1),
#color-1:checked ~ .product::after {
background-color: hsl(30, 50%, 75%);
}
.product-nav label:nth-of-type(2),
#color-2:checked ~ .product::after {
background-color: hsl(120, 50%, 75%);
}
.product-nav label:nth-of-type(3),
#color-3:checked ~ .product::after {
background-color: hsl(210, 50%, 75%);
}
.product-nav label:nth-of-type(4),
#color-4:checked ~ .product::after {
background-color: hsl(300, 50%, 75%);
}
#color-1:checked ~ .product-nav > label:nth-of-type(1),
#color-2:checked ~ .product-nav > label:nth-of-type(2),
#color-3:checked ~ .product-nav > label:nth-of-type(3),
#color-4:checked ~ .product-nav > label:nth-of-type(4) {
transform: scale(1.3);
}
#color-1:checked ~ .product-nav > label:nth-of-type(1) {
background-color: hsl(30, 70%, 45%);
}
#color-2:checked ~ .product-nav > label:nth-of-type(2) {
background-color: hsl(120, 70%, 45%);
}
#color-3:checked ~ .product-nav > label:nth-of-type(3) {
background-color: hsl(210, 70%, 45%);
}
#color-4:checked ~ .product-nav > label:nth-of-type(4) {
background-color: hsl(300, 70%, 45%);
}
<section class="container">
<input type="radio" name="color" id="color-1" checked hidden>
<input type="radio" name="color" id="color-2" hidden>
<input type="radio" name="color" id="color-3" hidden>
<input type="radio" name="color" id="color-4" hidden>
<div class="product">
<img src="http://pngimg.com/uploads/vans/vans_PNG24.png" alt="Product">
</div>
<div class="product-nav">
<label for="color-1"></label>
<label for="color-2"></label>
<label for="color-3"></label>
<label for="color-4"></label>
</div>
</section>
But when try to apply on image with white color it is not working. any solution?
In case you haven't figured this out yourself by now:
Changing the hue (the 'color tone' in color wheel degrees) of a color does not change its saturation nor its lightness. Any grayscale image has pixels with saturation: 0%, so after a hue change you are still left with a grayscale image. This is true for any shade of gray between black and white (the lightness parameter). Despite the fact that you are mixing it with a saturated color, only the hue of that color is transfered.
The quick solution is using mix-blend-mode: color-burn, but this has the side effect that colors will get deeper contrast, whcih will need to be corrected. Probably different contrast values per color transfered.
To add insult to injury, the following can be very confusing at first:
linear colors: when using the CSS hsl(..) function for a color, only changing the hue will yield that specific color tone from the color wheel. E.g. hsl(0, 100%, 50%), HTML 'red', changed to its complementary color hsl(180, 100%, 50%) yields HTML 'cyan'. We programmers like that, 0 + 180 = 180 = 'cyan'. Straightforward logic, however...
perceptive colors mix-blend-mode and filter: hue-rotate(..) use internal (internationally accepted) color conversion tables to create colors that change the color tone, but also the 'feeling' of a color. E.g. the complementary color of above 'red' becomes a 'darker green', which has a saturation and lightness that 'feel' the same as those of 'red'. For me as a programmer it means 1 + 1 = 2, but it feels like 1. Which just does not compute... (don't try to figure out the mathematical logic, browser literally use hardcoded arrays for the perceptive color conversion).
So, if you think you are blending a 'red' toned image with 'cyan', don't be surprised when it turns out to be 'some shade of green'.
When you feel really confident: Mozilla source: gfx/src/FilterSupport.cpp, check the various filter matrix functions. Used by SVG filters, blend-mode and filter...

Enforce key size on virtual keyboard

This is the layout I am trying to achieve: https://jsfiddle.net/h0oa3Lps/ All keys are the same size.
In my application I have this code. The js is at the bottom of my jade file:
$('.keyboard')
.keyboard({
layout: 'custom',
customLayout: {
'default' : [
'1 2 3 {c}',
'4 5 6 {b}',
'7 8 9 {dec}',
'{left} {right} 0 {a}'
]
},
maxLength : 6,
restrictInput : true,
useCombos : false,
acceptValid : true,
validate : function(keyboard, value, isClosing){
// only make valid if input is between 0 and 100 inclusive
return value >= 0.0 && value <= 100.0;
}
})
.addTyping();
When using css/keyboard.min.css, the left arrow, right arrow and backspace keys are slightly larger than the other keys. Also the text positioning is off. Image:
If I switch to css/keyboard-basic.min.css the arrow keys are the same size as regular keys but the esc, backspace, and accept keys are twice the size as the regular keys. Also this takes up half of the screen (since it's not using the jquery-ui positioning). Image:
How do I enforce uniform key size?
If it makes any difference I am using Node, Express and Foundation v5.5.3 plus I have just updated to the latest versions of jQuery, jQuery-ui and jQuery.keyboard.
To fix this issue I copied the unminified css of keyboard.css to a keyboard-butchered.css. I then started experimenting with the styles in keyboard-basic.css and eventually came up with the following that partially answered my question:
.ui-keyboard {
/* adjust overall keyboard size using "font-size" */
font-size: 28px; /* increase button size for small screen */
text-align: center;
background: #fefefe;
border: 1px solid #aaa;
padding: 4px;
/* include the following setting to place the
keyboard at the bottom of the browser window */
left: 0px;
top: auto;
/*position: fixed;*/
position: absolute;
white-space: nowrap;
overflow-x: auto;
/* see issue #484 */
-ms-touch-action: manipulation;
touch-action: manipulation;
}
I then mixed in the style for the keyboard button. This gives the correct style as seen in the jsfiddle demo (but jumbo sized).
.ui-keyboard-button {
border: 1px solid #aaa;
padding: 0 0.5em;
margin: 1px;
min-width: 3em;
height: 3em;
line-height: 3em;
vertical-align: top;
font-family: Helvetica, Arial, sans-serif;
color: #333;
text-align: center;
border-radius: 5px;
-webkit-box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.5);
background: white;
background-image: -webkit-linear-gradient(-90deg, white 0%, #e3e3e3 100%);
background-image: linear-gradient(-90deg, white 0%, #e3e3e3 100%);
cursor: pointer;
overflow: hidden;
-moz-user-focus: ignore;
}

transition in javascript doesnt start

I have the strangest issue i have ever seen - hope you can help me guys.
I am making rainbow text transition in my chrome packaged app. You can see it
// script2.js
var box = document.getElementById('kalreg');
box.addEventListener('transitionend', loopTransition, false )
function loopTransition(e) {
if ( e.propertyName == 'color' ) {
console.log('aa');
if (box.className == "it-animate") {
console.log('bb');
$(box).removeClass("it-animate")
} else {
box.className = "it-animate";
console.log('cc');
}
}
}
box.className = ''
.it-wrapper{
padding: 30px;
text-align: center;
max-width: 1140px;
}
.it-wrapper h3{
font-size: 130px;
line-height: 150px;
padding: 30px 30px 40px;
color: rgba(255,255,255,0.1);
font-family: 'guanine', 'Arial Narrow', Arial, sans-serif;
text-shadow: 1px 1px 1px rgba(255,255,255,0.3);
background: -webkit-linear-gradient(left, rgba(105,94,127,0.54) 0%,
rgba(255,92,92,0.57) 15%,
rgba(255,160,17,0.59) 27%,
rgba(252,236,93,0.61) 37%,
rgba(255,229,145,0.63) 46%,
rgba(111,196,173,0.65) 58%,
rgba(106,132,186,0.67) 69%,
rgba(209,119,195,0.69) 79%,
rgba(216,213,125,0.7) 89%,
rgba(216,213,125,0.72) 100%),
-webkit-repeating-linear-gradient(-45deg, rgba(255,255,255,0.9), transparent 20px, rgba(255,255,255,0.3) 40px);
background-size: 300% 100%;
background-position: center left, top left;
-webkit-background-clip: text;
-moz-background-clip: text;
background-clip: text;
transition: all 2s ease;
-moz-border-radius: 90px 15px;
-moz-box-shadow: 0px 0px 0px 10px rgba(255,255,255,0.4);
}
.it-wrapper h3.it-animate{
background-position: center right, top right;
color: rgba(255,137,149,0.7);
-moz-box-shadow: 0px 0px 0px 10px rgba(39,137,149, 0.9);
}
input {
width: 100%;
}
#font-face {
font-family: guanine;
src: local(guanine), url('fonts/guanine_.ttf') format('opentype');
}
<div class="it-wrapper">
<h3 class="it-animate" id="kalreg">text</h3>
</div>
working in jsfiddle here:
fiddle
If you press "run" rainbow would move. And here goes the strangest part. On my computer this animation doesnt start although files look identically except one small difference - i include script2.js (commented in html file in fiddle) instead of raw javascript in html file. But there is a way to start animation on ma computer. All I need to do is instead of last line in javascript that looks like this:
box.className = ''
put something like this:
setTimeout(function () { box.className = ''}, 0)
I have no idea what is going on here, especially everything worked fine yesterday. Any ideas ? I am sitting with this all evening and cant find any reason why it behaves like that.
Kalreg

Remove Div On Click With Timeout

I have this javascript on click to remove div on click, but it doesnt work at all :(
Can you please help me ? I would be so happy (I already tried to search over the other questions)
There is JS
onclick="setTimeout('$('#wait').remove()', 11000);"
Wrong syntax and quotes usage.
This:
onclick = "setTimeout(function() { $('#wait').remove() }, 11000);";
would be correct.
Note the nested single quotes in your handler. That won't end well. What's the browser supposed to do with this?
'$('#wait').remove()'
You really want to define a function and use that instead. You avoid all of the pitfalls of passing a string to setTimeout(), multi-level quoting, etc.
function hideit() {
$('#wait').remove();
}
// ...
<button onclick="setTimeout(hideit, 11000);">click me</button>
I think pretty much all of these solutions would work. Here is another perhaps more elegant version of what you are doing up there, Chymmi.
JsFiddle Demo: https://jsfiddle.net/kvvbbz6e/4/
Javascript
$(document).ready(function(){
//--------------------------------------------------------------
// this is what you would need
var waitButton = $('#wait'),
waitButtonTimer;
waitButton.on('click',function(){ // clicking this a second time will reset the timer.
clearInterval(waitButtonTimer);
waitButtonTimer = setTimeout(function(){
waitButton.off('click');
$('.infolabel').text('click event unbound');
}, 4000);
});
//--------------------------------------------------------------
});
HTML
<div id="wait" class="button">Wait Button</div>
<span class="infolabel">Click event bound</span>
CSS
.button {
display: inline-block;
color: #666;
height: 24px;
font-size: 9.5pt;
font-weight: bold;
line-height: 22px;
border: 0;
padding: 0 5px;
margin: 0;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 4px;
background: rgb(255,255,255); /* Old browsers */
background: -moz-linear-gradient(top, rgba(255,255,255,1) 60%, rgba(245,245,245,1) 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(60%,rgba(255,255,255,1)), color-stop(100%,rgba(245,245,245,1))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, rgba(255,255,255,1) 60%,rgba(245,245,245,1) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, rgba(255,255,255,1) 60%,rgba(245,245,245,1) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, rgba(255,255,255,1) 60%,rgba(245,245,245,1) 100%); /* IE10+ */
background: linear-gradient(to bottom, rgba(255,255,255,1) 60%,rgba(245,245,245,1) 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#f5f5f5',GradientType=0 ); /* IE6-9 */
box-shadow: 0px 1px 1px #fff;
cursor: pointer;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
Rather than have some javascript inline in an onclick you should use .delay and .queue from jQuery.
$('#clickme').on('click', function(){
$('#wait').delay(11000).queue(function(){
$(this).remove().dequeue()
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wait">Gone in 11 Seconds</div>
<button id="clickme">Click me to start the countdown</button>

weird bug with ranges over canvases

This jsfiddle:http://jsfiddle.net/SDR2W/3/
Anyway, the sliders have a system so the top shade will never be darker than the bottom. But when you drag any of the ranges upward, at a value of 10, the sliders act weird, and i don't understand why. (the ranges are hidden on the side of the canvases) wondrin if any of you see the problem?
Thanks
<input type="range" class="vs1 vs" min="0" max="45" style="left:-89px;top:-12px" id="vs1" />
<input type="range" class="vs2 vs" min="0" max="45" style="right:-89px;top:-12px" id="vs2" />
<style>
input {
font-weight:bold;
font-family:arial;
outline:none;
}
input[type=range].vs {
-webkit-appearance: none;
background: none;
width: 200px;
height:28px;
-webkit-transform:rotate(90deg);
margin-top: 97px;
z-index: 10;
position: absolute;
border:1px solid rgba(0, 0, 0, 0);
opacity:0.4;
transition-duration: 1s;
}
input[type="range"].vs1::-webkit-slider-thumb {
-webkit-appearance: none;
background-color: black;
width: 5px;
height: 15px;
border-top-right-radius:2em;
border-top-left-radius:2em;
position: relative;
top: 6px;
}
input[type="range"].vs2::-webkit-slider-thumb {
-webkit-appearance: none;
background-color: black;
width: 5px;
height: 15px;
border-bottom-right-radius:2em;
border-bottom-left-radius:2em;
position: relative;
bottom: 7px;
}
input[type=range]:hover.vs {
background: -webkit-gradient(linear, left top, right top, color-stop(100%, #ffcb93), color-stop(73%, #ffd8af), color-stop(0%, #ffffff));
border:1px solid black;
opacity:1;
}
input[type=range]:active.vs {
background: -webkit-gradient(linear, left top, right top, color-stop(100%, #ffcb93), color-stop(73%, #ffd8af), color-stop(0%, #ffffff));
border:1px solid black;
opacity:1;
}
</style>
You had this tagged as jQuery, so I have reduced & simplified it by somewhat actually using jQuery:
if (~~$('#vs1').val() > ~~$('#vs2').val()) {
if (qwas == 1) $('#vs2').val($('#vs1').val())
if (qwas == 2) $('#vs1').val($('#vs2').val())
}
jSFiddle: http://jsfiddle.net/TrueBlueAussie/ZYX8Y/3/
Note: ~~ converts a value to an integer (including strings). Much simpler & faster than parseInt()
Another note: At first I managed to easily break your code as there are no braces on the nested ifs... really bad practice for code maintenance.
You shouldn't compare strings directly. The value property gives you strings.
So "1" and "10" don't compare as you think.
To solve your problem use:
parseInt(obj.value, 10)
where obj is the DOM element you get with document.getElementById().
Use this everywhere, in the if() and in the get and set of your assignments.

Categories

Resources