如何创建仅具有绿色、蓝色、橙色和金色值的颜色?

How can I create a color with values for green, blue, orange, and gold only?

如果知道红色、绿色和蓝色的 "weights",就可以使用 class 来创建一种颜色,比如

.blaRGB {
    color: rgb(128, 128, 128)
}
.blaHSL {
    color: hsl(33%, 34%, 33%)
}

并像这样在 HTML 中使用它:

<p class="blaRGB">BLA RGB</p>
<p class="blaHSL">BLA HSL</p>

根据上面显示的值,blaRGB 是暗灰色,blaHSL 是白色。

但是如果要表示其他颜色的组合,例如绿色、蓝色、橙色和金色,该怎么办?

有没有一种方法可以使用如下所示的符号来定义此类颜色?

.CyndiLauper {
    color: truecolors(24, 13, 11, 12) 
}

或者用 color: gbog(24, 13, 11, 12) 其中 gbog 中的字母分别代表绿色、蓝色、橙色和金色?

目的是根据上面的 CSS 定义,HTML

<p class="CyndiLauper">These are your True Colors, shining through!</p>

将以这四种颜色的加权组合显示文本。

我相信使用绿色、蓝色、橙色和金色的 RGB 值进行一些复杂的数学运算是可能的,但我不知道如何进行。

更新

我意识到我最初忽略的问题的关键组成部分是 "What exactly do you mean by green, blue, orange, and gold"?

为了回答这个问题,根据官方 "True Colors" website,并使用 ColorZilla 浏览器插件,这些颜色的 RGB 值为:

green = 15, 167, 73
blue = 0, 152, 215
orange = 243, 123, 38
gold = 255, 230, 101

(在我看来,它们实际上更像是森林绿、道奇蓝、红橙色和黄色。)

不,你不能。这是一个 link 到 W3 Css Colors 的定义,在顶部声明只能使用蓝色、红色和绿色。

编辑:好的,让我澄清一下。根据我的理解,这在本质上是不可能的。但是,您可以使用 Less 和 Sass 做一些事情来达到您想要的结果。 Here 是一些关于 Less Color 函数的教程。最有趣的是关于混合颜色的部分:

.box.mix {
    background-color: mix(@blue, @yellow, 50%);
}

不过,我没有这方面的经验,您需要了解一下。

我想知道答案是否不只是 'mix' RGB 颜色?

var green = [15, 167, 73];
var blue = [0, 152, 215];
var orange = [243, 123, 38];
var gold = [255, 230, 101];

generateTrueColor(greenRatio, blueRatio, orangeRatio, goldRatio){
  for(var i = 0; i < 3, i++){
    RGB[i] = greenRatio * green[i] + blueRatio * blue[i] + orangeRatio * orange[i] + goldRatio * gold[i];
  }
  return RGB;
  for(var i = 0; i < 3, i++){
    if(RGB[i] > 255) RGB[i] = 255;
  }
}

generateTrueColor(1, 0.1, 0.1, 0.1);

我不确定除以 50 是 right/best 的事情,但这很有效:

