溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

使用 JavaScript 控制 CSS 中的顏色

發(fā)布時(shí)間:2020-08-12 15:20:10 來源:ITPUB博客 閱讀:174 作者:智云編程 欄目:web開發(fā)

背景知識(shí):顏色模型

點(diǎn)開這篇文章的你,肯定是想要學(xué)習(xí)怎樣控制顏色的——我們后面就會(huì)講具體操作。但首先,我們需要對 CSS 如何標(biāo)記顏色有一個(gè)基本的認(rèn)識(shí)。CSS 使用的是兩種顏色模型:RGB 和 HSL,我們先簡單了解一下。

RGB

RGB 就是“紅色,綠色,藍(lán)色”的簡稱。這個(gè)模型由三個(gè)數(shù)字組成,每個(gè)數(shù)字表示其所代表的顏色在最終生成的顏色中有多高的亮度。在 CSS 中,每個(gè)數(shù)值的范圍都是 0-255,三個(gè)數(shù)值間用逗號(hào)分隔,作為 CSS rgb 函數(shù)的參數(shù),例如:rgb(50,100,0)。

RGB 是一種“增量”顏色系統(tǒng)。這意味著每個(gè)數(shù)字越高,最終生成的顏色就越亮。如果所有值都相等就生成灰度顏色;如果所有值都為零,結(jié)果為黑色;如果所有值都是 255,則結(jié)果為白色。

此外你也可以使用十六進(jìn)制表示法來標(biāo)記 RGB 顏色,其中每種顏色的數(shù)值從 10 進(jìn)制轉(zhuǎn)換為 16 進(jìn)制。例如,rgb(50,100,0)用 16 進(jìn)制就寫成#326400。

雖然我個(gè)人比較習(xí)慣使用 RGB 模型(特別是十六進(jìn)制),但我也經(jīng)常發(fā)現(xiàn)它不易閱讀,也不容易操作。下面來看 HSL 模型。


一個(gè)人學(xué)習(xí)會(huì)有迷茫,動(dòng)力不足。這里推薦一下我的前端學(xué)習(xí)交流群:731771211 ,里面都是學(xué)習(xí)前端的,如果你想制作酷炫的網(wǎng)頁,想學(xué)習(xí)編程。自己整理了一份2019最全面前端學(xué)習(xí)資料,從最基礎(chǔ)的HTML+CSS+JS【炫酷特效,游戲,插件封裝,設(shè)計(jì)模式】到移動(dòng)端HTML5的項(xiàng)目實(shí)戰(zhàn)的學(xué)習(xí)資料都有整理,送給每一位前端小伙伴,有想學(xué)習(xí)web前端的,或是轉(zhuǎn)行,或是大學(xué)生,還有工作中想提升自己能力的,正在學(xué)習(xí)的小伙伴歡迎加入學(xué)習(xí)。

HSL

HSL是“色調(diào),飽和度,光線”的簡稱,HSL 也包含三個(gè)值。色調(diào)值對應(yīng)于色輪上的點(diǎn),由 CSS 角度值表示,最常用的是度數(shù)單位。

飽和度以百分比表示,是指顏色的強(qiáng)度。當(dāng)飽和度為 100%時(shí)顏色最深,飽和度越低,顏色越淺,直到灰度為 0%。

亮度也以百分比表示,指的是顏色有多亮。 “常規(guī)”的亮度是 50%。無論色調(diào)和飽和度值如何,100%的亮度都是純白色,0%的亮度就是純黑色。

我覺得 HSL 模型更直觀一些,顏色.之間的關(guān)系更加明顯,控制顏色時(shí)只要簡單地調(diào)整幾個(gè)數(shù)字就可以了。

顏色模型之間的轉(zhuǎn)換

RGB 和 HSL 顏色模型都將顏色分解為各種屬性。要在不同模型之間進(jìn)行轉(zhuǎn)換,我們首先需要計(jì)算這些屬性。

除了色調(diào),上面提到的所有數(shù)值都可以表示為百分比。就連 RGB 值也是用字節(jié)表示的百分比。 在下面提到的公式和函數(shù)中,這些百分比將由 0 到 1 之間的小數(shù)來表示。

這里提一下,我并不會(huì)深入探討這些數(shù)學(xué)知識(shí);相比之下,我將簡要介紹一遍原始數(shù)學(xué)公式,然后將其轉(zhuǎn)換為 JavaScript 格式。

從 RGB 模型中計(jì)算亮度

