【问题标题】:CSS Conditional Formatting with a colour range具有颜色范围的 CSS 条件格式
【发布时间】:2021-05-09 16:41:58
【问题描述】:

我希望使用 div 和 span 创建一个基本图表,并希望根据设置其高度的值对图表中的每一列应用条件格式。我无法破解的技巧是我想让它的功能有点像此处示例中的 Excel 条件格式:

颜色在一个范围内(从浅到深)。 有没有一种简单的方法可以做到这一点?我可以看到如何将静态值应用于静态颜色,但希望我可以对颜色范围做一些事情,比如这个 excel 示例。

因此,下面的屏幕截图显示了一个柱形图,其中每一列都有不同的橙色阴影,由列的值决定:

列越接近 25,颜色越深。同样,值越低,橙色越浅。

【问题讨论】:

    标签: html css conditional-formatting


    【解决方案1】:

    听起来您的目标是根据值在两种颜色之间的某处为条着色。如果是这样,你可以使用 css 动画来模拟颜色渐变。

    想法是这样的:

    • 设置动画,将背景设置为两种颜色之一。这有效地计算了两种颜色之间的梯度。您可以使用 @keyframesanimation 执行此操作。
    • 暂停动画,因为我们不希望它实际播放。这是通过animation-play-state 完成的。
    • 选择动画中的特定帧以获得正确的中间颜色。这可以用否定的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>

    如果需要,可以通过使动画持续时间超过 25 秒来调整粒度。

    【讨论】:

    • 谢谢你...我很快就会试一试!唯一的问题是,我目前在条形图上有一个动画,可以在加载时快速扩展它们(看起来很整洁)。将它添加到同一个 div 元素会阻止它工作(即我们现在正在暂停动画?!)
    • 文档建议您可以暂停一些动画并播放其他动画:developer.mozilla.org/en-US/docs/Web/CSS/animation-play-state
    • 这对我来说非常完美......!谢谢!我现在也了解了单个元素中的多个动画,因此也感谢您! :)
    【解决方案2】:

    我将提供两个选项,也许您可​​以根据您的需要提供更多详细信息。

    第一个可能不是您想要的,因为它会根据特定高度设置特定的渐变。只会为此提供一个 Codepen。 https://codepen.io/jfirestorm44/pen/yLMNPPM?editors=1100

    下一个是我认为你想要的更多。如果您知道条形图的最大高度,您可以使用它来设置 linear-gradient 上的渐变中断。

    更新: 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);
        }
      }
    }
    

    更新的 Codepen:https://codepen.io/jfirestorm44/pen/jOBPopj?editors=1100

    添加一个 JS 选项:

    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>

    【讨论】:

    • 非常感谢您的回答...!我知道我的问题可能不太清楚,所以更新了我所追求的更多细节......我希望这会有所帮助!我有点急于提出最初的问题,所以希望这个编辑有助于使我的要求更清楚一点?再次感谢!
    • 第二个例子看起来非常接近......但是,我不会在显示完整渐变的列之后,而是在整个列之后仅显示列渐变顶部的颜色。 . 我希望这是有道理的......?
    • 我更新了代码。 HSL 对此非常有用,因为您可以根据一个值更改亮度,从而渲染一系列颜色。在这种情况下,它从 50% 变为 75%。基于我拥有的酒吧数量。
    • 您可以将其更改为 -10 以提供更深的颜色变化或任何适合您需要的颜色。如果你真的想发疯,同样可以应用于色调和饱和度。
    • 再次感谢您的更新!这看起来真的很好。我会看看我是否可以集成这个解决方案。然而,我的第一个想法是列数在 SCSS 中是硬编码的——但是我有动态的列数,具体取决于用户输入。我需要看看我是否可以将这个想法整合到一个更动态的解决方案中。再次感谢您的帮助,谢谢!
    【解决方案3】:

    [编辑] 此答案仅从左到右对条形进行着色,左侧具有最浅的颜色。

    我会让容器有一个白色的背景和黑色的条,然后在所有东西上添加一个渐变,在一个伪元素的帮助下,mixed-blend-mode: lighten 只为黑色条着色。

    作为奖励,我添加了另一个具有重复线性渐变的伪元素,该渐变由真正的浅灰色组成,以创建水平线。然后,我将mixed-blend-mode: darken 添加到此元素中,以使它们出现在条形“下方”。

    我还通过随机化每个条形的 CSS 属性来随机化条形的高度。

    此解决方案可扩展,因此无论您有多少条,您仍然可以在所有条上获得渐变,而无需更改 CSS 代码。

    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>

    【讨论】:

    • 谢谢你,我会试一试的。然而,看看你的 sn-p 的结果,它看起来并不像颜色的阴影取决于条的值(高度) - 而是从左到右每个条变暗,无论高度如何.. .??
    • 哦,这就是我从草率阅读中得到的。是的,我以为是从左到右。 :D Justin 的答案很准确,使用 HSL 值。
    • 感谢您的反馈!我已经尝试过 Justin 的示例,但需要弄清楚如何使 SCSS 中的列数动态化,因为不同的屏幕具有不同的列数。我对 SCSS 非常陌生,因此必须深入研究。否则,是的,它看起来真的很好!再次干杯!
    • @CJH 您实际上并不需要 SCSS,而是通过仅通过 javascript 更新 CSS 变量来重用我的解决方案。如果你有兴趣,我可以快速写下一些东西。
    • 啊,我明白了,是的,如果你能做到,将不胜感激!谢谢! :)
    【解决方案4】:

    结合使用我和贾斯汀的答案,但适用于普通 CSS。

    这个答案是使用 HSL 和 CSS 变量来设置颜色和高度。

    随机值

    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>

    增加值

    从 5 到 25 的静态值,如 OP 的图片所示。

    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>

    【讨论】:

    • 感谢 Rickard....!正如您发布的那样,我已经接受了最高响应(Auroratide)作为接受的答案......它的不同旋转但有趣的旋转。希望我能将其中几个标记为正确答案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-20
    相关资源
    最近更新 更多