// Note that the results differ from "true" blue, green, orange, and gold; the colors used to represent these are custom versions of those colors, as found on the True Colors website
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Sandbox
{
    public partial class FormTrueColorsMain : Form
    {
        // Primary constituents of the "True Colors" hues
        const int GREEN_RED = 15;
        const int GREEN_GREEN = 167;
        const int GREEN_BLUE = 73;
        const int BLUE_RED = 0;
        const int BLUE_GREEN = 152;
        const int BLUE_BLUE = 215;
        const int ORANGE_RED = 243;
        const int ORANGE_GREEN = 123;
        const int ORANGE_BLUE = 38;
        const int GOLD_RED = 255;
        const int GOLD_GREEN = 230;
        const int GOLD_BLUE = 101;

        Color tcGreen = Color.FromArgb(15, 167, 73);
        Color tcGreenComplement = Color.FromArgb(240, 88, 182);
        Color tcBlue = Color.FromArgb(0, 152, 215);
        Color tcOrange = Color.FromArgb(243, 123, 38);
        Color tcGold = Color.FromArgb(255, 230, 101);

        public FormTrueColorsMain()
        {
            InitializeComponent();
            InitializeControls();
        }

        private void InitializeControls()
        {
            lblGreen.ForeColor = tcGreen;
            lblGreen.BackColor = Color.White; // tcGreenComplement;
            lblBlue.ForeColor = tcBlue;
            lblBlue.BackColor = Color.White;
            lblOrange.ForeColor = tcOrange;
            lblOrange.BackColor = Color.Black;
            lblGold.ForeColor = tcGold;
            lblGold.BackColor = Color.Black;
            // For these to work, needed to also comment out "Application.EnableVisualStyles();" in Program.cs (see Crispy's answer at 
            progressBarGreen.ForeColor = tcGreen;
            progressBarGreen.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
            progressBarBlue.ForeColor = tcBlue;
            progressBarBlue.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
            progressBarOrange.ForeColor = tcOrange;
            progressBarOrange.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
            progressBarGold.ForeColor = tcGold;
            progressBarGold.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // If they have already been set (user clicked the arrows rather than entered the value directly), this is moot but it's
            // probably not worthwhile checking to see whether their value is 0, and only calling the methods conditionally in that case.
            SetGreenProgressBar();
            SetBlueProgressBar();
            SetOrangeProgressBar();
            SetGoldProgressBar();

            int greenVal = (int)numericUpDownGreen.Value;
            int blueVal = (int)numericUpDownBlue.Value;
            int orangeVal = (int)numericUpDownOrange.Value;
            int goldVal = (int)numericUpDownGold.Value;

            Color trueColor = GetTrueCombinedColor(greenVal, blueVal, orangeVal, goldVal);
            pictureBoxTCCombo.BackColor = trueColor;
        }

        private Color GetTrueCombinedColor(int greenVal, int blueVal, int orangeVal, int goldVal)
        {
            // tcBlue has no red, so can disregard blueVal for redTotal
            int redTotal = ((greenVal * GREEN_RED) + (orangeVal * ORANGE_RED) + (goldVal * GOLD_RED));
            int greenTotal = ((greenVal * GREEN_GREEN) + (blueVal * BLUE_GREEN) + (orangeVal * ORANGE_GREEN) + (goldVal * GOLD_GREEN));
            int blueTotal = ((greenVal * GREEN_BLUE) + (blueVal * BLUE_BLUE) + (orangeVal * ORANGE_BLUE) + (goldVal * GOLD_BLUE));

        int redWeight = redTotal / 50;
        int greenWeight = greenTotal / 50;
        int blueWeight = blueTotal / 50;
        if (redWeight <= 0) redWeight = 1;
        if (greenWeight <= 0) greenWeight = 1;
        if (blueWeight <= 0) blueWeight = 1;
        if (redWeight >= 256) redWeight = 255;
        if (greenWeight >= 256) greenWeight = 255;
        if (blueWeight >= 256) blueWeight = 255;

            Color trueColorCombo = Color.FromArgb(redWeight, greenWeight, blueWeight);
            //Color trueColorCombo = Color.FromArgb(redWeight, greenWeight, blueWeight, 10);
            return trueColorCombo;
        }

        private void numericUpDownGreen_ValueChanged(object sender, EventArgs e)
        {
            SetGreenProgressBar();
        }

        private void SetGreenProgressBar()
        {
            progressBarGreen.Value = (int)numericUpDownGreen.Value;
        }

        private void numericUpDownBlue_ValueChanged(object sender, EventArgs e)
        {
            SetBlueProgressBar();
        }

        private void SetBlueProgressBar()
        {
            progressBarBlue.Value = (int)numericUpDownBlue.Value;
        }

        private void numericUpDownOrange_ValueChanged(object sender, EventArgs e)
        {
            SetOrangeProgressBar();
        }

        private void SetOrangeProgressBar()
        {
            progressBarOrange.Value = (int)numericUpDownOrange.Value;
        }

        private void numericUpDownGold_ValueChanged(object sender, EventArgs e)
        {
            SetGoldProgressBar();
        }

        private void SetGoldProgressBar()
        {
            progressBarGold.Value = (int)numericUpDownGold.Value;
        }
    }

}

实用程序如下所示:

辛迪·劳珀,尽情享受吧!

