CSS Color-Range Conditional Styling

I am interested in creating a simple chart using divs and spans, with the goal of implementing conditional formatting on each column based on its value to determine height. I have been struggling with figuring out how to make it work similar to Excel's conditional formatting feature as shown in this example:

https://i.sstatic.net/LZ5SW.png

In the example, colors are organized within a range from light to dark. Is there an uncomplicated way to achieve this effect? While I can assign static values to static colors, I was hoping to find a solution that allows for color ranges like what is seen in the Excel demonstration.

For instance, the screenshot below displays a column chart where each column is a different shade of orange depending on the column's value:

https://i.sstatic.net/kfUJI.png

The closer the column is to 25, the darker the color becomes. Conversely, lower values result in lighter shades of orange.

Answer №1

Are you aiming to create a color gradient effect for a bar that transitions between two colors based on a value? If so, you can achieve this using CSS animations.

Here's the concept:

  • Create an animation that transitions the background between the two colors. By utilizing @keyframes and animation, you can simulate the gradient effect.
  • Pause the animation initially to prevent it from playing automatically. Use the property animation-play-state for this purpose.
  • Determine the in-between color at a specific point in the animation by setting a negative animation-delay.

.bars {
  display: flex;
  justify-content: space-evenly;
}

.bar {
  animation: color-gradient 25s linear 1;
  animation-fill-mode: forwards;
  animation-play-state: paused;
  width: 3em;
}

@keyframes color-gradient {
  from { background: red; }
  to   { background: blue; }
}
<div class="bars">
  <div class="bar" style="height: 5em; animation-delay: -5s;"></div>
  <div class="bar" style="height: 10em; animation-delay: -10s;"></div>
  <div class="bar" style="height: 15em; animation-delay: -15s;"></div>
  <div class="bar" style="height: 20em; animation-delay: -20s;"></div>
  <div class="bar" style="height: 25em; animation-delay: -25s;"></div>
</div>

If necessary, adjust the granularity by extending the animation duration beyond 25 seconds.

Answer №2

Presenting two alternatives for consideration, with the opportunity to provide additional specifics based on these options.

The first option may not align with your requirements as it establishes a defined gradient based on a specific height. Access the Codepen link provided for this option: https://codepen.io/jfirestorm44/pen/yLMNPPM?editors=1100

The second alternative seems more suitable for your needs. You can determine the gradient breaks for your linear-gradient based on the maximum height of the bar graph.

UPDATED: HTML

<div id="container">
  <div id="first" class="bar"></div>
  <div id="second" class="bar"></div>
  <div id="third" class="bar"></div>
  <div id="fourth" class="bar"></div>
  <div id="fifth" class="bar"></div>
</div>

SCSS

.bar {
  @for $i from 1 through 5 {
    $height: 20px * $i;
    $light: 75% + $i * -5;
    &:nth-child(#{$i}) {
      position: absolute;
      bottom: 50%;
      left: 20% + ($i * 10%);
      width: 20px;
      height: $height;
      font-size: 25px;
      transform: translate(-80%, 0);
      background: hsl(35, 100%, $light);
    }
  }
}

Updated Codepen: https://codepen.io/jfirestorm44/pen/jOBPopj?editors=1100

Introducing a JavaScript Option:

let inputNum = document.getElementById("number");
let button1 = document.getElementById("button1");
let border = document.getElementById("border");
let dropDown = document.getElementById("cars");
function color() {
  if (inputNum.value > 0) {
    let bar = document.createElement("div");
    bar.classList.add("bar");
    border.appendChild(bar);
    let bars = document.getElementsByClassName("bar");

    let carName = document.createElement("p");
    carName.classList.add("carType");
    carName.textContent = cars.options[cars.selectedIndex].text;
    border.appendChild(carName);
    let names = document.getElementsByClassName("carType");

    let height = inputNum.value * 26;
    for (let i = 0; i < bars.length; i++) {
      names[names.length - 1].style.top = "275px";
      names[names.length - 1].style.left = -5 + i * 30 + "px";
      bars[bars.length - 1].style.height = height + "px";
      bars[bars.length - 1].style.backgroundColor =
        "hsl(35, 100%," + (75 - height / 5.2) + "%)";
      bars[bars.length - 1].style.left = 10 + i * 30 + "px";
    }
  }
}
#container {
  position: absolute;
  top: 40px;
  left: 0;
  width: 400px;
  height: 300px;
}
#border {
  position: relative;
  left: 100%;
  top: 0;
  width: 90%;
  height: 90%;
  border-left: 2px solid grey;
  border-bottom: 2px solid grey;
  transform: translate(-100%, 0);
}
#numberContainer {
  position: relative;
  left: -5%;
}
.num {
  line-height: 10px;
}
.num:before {
  content: "";
  position: absolute;
  left: 18px;
  width: 100%;
  height: 10px;
  border-bottom: 1px lightgrey solid;
}
.bar {
  position: absolute;
  bottom: 0;
  width: 20px;
}
#button1 {
  position: relative;
  top: 0;
  width: 60px;
  height: 20px;
}
.car {
  position: absolute;
  top: 10px;
}
.carType {
  position: absolute;
  bottom: -85px;
  writing-mode: vertical-rl;
  text-orientation: upright;
}
<div id="container">
  <div id="border">
    <div id="numberContainer">
      <p class="num">10</p>
      <p class="num">9</p>
      <p class="num">8</p>
      <p class="num">7</p>
      <p class="num">6</p>
      <p class="num">5</p>
      <p class="num">4</p>
      <p class="num">3</p>
      <p class="num">2</p>
      <p class="num">1</p>
      <p class="num">0</p>
    </div>

  </div>
</div>
<input type="number" min="0" max="10" value="0" id="number"/>
<label for="cars">Choose a car:</label>

<select name="cars" id="cars">
  <option value="volvo">Volvo</option>
  <option value="saab">Saab</option>
  <option value="mercedes">Mercedes</option>
  <option value="audi">Audi</option>
</select>
<button type="button" onclick="color()" id="button1">Submit</button>

Answer №3

Although this question may be older, it is now achievable with the help of CSS variables and the color-mix property:

let rectangles = document.querySelectorAll('.rectangle');

let increment = 0;
for (const rectangle of rectangles) {
  rectangle.style.setProperty('--value', `${increment += 2}`);
}
.panel {
  --minimum: 0;
  --maximum: 10;
  --increments: oklch;
  --value: 0.5;
  --higher-color: #843c0c;
  --lower-color: #fbe5d6;
  display: inline-flex;
  align-items: flex-end;
  background-color: #fff;
  padding: 1rem;
  gap: 3rem;
  border: 1px solid grey;
}

.rectangle {
  --normalized: calc(100% * (var(--value) - var(--minimum))/(var(--maximum) - var(--minimum)));
  background-color: color-mix(
    in var(--increments),
    var(--higher-color) var(--normalized),
    var(--lower-color)
  );
  width: 1.5rem;
  height: calc(1rem * var(--value));
}
<div class="panel">
  <div class="rectangle"></div>
  <div class="rectangle"></div>
  <div class="rectangle"></div>
  <div class="rectangle"></div>
  <div class="rectangle"></div>
</div>

You can even implement a three-color gradient, as discussed in this related question:

Is there a way to interpolate the colour of an element using css, based on a value?

Answer №4

[edit] This answer specifically focuses on styling the bars with a gradient effect from left to right, starting with the lightest color on the left side.

To achieve this effect, I suggest setting the container background to white and styling the bars in black. Then, you can apply a gradient over everything using a pseudo-element that has the property mixed-blend-mode: lighten to only affect the color of the black bars.

In addition, you can enhance the design by adding another pseudo-element with a repeating linear gradient in a very light grey shade to create horizontal lines. By applying mixed-blend-mode: darken to this element, it will give the appearance of the lines being beneath the bars.

To add variation to the height of the bars, you can randomize a CSS property for each bar. This not only adds visual interest but also ensures scalability regardless of the number of bars present without needing any changes to the CSS code.

let bars = document.querySelectorAll('.bar');

function randomize(max, min) {
  min = min || 0;
  
  return Math.floor(Math.random() * (max - min) + min);
}

for (const bar of bars) {
  bar.style.setProperty('--bar-height', `${randomize(10, 2)}rem`);
}
.container {
  position: relative;
  display: inline-flex;
  margin-left: 4.5rem;
  align-items: flex-end;
  background-color: #fff;
  padding: 0px 1rem;
}