亮度是三個(gè) HSL 值中最容易計(jì)算的一個(gè)。其數(shù)學(xué)式如下,其中 M 是 RGB 值的最大值,m 是最小值:

使用 JavaScript 控制 CSS 中的顏色

用 JavaScript 函數(shù)寫成下面的形式:

const rgbToLightness =(r,g,b)=>     1/2 *(Math.max(r,g,b)+ Math.min(r,g,b));

從 RGB 模型中計(jì)算飽和度

飽和度僅比亮度稍微復(fù)雜一些。 如果亮度為 0 或 1,則飽和度值為 0;否則,它基于下面的數(shù)學(xué)公式計(jì)算得出,其中 L 表示亮度:

使用 JavaScript 控制 CSS 中的顏色

寫成 JavaScript:

const rgbToSaturation = (r,g,b) => {
  const L = rgbToLightness(r,g,b);
  const max = Math.max(r,g,b);
  const min = Math.min(r,g,b);
  return (L === 0 || L === 1)
   ? 0
   : (max - min)/(1 - Math.abs(2 * L - 1));
};

從 RGB 模型中計(jì)算色調(diào)

從 RGB 坐標(biāo)中計(jì)算色調(diào)角度的公式有點(diǎn)復(fù)雜:

使用 JavaScript 控制 CSS 中的顏色

寫成 JavaScript:

const rgbToHue = (r,g,b) => Math.round(
  Math.atan2(
    Math.sqrt(3) * (g - b),
    2 * r - g - b,
  ) * 180 / Math.PI
);

最后 180 / Math.PI 的算法是將結(jié)果從弧度轉(zhuǎn)換為度。

計(jì)算 HSL

上面這些函數(shù)都可以包含在同一個(gè)功能函數(shù)里:

const rgbToHsl = (r,g,b) => {
  const lightness = rgbToLightness(r,g,b);
  const saturation = rgbToSaturation(r,g,b);
  const hue = rgbToHue(r,g,b);
  return [hue, saturation, lightness];
}

從 HSL 模型中計(jì)算 RGB 值

開始計(jì)算 RGB 之前,我們需要一些前提值。

首先是“色度”值:

使用 JavaScript 控制 CSS 中的顏色

還有一個(gè)臨時(shí)的色調(diào)值,我們將用它來確定我們所屬的色調(diào)圈的“段”:

使用 JavaScript 控制 CSS 中的顏色

接下來,我們設(shè)一個(gè)“x”值,它將用作中間(第二大)組件值:

使用 JavaScript 控制 CSS 中的顏色

我們再設(shè)一個(gè)“m”值,用于調(diào)整各個(gè)亮度值:

使用 JavaScript 控制 CSS 中的顏色

根據(jù)色調(diào)區(qū)間值,r,g 和 b 值將映射到 C,X 和 0:

使用 JavaScript 控制 CSS 中的顏色

最后,我們需要映射每個(gè)值以調(diào)整亮度:

使用 JavaScript 控制 CSS 中的顏色

將上面這些都寫到 JavaScript 函數(shù)中:

    const hslToRgb = (h,s,l) => {
  const C = (1 - Math.abs(2 * l - 1)) * s;
  const hPrime = h / 60;
  const X = C * (1 - Math.abs(hPrime % 2 - 1));
  const m = l - C/2;
  const withLight = (r,g,b) => [r+m, g+m, b+m];
if (hPrime <= 1) { return withLight(C,X,0); } else
  if (hPrime <= 2) { return withLight(X,C,0); } else
  if (hPrime <= 3) { return withLight(0,C,X); } else
  if (hPrime <= 4) { return withLight(0,X,C); } else
  if (hPrime <= 5) { return withLight(X,0,C); } else
  if (hPrime <= 6) { return withLight(C,0,X); }
}

創(chuàng)建顏色對象

為了便于在操作屬性時(shí)訪問,我們將創(chuàng)建一個(gè) JavaScript 對象。把前面提到的這些函數(shù)打包起來就能創(chuàng)建這個(gè)對象:

const rgbToObject = (red,green,blue) => {
  const [hue, saturation, lightness] = rgbToHsl(red, green, blue);
  return {red, green, blue, hue, saturation, lightness};
}
 
const hslToObject = (hue, saturation, lightness) => {
  const [red, green, blue] = hslToRgb(hue, saturation, lightness);
  return {red, green, blue, hue, saturation, lightness};
}

顏色控制

現(xiàn)在我們已經(jīng)知道怎樣在顏色模型之間進(jìn)行轉(zhuǎn)換了,那么就來看看該如何控制這些顏色!