有多种混合颜色的方法,具体取决于您使用的颜色模型:

以下代码片段演示了两种混合方法。最左边的列显示四种原始颜色。下一列显示具有 0.25 不透明度的相同颜色,从而产生半透明颜色。第三列将半透明颜色叠加在一起,相当于 alpha 合成。

第四列显示了另一种混合方法。这里我们看到分别对四种原始颜色的R、G、B分量进行平均的结果。

var Colors = {
  names: ['green', 'blue', 'orange', 'gold'],
  values: {
    green: { r: 15, g: 167, b: 73 },
    blue: { r: 0, g: 152, b: 215 },
    orange: { r: 243, g: 123, b: 38 },
    gold: { r: 255, g: 230, b: 101 }
  }
};

Colors.toHex2 = function (decimal) {
  var hex = decimal.toString(16);
  return (hex.length == 1 ? '0'+hex : hex);
};

Colors.toColorString = function (value) {
  var g = Colors,
      toHex2 = g.toHex2;
  var parts = [ '#', toHex2(value.r), toHex2(value.g), toHex2(value.b) ];
  return parts.join('');
};

Colors.load = function () {
  var g = Colors,
      names = g.names,
      values = g.values,
      containers = {
        original: document.getElementById('original'),
        translucent: document.getElementById('translucent'),
        layered: document.getElementById('layered'),
        averaged: document.getElementById('averaged')
      },
      averaged = { r: 0, g: 0, b: 0 };
  document.body.style.paddingTop = 10*(1+names.length) + 'px';
  for (var i = 0; i < names.length; ++i) {
    var name = names[i],
        value = values[name],
        color = g.toColorString(value),
        swatch = document.createElement('div'),
        proportion = 1 / names.length;
    swatch.className = 'swatch';
    swatch.style.backgroundColor = color;
    containers.original.appendChild(swatch);

    swatch = swatch.cloneNode();
    swatch.style.opacity = proportion;
    containers.translucent.appendChild(swatch);

    swatch = swatch.cloneNode();
    swatch.style.height = 60 + 10*(names.length-1) + 'px';
    swatch.style.top = 10*(1+i-names.length) + 'px';
    containers.layered.appendChild(swatch);

    averaged.r += proportion * value.r;
    averaged.g += proportion * value.g;
    averaged.b += proportion * value.b;
  }

  swatch = document.createElement('div');
  swatch.className = 'swatch';
  averaged.r = Math.round(averaged.r);
  averaged.g = Math.round(averaged.g);
  averaged.b = Math.round(averaged.b);
  swatch.style.backgroundColor = g.toColorString(averaged);
  containers.averaged.appendChild(swatch);
};

window.onload = Colors.load;
body {
  font-family: sans-serif;
  font-size: 24px;
  margin: 0;
  padding-left: 20px;
}
.display {
  width: 120px;
  float: left;
}
.swatch {
  width: 100px;
  height: 60px;
  margin-bottom: 10px;
}
.layered {
  position: relative;
  height: 60px;
}
.layered .swatch {
  position: absolute;
}
<div id="original" class="display"></div>

<div id="translucent" class="display"></div>

<div id="layered" class="display layered"></div>

<div id="averaged" class="display"></div>

在上面的演示中,我们让网络浏览器为我们进行 alpha 合成。我们也可以直接进行 alpha 合成。图层不透明度相当于alpha通道,所以我们将每种颜色的alpha通道设置为颜色的权重。也就是说,如果一个颜色的权重是25%,我们就把它的alpha通道设置为0.25。

请注意,alpha 通道的范围是从 0 到 1。但是,我们的 RGB 分量的范围是从 0 到 255。

假设我们混合这两种颜色:

  • RGB 值 background 带 alpha 通道 alpha.background
  • RGB 值 foreground 带 alpha 通道 alpha.foreground

我们计算结果颜色的 alpha 通道 alpha.mix 如下:

alpha.mix = 1 - (1-alpha.background)*(1-alpha.foreground);

要计算 RGB 值的 R 分量 mix,我们这样做:

mix.r = 255 * (foreground.r/255.0 * alpha.foreground/alpha.mix +
        mix.r/255.0 * alpha.background*(1-alpha.foreground)/alpha.mix);