.container::before,
.container::after {
  content: '';
  position: absolute;
  top: 0px;
  bottom: 0px;
  left: 0px;
  right: 0px;
}

.container::before {
  background: linear-gradient(to right, #fbe5d6, #843c0c);
  mix-blend-mode: lighten;
}

.container::after {
  background: repeating-linear-gradient(to top, #f4f1f1, #f4f1f1 1px, transparent 1px, transparent 1rem);
  z-index: 10;
  mix-blend-mode: darken;
}

.bar {
  width: 1.5rem;
  height: var(--bar-height);
  background-color: #000;
}

.bar + .bar {
  margin-left: 3rem;
}
<div class="container">
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
</div>

Answer №5

Using a blend of my and Justin's responses, but tailored for pure CSS.

This solution incorporates HSL and CSS variables to define the color and height.

Randomized Data

let bars = document.querySelectorAll('.bar');

function randomize(max, min) {
  min = min || 0;
  
  return Math.floor(Math.random() * (max - min) + min);
}

for (const bar of bars) {
  let maxValue = 25;
  let randomValue = randomize(maxValue, 2);
  let height = randomValue/2;
  
  let hue = '24deg';
  let saturation = '82%';
  let maxHue = 90;
  let minHue = 30;
  let hueRange = maxHue - minHue;
  let lightness = `${maxHue - hueRange * (randomValue/maxValue)}%`;
  
  bar.style.setProperty('--bar-height', `${height}rem`);
  bar.style.setProperty('--color-background-bar', `hsl(${hue}, ${saturation}, ${lightness})`);
}
.container {
  display: inline-flex;
  margin-left: 4.5rem;
  align-items: flex-end;
  padding: 0px 1rem;

  background: repeating-linear-gradient(to top, #eee, #eee 1px, transparent 1px, transparent 1rem);
}

.bar {
  width: 1.5rem;
  height: var(--bar-height);
  background-color: var(--color-background-bar);
}

.bar + .bar {
  margin-left: 3rem;
}
<div class="container">
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
</div>

Escalating Values

Fixed values ranging from 5 to 25, mirroring the diagram posted by the author.

let bars = document.querySelectorAll('.bar');

bars.forEach((bar, index) => {
  let maxValue = 25;
  let customValue = 5 + index * 5;
  let height = customValue/2;
  
  let hue = '24deg';
  let saturation = '82%';
  let maxHue = 90;
  let minHue = 30;
  let hueRange = maxHue - minHue;
  let lightness = `${maxHue - hueRange * (customValue/maxValue)}%`;

  bar.style.setProperty('--bar-height', `${height}rem`);
  bar.style.setProperty('--color-background-bar', `hsl(${hue}, ${saturation}, ${lightness})`);
});
.container {
  display: inline-flex;
  margin-left: 4.5rem;
  align-items: flex-end;
  padding: 0px 1rem;

  background: repeating-linear-gradient(to top, #eee, #eee 1px, transparent 1px, transparent 1rem);
}

.bar {
  width: 1.5rem;
  height: var(--bar-height);
  background-color: var(--color-background-bar);
}

.bar + .bar {
  margin-left: 3rem;
}
<div class="container">
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
  <div class="bar"></div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Arranging components in a horizontal layout on Jquery mobile

I'm completely new to Jquery mobile and I'm having trouble getting these elements aligned. Here's my code, but I need the two icons to line up horizontally with the caption "Heading". <h3>Heading</h3> <img src="../re ...

Looking for a straightforward way to incorporate a "Read more" and "Show Less" functionality into a Wordpress site using Javascript?

As a last resort, I am seeking a quick and simple fix. I have been experimenting with Javascript to implement a 'Read more...' & '... Read Less' feature on six different sections of a single page. The goal is to display only the fi ...

What's causing ng-show to malfunction in IE11 on AngularJS?

I am experiencing a strange issue with my code - ng-show works perfectly fine on Firefox, but not on IE 11. <div ng-show="isExist" class="panel panel-default"> Here is the relevant code snippet from the controller: $scope.isExist = false; if(user ...

Retrieve HTML classes within JavaScript textual templates

<!-- TEMPLATE UPLOAD --> <script id="template-upload" type="text/x-tmpl"> {% for (var i=0, file; file=o.files[i]; i++) { %} <tr class="template-upload fade"> <td class="name"><span>{%=file.name%}</span></td> <td ...

What is the best way to ensure HTML validation during a pull request?

Are there any tools available to validate all specified files in a pull request? I have previously used Travis CI for testing and am now searching for a similar plugin focused on validation rather than tests, such as W3C validation. ...

Utilizing a dynamic URL to set the background image of a div element (with the help of

Currently, I am in the process of designing a user registration page that allows users to input an image URL and view a preview of the image within a designated div. The div already contains a default image set by a specific class. The HTML code for displa ...

Designing a straightforward thumbs-up icon

Hey there! I'm currently working on a blog application and trying to set up a simple like button for each post identified by its primary key (pk). However, I encountered an error along the way. The error message I received is "NoReverseMatch at /sing ...

How to eliminate the vertical scroll indicators in Material UI's TextField

I'm currently working on customizing the styling of a Material UI textfield and I need to remove the top-down arrows. Below is the code snippet I have so far: const theme = createMuiTheme({ MuiInput: { root: { "&::-webkit-outer-spin-bu ...

Are there any JavaScript functions available that can navigate to a different HTML page?

Here is an example of the functionality I am attempting. Can it be implemented? function CloseHTML(){ ApplyCSSClosingTransition(); setTimeout(function() { RedirectToAnotherPage(); }, 2000); } <div onClick='CloseHTML()'&g ...

I wonder where this unique design originated from on my webpage?

This is a screenshot of Chrome Developer Tools that shows the styling information. Usually, the style is clearly defined in a specific CSS file (like in this screenshot, datepicker.css). I am attempting to modify the styling at the very top of the screens ...

Changing the text in a Bootstrap tool-tip

Currently encountering an issue where I am attempting to modify the text displayed in a tooltip, but it appears that the change is not taking effect. Instead, upon hovering over, you will see the text "your new title." My goal is simply to alter the text w ...

Applying FadeIn Effect to Background Image on Hover

For several applications, I have utilized this jQuery code that swaps images with a smooth fading effect. It's incredibly straightforward. $(document).ready(function() { $("img.a").hover( function() { $(this).stop().animate({ ...

Sending a post request to a Spring controller with ajax: Step-by-step guide

I am having trouble sending a post request to the spring controller using ajax. It seems that something is not working correctly. If anyone can help me figure out what I did wrong, I would greatly appreciate it. $("#myprofile").on('submit&ap ...

OutOfMemoryError caused by Bitmap

I'm experiencing an issue with this error. I created a favicon parser from URLs using the following code: public class FavIconParser { public static String extractUrl(String url) { StringBuffer sb = new StringBuffer(); Pattern p = Pattern.co ...

JavaScript for Loading and Moving Ads in IE8

On my website at , I have placed my AdSense ads at the top of the page. However, I encountered an issue with Internet Explorer 8 where the Javascript code I used to move the ads to a different position on the page doesn't seem to work: <!-- POSI ...

Prompting the website to 'refresh' and return to the beginning of the page

My website's functionality is closely tied to the user's position on the page. Different features are triggered once specific distances are reached. I am seeking a way for users to automatically return to the top of the page upon page reload. Cu ...

Troubleshooting the issue with UI-Router AngularJS controller not functioning properly in a

Trying to grasp the ins and outs of UI-Router in conjunction with Angular has proven to be quite challenging for me. In my setup, there's an index: <body> <div ui-view></div> <!--Location of file holding app--> <scri ...

gallery showcasing pictures with a prominent main image and accompanying smaller images

I am struggling to display my image gallery the way I envision it. I would like to have a larger main image with the rest of the images displayed on the right side below it. The current code I have is: <div class="gallery"> <a href=" ...

Utilizing functions for object creation in JavaScript

Having trouble with creating a function that automatically generates an object and then alerts its properties. Can't seem to get the alerts when I click the button. Any assistance would be appreciated. <html> <head> <s ...

What is the reason for the enhanced sharpness of fonts in Chrome compared to other browsers?

I couldn't find an answer to this question through my searches on Google, so I apologize if it's already been asked. I've been working on a web project recently and one thing I noticed is that the fonts appear much bolder in Firefox or Safar ...