Reputation: 716
I'm trying to create a Div that can have about 100 different shades depending on the value of a variable which in this case is "votes". The more upvotes the redder the button. The more downvotes the bluer the button.
I can easily make a function like this with 8 classes :
$scope.divColor = function (votes) {
if (votes < 60)
return "blue60";
else if (votes >= 60 && votes <= 69)
return "blue70";
else if (votes >= 70 && votes <= 79)
return "blue80";
else if (votes >= 80 && votes <= 89)
return "blue90";
else if (votes >= 90 && votes <= 99)
return "red100";
else if (votes >= 100 && votes <= 109)
return "red110";
else if (votes >= 110 && votes <= 119)
return "red120";
else if (votes >= 120)
return "red130";
}
But is there anyway to have a variable somewhere that uses the votes value to set the actual background-color rather than the class?
Upvotes: 4
Views: 2057
Reputation: 8457
Set a 1000% gradient background from red to blue then when the vote is updated, simply change its position on javascript: document.getElementById("element").style.backgroundPosition = "0% 50%";
. Where min(red): 0% 0%
middle(purple): 0% 50%
max(blue): 0% 100%
UPDATE: As you see below on the comments, use "100000%" instead of "1000%" to avoid any gradient shade of being noticed.
function test(){
var votes = document.getElementById("test").value;
document.getElementById("testobj").style.backgroundPosition = "0% " + votes + "%";
}
.square {
width:100px;
height:100px;
background: linear-gradient(0deg, skyblue, tomato);
background-size: 100000% 100000%;
float:left;
line-height: 100px;
text-align: center;
outline: 2px solid black;
}
input {
margin-left: 5px;
width: 100px;
display: inline-block;
vertical-align: middle;
}
.A {
background-position:0% 0%;
}
.B {
background-position:0% 50%;
}
.C {
background-position:0% 100%;
}
.D {
width:100px;
height:100px;
background: linear-gradient(0deg, skyblue, tomato);
background-size: 100000% 100000%;
display: inline-block;
line-height: 100px;
text-align: center;
outline: 2px solid black;
}
<div class="square A">0%</div>
<div class="square B">50%</div>
<div class="square C">100%</div>
<input id=test type="range" name="votes" min="0" max="100" oninput="test()">
<div id=testobj class="D">Slider test</div>
Upvotes: 7
Reputation: 47081
You can't do everything you want to do in just CSS, but there several different ways to achieve the desired effect that involve both CSS and another language.
Instead of changing the class of an element, you can directly change its styling, as suggested by Andrew Willems's answer :
var votes = 0;
function shadeColor() {
var numLvls = 25;
var maxVotes = 200;
var redVal = parseInt(parseInt(Math.min(votes, maxVotes) / maxVotes * (numLvls - 1)) / (numLvls - 1) * 255);
var bluVal = 255 - redVal;
color = "rgb(" + redVal + ", 0, " + bluVal + ")";
return color;
}
function updateVotecount() {
document.getElementById("voteCount").value = votes;
}
function vote() {
votes = votes + 10;
updateVotecount();
document.getElementById("myShade").style.backgroundColor = shadeColor();
}
document.getElementById("myShade").style.backgroundColor = shadeColor();
document.getElementById("update").addEventListener("click", vote);
#myShade, input {
color : #FFF;
disabled: true;
background: transparent;
border : none;
}
<div id="myShade">
Number of votes = <input id="voteCount" value="0">
</div>
<button id="update">Vote</button>
This option works in every browser, but it's still a pure JS option.
(see also this Fiddle)
Another option to consider would be the use of a CSS preprocessor language like Less or Sass, which adds not only variables but also mixins, functions and a whole bunch of other interesting stuff.
In Sass, you could do something like this :
$votes : 20;
@function shade-color($votes) {
$numLvls : 25;
$maxVotes : 200;
$redVal : round(round(min($votes, $maxVotes) / $maxVotes * ($numLvls - 1)) / ($numLvls - 1) * 255);
$bluVal : 255 - $redVal;
@return unquote("rgb(" + $redVal + ", 0, " + $bluVal + ")");
}
.shade {
color: shade-color($votes);
}
This Sass code would produce the following CSS :
.shade {
color: rgb(21, 0, 234);
}
Unfortunately, this adds another scripting language to your stack, which might unnecessarily complicate matters. Also, pre-processor languages aren't ideal when the values of your variables are updated often, as they need to be compiled into CSS before they can be used in a browser.
The latest CSS specs do allow variables, which are accessible from JavaScript.
That means you could do something like this :
var votes = 0;
function shadeColor() {
var numLvls = 25;
var maxVotes = 200;
var redVal = parseInt(parseInt(Math.min(votes, maxVotes) / maxVotes * (numLvls - 1)) / (numLvls - 1) * 255);
var bluVal = 255 - redVal;
color = "rgb(" + redVal + ", 0, " + bluVal + ")";
return color;
}
function updateVotecount() {
document.getElementById("voteCount").value = votes;
}
function vote() {
votes = votes + 10;
updateVotecount();
document.body.style.setProperty('--shade-color', shadeColor(votes));
}
document.body.style.setProperty('--shade-color', shadeColor(votes));
document.getElementById("update").addEventListener("click", vote);
body {
--shade-color : #000;
}
#myShade, input {
color : #FFF;
disabled: true;
background: transparent;
border : none;
}
#myShade {
background : var(--shade-color);
}
<div id="myShade">
Number of votes = <input id="voteCount" value="0">
</div>
<button id="update">Vote</button>
(see also this Fiddle)
Unfortunately, it's currently only supported by the following browsers :
Pretty much every other browser (including Chrome 48, IE11 & Edge 14) do not support this feature, which means that you can't use it in production code yet.
Upvotes: 1
Reputation: 12458
Here is a solution that provides a color from a blue-to-red spectrum that is divided into a particular number of discrete colors (numLvls
). This requires setting a vote count for the "highest" color, i.e. red (maxVotes
).
var redVal = parseInt(parseInt(Math.min(votes, maxVotes) / maxVotes * (numLvls - 1)) / (numLvls - 1) * 255);
var bluVal = 255 - redVal;
Put together the two, i.e. "rgb(" + redVal + ", 0, " + bluVal + ")"
to get the CSS-friendly color string.
See the code snippet below for a demo. The example uses 5 color levels, not the 100 from your question, just for simplicity, but any value can be used.
var votes = 0;
var maxVotes = 13;
var numLvls = 5;
var color = "rgb(0, 0, 255)";
report();
$("button").click(function(evt) {
if (evt.target.id === "up") votes += 1;
else votes -= 1;
if (votes < 0) votes = 0;
var redVal = parseInt(parseInt(Math.min(votes, maxVotes) / maxVotes * (numLvls - 1)) / (numLvls - 1) * 255);
var bluVal = 255 - redVal;
color = "rgb(" + redVal + ", 0, " + bluVal + ")";
report();
});
function report() {
$("#votes").html("votes: " + votes + "<br/>color: " + color);
$("#msg").css("background-color", color);
$("#maxVotes").text("votes required for full red color: " + maxVotes);
$("#numLvls").text("number of distinct color levels: " + numLvls);
}
#msg {
color: white;
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="up">UP</button>
<button id="dn">DOWN</button>
<div id="msg"> Something to be colored based on vote count</div>
<div id="votes"></div>
<div id="maxVotes"></div>
<div id="numLvls"></div>
Upvotes: 1
Reputation: 9439
Yes, by targeting the value like this in your css input[value="1"]{}
see fiddle: https://jsfiddle.net/vctbszc2/4/
html
<input type="button" value="1"><br>
<input type="button" value="2"><br>
<input type="button" value="3"><br>
<input type="button" value="4"><br>
css
input[value="1"]{
background-color: blue;
}
input[value="2"]{
background-color: red;
}
input[value="3"]{
background-color: green;
}
input[value="4"]{
background-color: yellow;
}
So after reading Pulie's comments below, the closest you can get is something like this: http://jsfiddle.net/6DAwY/952/
This will give you a range for 8 conditions. by using input[value^="1"]
you are looking for a value that with the number 1, so 10,11,12.... then when you hit 20 it will use this css input[value^="2"]
and so on.
html
<input value="0">
<input value="11">
<input value="23">
<input value="35">
<input value="42">
<input value="53">
<input value="65">
<input value="72">
<input value="86">
CSS
[value^="0"] {
background-color: purple;
}
input[value^="1"] {
background-color: red;
}
input[value^="2"] {
background-color: green;
}
input[value^="3"] {
background-color: yellow;
}
input[value^="4"] {
background-color: blue;
}
input[value^="5"] {
background-color: orange;
}
input[value^="6"] {
background-color: grey;
}
input[value^="7"] {
background-color: lightblue;
}
input[value^="8"] {
background-color: lightgreen;
}
Upvotes: 3
Reputation: 3926
What you can do is setting a data attribute with a value with jQuery. And then you can use the value of the attribute in your css. It's very dynamic, so you don't need to write for each value style separately.
div { background-color: attr(data-color) }
Upvotes: 0