同样对于 G 组件 mix.g 和 B 组件 mix.b

下面的代码片段是一个交互式演示,它将 alpha 合成与并行平均 RGB 分量的更简单方法进行了比较。 运行 代码并使用滑块来查看这两种方法之间的区别。

var Mixer = {
  color: {
    names: ['green', 'blue', 'orange', 'gold'],
    rgb: {
      green: { r: 15, g: 167, b: 73 },
      blue: { r: 0, g: 152, b: 215 },
      orange: { r: 243, g: 123, b: 38 },
      gold: { r: 255, g: 230, b: 101 }
    }
  },
  style: {
    swatch: { width: 150, height: 90, margin: { right: 15 } },
    slider: { height: 20 },
    handle: { width: 20, height: 34 }
  }
};

Mixer.toHex2 = function (decimal) {
  var hex = decimal.toString(16);
  return (hex.length == 1 ? '0'+hex : hex);
};

Mixer.toCSS = function (rgb) {
  var g = Mixer,
      toHex2 = g.toHex2;
  var parts = [ '#', toHex2(rgb.r), toHex2(rgb.g), toHex2(rgb.b) ];
  return parts.join('');
};

Mixer.toString = function (rgb) {
  return 'rgb(' + [rgb.r, rgb.g, rgb.b].join(', ') + ')';
};

Mixer.makeUnselectable = function (element) {
  element.className += ' unselectable';
  element.ondragstart = element.onselectstart = function (event) {
    event.preventDefault();
  };
};

Mixer.makeElement = function (tag, className, innerHTML, unselectable) {
  var g = Mixer,
      element = document.createElement(tag);
  element.className = (className ? className : '');
  element.innerHTML = (innerHTML ? innerHTML : '');
  if (unselectable) {
    g.makeUnselectable(element);
  }
  return element;
};

Mixer.handleDown = function (event) {
  event = event || window.event;
  var g = Mixer;
  g.mouseX = { depart: event.screenX };
  g.activeHandle = this;
  window.onmousemove = Mixer.handleMove;
  window.onmouseup = Mixer.handleUp;
};
Mixer.handleMove = function (event) {
  event = event || window.event;
  var g = Mixer,
      handle = g.activeHandle,
      pos = handle.pos,
      handles = g.handles,
      num = g.num,
      slider = g.slider,
      proportion = g.proportion,
      segments = g.segments,
      handleWidth = g.style.handle.width,
      swatches = g.swatches,
      canvas = g.canvas,
      context = g.context,
      mixingFunctions = g.mixingFunctions,
      limit = {
        min: (pos == 0 ? 0 : handles[pos-1].right),
        max: (pos == num-2 ? slider.length.total : handles[pos+1].left) -
            handleWidth
      },
      mouseX = g.mouseX;
  mouseX.current = event.screenX;
  var left = handle.left + mouseX.current - mouseX.depart;
  if (left < limit.min) {
    left = limit.min;
  }
  if (left > limit.max) {
    left = limit.max;
  }
  handle.newLeft = left;
  segments[pos] = left - limit.min;
  context.fillStyle = swatches[pos].css;
  context.fillRect(limit.min, 0, segments[pos], canvas.height);
  segments[pos+1] = limit.max - left;
  context.fillStyle = swatches[pos+1].css;
  context.fillRect(left + handleWidth, 0, segments[pos+1], canvas.height);
  handle.style.left = left + 'px';
  var segmentSpan = segments[pos] + segments[pos+1],
      proportionSpan = proportion[pos] + proportion[pos+1];
  if (segmentSpan != 0) {
    proportion[pos] = Math.round(segments[pos]/segmentSpan * proportionSpan);
    proportion[pos+1] = proportionSpan - proportion[pos];
    swatches[pos].percent.innerHTML = proportion[pos] + '%';
    swatches[pos+1].percent.innerHTML = proportion[pos+1] + '%';
  }
  g.mixColors();
};
Mixer.handleUp = function (event) {
  var g = Mixer,
      handle = g.activeHandle;
  window.onmousemove = null;
  window.onmouseup = null;
  handle.left = handle.newLeft;
  handle.right = handle.left + g.style.handle.width;
};