更新屬性

我們提到的所有顏色屬性都可以單獨(dú)控制,返回一個(gè)新的顏色對象。例如,我們可以編寫一個(gè)旋轉(zhuǎn)色調(diào)角度的函數(shù):

const rotateHue = rotation => ({hue, ...rest}) => {
  const modulo = (x, n) => (x % n + n) % n;
  const newHue = modulo(hue + rotation, 360);
return { ...rest, hue: newHue };
}

rotateHue 函數(shù)會(huì)接受一個(gè)旋轉(zhuǎn)參數(shù)并返回一個(gè)新函數(shù),該函數(shù)接受并返回一個(gè)顏色對象。這樣就可以輕松創(chuàng)建新的“旋轉(zhuǎn)”函數(shù):

const rotate30 = rotateHue(30);
const getComplementary = rotateHue(180);
const getTriadic = color => {
  const first = rotateHue(120);
  const second = rotateHue(-120);
  return [first(color), second(color)];
}

用這種方式,你也可以編寫加深或提亮顏色的函數(shù)——或者反過來,減淡或變暗也行。

const saturate = x => ({saturation, ...rest}) => ({
  ...rest,
  saturation: Math.min(1, saturation + x),
});
const desaturate = x => ({saturation, ...rest}) => ({
  ...rest,
  saturation: Math.max(0, saturation - x),
});
const lighten = x => ({lightness, ...rest}) => ({
  ...rest,
  lightness: Math.min(1, lightness + x)
});
const darken = x => ({lightness, ...rest}) => ({
  ...rest,
  lightness: Math.max(0, lightness - x)
});

顏色謂詞

除了顏色控制以外,你還可以編寫“謂詞”——亦即返回布爾值的函數(shù)。

const isGrayscale = ({saturation}) => saturation === 0;
const isDark = ({lightness}) => lightness < .5;

處理顏色數(shù)組

過濾器

JavaScript [] .filter 方法會(huì)接受一個(gè)謂詞并返回一個(gè)新數(shù)組,其中包含所有“傳遞”的元素。我們在上一節(jié)中編寫的謂詞可以用在這里:

const colors = [/* ... an array of color objects ... */];
const isLight = ({lightness}) => lightness > .5;
const lightColors = colors.filter(isLight);

排序

要對顏色數(shù)組進(jìn)行排序,首先需要編寫一個(gè)“比較器”函數(shù)。 此函數(shù)接受一個(gè)數(shù)組的兩個(gè)元素并返回一個(gè)數(shù)字來表示“贏家”。正數(shù)表示第一個(gè)元素應(yīng)該先排序,而負(fù)數(shù)表示第二個(gè)元素應(yīng)該先排序。 零值表示平局。

例如,這是一個(gè)比較兩種顏色亮度的函數(shù):

const compareLightness = (a,b) => a.lightness - b.lightness;

這是一個(gè)比較飽和度的函數(shù):

const compareSaturation = (a,b) => a.saturation - b.saturation;

為了防止代碼重復(fù),我們可以編寫一個(gè)高階函數(shù)來返回一個(gè)比較函數(shù)來對比各種屬性:

const compareAttribute = attribute =>
  (a,b) => a[attribute] - b[attribute];
const compareLightness = compareAttribute('lightness');
const compareSaturation = compareAttribute('saturation');
const compareHue = compareAttribute('hue');

平均屬性

你可以搭配各種 JavaScript 數(shù)組方法來平衡顏色數(shù)組中的特定屬性。首先,你可以使用 reduce 求和并用 Array length 屬性分割來計(jì)算一個(gè)屬性的均值:

    const colors = [/* ... an array of color objects ... */];
const toSum = (a,b) => a + b;
const toAttribute = attribute => element => element[attribute];
const averageOfAttribute = attribute => array =>
  array.map(toAttribute(attribute)).reduce(toSum) / array.length;

你可以用它來“規(guī)范化”一組顏色:

/* ... continuing */
const normalizeAttribute = attribute => array => {
  const averageValue = averageOfAttribute(attribute)(array);
  const normalize = overwriteAttribute(attribute)(averageValue);
  return normalize(array);
}
const normalizeSaturation = normalizeAttribute('saturation');
const normalizeLightness = normalizeAttribute('lightness');
const normalizeHue = normalizeAttribute('hue');

結(jié)論

顏色是網(wǎng)絡(luò)不可或缺的一部分。將顏色分解為屬性就可以靈活控制它們,并創(chuàng)造出無限的可能。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI