0

I have a nice little button which uses a lot of fancy CSS to look good.

stupendous

Here's the code behind it (I'm ignoring compatibility issues for now); as you can see, it uses a few selectors for hover and click events.

.button {
    display: inline-block;
    width: 200px;
    height: 200px;
    padding: 15px;
    border-radius: 25px;
    background:linear-gradient(to bottom, hsla(36, 100%, 60%, 1) 5%, hsla(36, 100%, 40%, 1) 100%);
    border:2px solid hsla(36, 100%, 30%, 1);
    box-shadow:inset 0px 2px 2px 0px white;
    position: relative;
    left: 0px;
    top: 0px;
    text-shadow:0px 1px 0px hsla(36, 100%, 30%, 1);
    margin: 25px;
}

.button:hover {
    background:linear-gradient(to bottom, hsla(36, 100%, 65%, 1) 5%, hsla(36, 100%, 45%, 1) 100%);
}

.button:active {
    background:linear-gradient(to bottom, hsla(36, 100%, 40%, 1) 5%, hsla(36, 100%, 60%, 1) 100%);
}

However, to streamline the process in the future when there will be many buttons, I instead wanted to be able to make the button have a custom attribute for colour (buttonColor below) which will be read by some JavaScript, turned into Hue/Saturation/Lightness, and eventually changed for the many different variations. Each button contains at least three colours; two for the gradient and one for the drop shadow and border.

<div class="button" id="testButton"buttonColor="ff8c00">
    <p class="buttonHeader">foo</p>
    <p class="buttonBody">foo2</p>
</div>

Here's what I've got in the JavaScript:

function hexToRgb(hex) {  //converts hexadecimal colors into Red/Green/Blue
    //code omitted for sake of conciseness
    return [r, g, b];
}
function rgbToHsl(r, g, b) { //converts Red/Green/Blue into Hue/Saturation/Lightness
    //ditto
    return [h, s, l]
}

var buttons = document.body.getElementsByClassName('button'); //Gets all elements with button class

for (var i = 0; i < buttons.length; i++) {
    var rgb = hexToRgb(buttons[i].getAttribute("buttoncolor")); //
    var hsl = rgbToHsl(rgb.r, rgb.g, rgb.b)
    //here
}

And right there is where I'm stuck.

I can easily modify the style of the button, but only while it's inactive; There's no way I've found to change how it reacts under the :hover and :active selectors.

2
  • i dont think I fully understand what it is you're trying to do. You want to add a hex color as an attribute to do what exactly? Commented Jan 7, 2015 at 0:58
  • OK i get that you want to convert hex to RGB then to HSL. I don't quite understand this: and eventually changed for the many different variations how do you plan on changing to many variations? or is that the issue? and can you post all of your JS if there is more? Commented Jan 7, 2015 at 1:06

1 Answer 1

1

use data attributes! try something like this:

<div class="button" id="testButton" data-button-color="ff8c00">
    <p class="buttonHeader">foo</p>
    <p class="buttonBody">foo2</p>
</div>

js

function hexToRgb(hex) {
    // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
    var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
    hex = hex.replace(shorthandRegex, function(m, r, g, b) {
        return r + r + g + g + b + b;
    });
 
    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16)
    } : null;
}

function rgbToHsl(r, g, b){
    r /= 255, g /= 255, b /= 255;
    var max = Math.max(r, g, b), min = Math.min(r, g, b);
    var h, s, l = (max + min) / 2;

    if(max == min){
        h = s = 0; // achromatic
    }else{
        var d = max - min;
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
        switch(max){
            case r: h = (g - b) / d + (g < b ? 6 : 0); break;
            case g: h = (b - r) / d + 2; break;
            case b: h = (r - g) / d + 4; break;
        }
        h /= 6;
    }

    return [h, s, l];
}

 


var buttons = document.body.getElementsByClassName('button'); //Gets all elements with button class

for (var i = 0; i < buttons.length; i++) {
    var rgb = hexToRgb(buttons[i].data("button-color")),
        hsl = rgbToHsl(rgb.r, rgb.g, rgb.b),
        rules = [];
    rules[i][0] = hsl;
    
    hsl[2] = 100 - hsl[2]; // make second color
    rules[i][1] = hsl;
    var len = rules.length;
    for(;len--;) {
        buttons[i].style = 
            "background: linear-gradient(to bottom, hsla(36, 100%, "+rules[i][0]+"%, 1) 5%, hsla(36, 100%, "+rules[i][1]+"%, 1) 100%);"; // put rules on el
    }
}

edit

David Walsh has an excellent post on adding rules to stylesheets with js.

let's say you made a rules array

var rules = [...]; // ['float: left', 'cursor: pointer']

or object

var rules = {
    'hover': [...], // rules...
    'active': [...]
};

in your code above. You could then insert them with the following:

var sheet = (function() {
    var style = document.createElement("style");
    style.appendChild(document.createTextNode(""));
    document.head.appendChild(style);
    return style.sheet;
})();

function addCSSRule(sheet, selector, rules, index) {
    if("insertRule" in sheet) {
        sheet.insertRule(selector + "{" + rules + "}", index);
    }
    else if("addRule" in sheet) {
        sheet.addRule(selector, rules, index);
    }
}

// ['float: left', 'cursor: pointer']
addCSSRules(document.styleSheets[0], ".button:hover", rules.join(';'));

or

// { 'hover': ['float: left'], 'active': ['cursor: pointer']};
addCSSRules(document.styleSheets[0], ".button:hover", rules.hover.join(';'));
addCSSRules(document.styleSheets[0], ".button:active", rules.active.join(';'));
Sign up to request clarification or add additional context in comments.

1 Comment

The problem's not that I can't change the style; it's that I can't change the styles of the :hover and :active selectors through Javascript.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.