Mixer.makeFunctionName = function (title) {
  var parts = ['mix'],
      tokens = title.split(' ');
  for (var i = 0; i < tokens.length; ++i) {
    var token = tokens[i];
    parts.push(token[0].toUpperCase() + token.substring(1));
  }
  return parts.join('');
};

Mixer.mixAlphaCompositing = function (swatch, label) {
  return function () {
    var g = Mixer,
        swatches = g.swatches,
        proportion = g.proportion,
        num = g.num,
        mix = {},
        subs = ['r', 'g', 'b'];
    for (var i = 0; i < subs.length; ++i) {
      var x = subs[i];
      mix[x] = swatches[0].rgb[x];
    }
    var alpha = { back: proportion[0]/100 };
    for (var pos = 1; pos < num; ++pos) {
      var fore = swatches[pos].rgb;
      alpha.fore = proportion[pos]/100,
      alpha.mix = 1 - (1-alpha.back)*(1-alpha.fore);
      if (alpha.mix >= 1.0e-6) {
        for (var i = 0; i < subs.length; ++i) {
          var x = subs[i];
          mix[x] = 255 * (fore[x]/255 * alpha.fore/alpha.mix +
              mix[x]/255 * alpha.back*(1-alpha.fore)/alpha.mix);
        }
      }
      alpha.back = alpha.mix;
    }
    for (var i = 0; i < subs.length; ++i) {
      var x = subs[i];
      mix[x] = Math.round(mix[x]);
    }
    var css = g.toCSS(mix);
    label.rgb.innerHTML = g.toString(mix);
    label.css.innerHTML = css;
    swatch.style.backgroundColor = css;
    swatch.style.opacity = alpha.mix;
  };
};

Mixer.mixWeightedAverage = function (swatch, label) {
  return function () {
    var g = Mixer,
        swatches = g.swatches,
        proportion = g.proportion,
        num = g.num,
        mix = { r: 0, g: 0, b: 0 },
        subs = ['r', 'g', 'b'];
    for (var pos = 0; pos < num; ++pos) {
      for (var i = 0; i < subs.length; ++i) {
        var x = subs[i];
        mix[x] += proportion[pos]/100 * swatches[pos].rgb[x];
      }
    }
    for (var i = 0; i < subs.length; ++i) {
      var x = subs[i];
      mix[x] = Math.round(mix[x]);
    }
    var css = g.toCSS(mix);
    label.rgb.innerHTML = g.toString(mix);
    label.css.innerHTML = css;
    swatch.style.backgroundColor = css;
  };
};

Mixer.mixColors = function () {
  var g = Mixer,
      mixingFunctions = g.mixingFunctions;
  for (var i = 0; i < mixingFunctions.length; ++i) {
    mixingFunctions[i]();
  }
};

Mixer.load = function () {
  var g = Mixer,
      style = g.style;

  // Make color swatches.
  var palette = g.palette = document.getElementById('palette'),
      names = g.color.names,
      swatches = g.swatches = [],
      num = g.num = names.length;
  for (var i = 0; i < num; ++i) {
    var name = names[i],
        rgb = g.color.rgb[name],
        css = g.toCSS(rgb),
        container = g.makeElement('div', 'swatchContainer', '', true),
        percent = g.makeElement('div', 'title', '', true),
        swatch = g.makeElement('div', 'swatch', '', true);
    swatches[i] = { rgb: rgb, css: css, percent: percent };
    container.appendChild(percent);
    swatch.style.backgroundColor = css;
    swatch.style.width = style.swatch.width + 'px';
    swatch.style.height = style.swatch.height + 'px';
    swatch.style.marginRight = style.swatch.margin.right + 'px';
    container.appendChild(swatch);
    container.appendChild(g.makeElement('div', 'label', g.toString(rgb), true));
    container.appendChild(g.makeElement('div', 'label', css, true));
    palette.appendChild(container);
  }
  var totalWidth = num*style.swatch.width + (num-1)*style.swatch.margin.right;

  // Initialize proportions.
  var proportion = g.proportion = new Array(num),
      each = Math.floor(100/num);
  for (var i = 0; i < num-1; ++i) {
    proportion[i] = each;
  }
  proportion[num-1] = 100 - (num-1)*each;
  for (var i = 0; i < num; ++i) {
    swatches[i].percent.innerHTML = proportion[i] + '%';
  }

  // Prepare the blended swatches.
  var blend = g.blend = { container: document.getElementById('blend') },
      mixers = ['alpha compositing', 'weighted average'],
      between = (totalWidth - mixers.length*style.swatch.width) /
          (mixers.length + 1);
  g.makeUnselectable(blend);
  blend.container.style.width = totalWidth + 'px';
  blend.container.style.height = style.swatch.height + 'px';
  g.mixingFunctions = [];
  for (var i = 0; i < mixers.length; ++i) {
    var mixer = mixers[i],
        container = g.makeElement('div', 'swatchContainer', '', true),
        title = g.makeElement('div', 'title', mixer, true),
        swatch = g.makeElement('div', 'swatch', '', true),
        label = {
          rgb: g.makeElement('div', 'label', '', true),
          css: g.makeElement('div', 'label', '', true)
        };
    swatch.style.width = style.swatch.width + 'px';
    swatch.style.height = style.swatch.height + 'px';
    container.style.left = i*style.swatch.width + (i+1)*between + 'px';
    container.appendChild(title);
    container.appendChild(swatch);
    container.appendChild(label.rgb);
    container.appendChild(label.css);
    blend.container.appendChild(container);
    var functionName = g.makeFunctionName(mixer),
        mixingFunction = g[functionName](swatch, label);
    g.mixingFunctions.push(mixingFunction);
  }

  // Assemble the slider widget.
  var slider = g.slider = document.getElementById('slider');
  slider.length = {
    total: totalWidth,
    free: totalWidth - (num-1)*style.handle.width
  };
  var segments = g.segments = new Array(num);
  var tail = slider.length.free;
  for (var i = 0; i < num-1; ++i) {
    var current = Math.round(proportion[i]/100*slider.length.free);
    segments[i] = current;
    tail -= current;
  }
  segments[num-1] = tail;
  slider.style.width = slider.length.total + 'px';
  slider.style.height = style.slider.height + 'px';
  var canvas = g.canvas = g.makeElement('canvas'),
      context = g.context = canvas.getContext('2d');
  g.makeUnselectable(slider);
  g.makeUnselectable(canvas);
  canvas.width = slider.length.total;
  canvas.height = style.slider.height;
  slider.appendChild(canvas);
  var handles = g.handles = new Array(num-1);
  var left = 0;
  for (var i = 0; i < num; ++i) {
    context.fillStyle = swatches[i].css;
    context.fillRect(left, 0, segments[i], canvas.height);
    if (i == num-1) {
      break;
    }
    var handle = handles[i] = g.makeElement('div', 'handle', '', true);
    handle.pos = i;
    handle.style.width = style.handle.width + 'px';
    handle.style.height = style.handle.height + 'px';
    handle.style.top = (style.slider.height - style.handle.height)/2 + 'px';
    handle.left = left + segments[i];
    handle.style.left = handle.left + 'px';
    handle.right = handle.left + style.handle.width;
    left = handle.right;
    handle.onmousedown = g.handleDown;
    slider.appendChild(handle);
  }

  g.mixColors();
};

window.onload = Mixer.load;
body {
  font-family: sans-serif;
  color: #444;
}

.unselectable {
  -webkit-user-select: none;
  -khtml-user-drag: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -moz-user-select: -moz-none;
  -ms-user-select: none;
  user-select: none;
}

#blend {
  position: relative;
  padding: 10px 0 90px;
}
#blend .swatchContainer {
  position: absolute;
}
#blend .swatchContainer .title {
  font-size: 17px;
  padding-bottom: 5px;
}

#slider {
  margin: 20px 0;
  position: relative;
}
.handle {
  position: absolute;
  background: #444;
  border-radius: 5px;
  cursor: pointer;
}

.swatchContainer {
  float: left;
}
.swatchContainer .title {
  font-size: 25px;
  text-align: center;
}
.swatchContainer .label {
  font-size: 17px;
}
<div id="blend"></div>

<div id="slider"></div>

<div id="palette"></div>