5
头图

概述

在前端领域,我们常常需要跟色彩打交道,除了一部分从设计转过来的前端外(ps:历史原因),后来的新生代前端绝大多数基本都是学理工科出身的,一般没有经过专门的设计训练和培养,这样在还原设计图的过程中对于色彩的理解都会或多或少有些出入,从而导致设计和前端产生不必要的矛盾(ps:本是同根生,都相互体谅下),本文旨在通过介绍相关的一些色彩知识,为大家提供一些设计和前端双重视角下的观点,也希望能够给大家提供一些对色彩的不同的认识和理解。

色彩理论

人类对色彩的研究其实很早都有记录,但真正把色彩作为一门学科或者说有其理论体系,还要从牛顿说起,在之后不断的科学发展过程中,人们逐渐对色彩有了不同的认识,也正是由于科学的发展,色彩理论在不同领域都有了长足的发展,本文着重分享两个对我们前端来说需要着重了解的色彩理论,即:色环理论以及加减色模式理论。

色环

色环理论经历了牛顿色环、伊顿色环(传统色环)、孟塞尔色环、Yurmby色环等几个不同的阶段,这里重点介绍传统的经典色环,也就是伊顿色环,其作为包豪斯体系中重要的理论课程,对设计领域的影响巨大(ps:对设计史感兴趣的童鞋,可以参看之前的这篇文章世界现代设计史),总体来说,色环理论可以简单提炼出以下几个常见的色彩概念:

名称相差度数解释
邻近色0-15度色环中两色相差较小,比较接近,不同人识别度不同,通常识别度较低
相似色15-45度色环中两色相差适中,既具有识别度,又具有相似度
中差色45-105度色环中两色相差有明显识别度,但又不会显得过于跳跃
对比色105-150度色环中两色相差有较强识别度,容易产生跳跃感
邻近互补色150-179度色环中两色相差较大,不建议搭配使用
互补色180度色环中两色相差对比强烈

加色模式 & 减色模式

在介绍加色模式和减色模式,我们先来看下我们从小学到的关于色彩的一些基本知识。我们之前上学的时候,美术老师可能教过三原色和三基色的概念,或者区分光学三原色和色彩三原色等等,这其实就已经是加色模式和减色模式的一个初步了解了,本质来说:三原色或者说三基色都是基于不同环境下材料而提出的一种基本色彩而已,我这里以光学三原色和色彩三原色来区分,光学三原色是:红(R)、绿(G)、蓝(B),也是我们前端开发过程中常用到的元色;而除了光学三原色外,还有一个色彩三原色,或者叫美术三原色,它们是:红(M)、黄(Y)、蓝(C),这个是印刷或者绘画过程中常常用到的元色。相信细心的同学已经发现我在标注英语的时候,色彩三原色和光学三原色里的红色及蓝色好像是不一样的,没错,正是由于不同场景下对于色彩使用的不同,而对色彩进行加合的过程中出现了不同的模式。这里,就要引出我们这一部分的核心理论了,即:加色模式和减色模式。

下面给出不严谨的加色模式和减色模式的定义

加色模式是指对色彩模型中的属性进行加和的模式;减色模式是指对色彩模型中的属性进行吸收的模式

那么为什么光学色彩是加色法而美术色彩却是减色呢?因为本质上,在光学场景中,比如在计算机显示器中通常使用的是从一种光源来发出不同的元色给人呈现色彩,不同的显示器制造材料有不同的显示特点,比如有:阴极射线管显示器(CRT)、等离子显示器(PDP)、液晶显示器(LCD)以及有机发光半导体显示器(OLED)等等,但这些通常都会是从一个光源发出的,因而这些通常就是加色模型,而一般来说会有RGB模型、YUV(YCrCb)模型等,在前端来说,咱们常见的是以RGB模型进行的相关对应关系代码操作,这里涉及到了色彩模型,具体请看下一部分的介绍。而在美术或者印刷场景中,则是利用的物体反射光线的原理,也就是说我们日常看到的物体的颜色其实是显示的它不能被吸收的颜色,例如:粉色颜料其实吸收了除粉色以外的所有光线,所以我们才能看到它是粉色,因而减色其实是吸收的模式,因而在CMYK模型中,其就是典型的减色模式。

色彩模型

在有了对色彩的初步认识之后,如果想要来描述色彩,我们就需要建立一个模型来描述它,这里就引出了色彩模型的概念,基于wiki百科和百度百科,我们不严谨的给出如下的定义:

色彩模型是用一个元组或者集合来描述可见光的子集,这里的元组通常为三元或者四元。

通常来说,按照是否设备相关,我们可以将色彩模型分为设备相关色彩模型以及设备不相关的色彩模型,基于此大致可以分为两大体系,即:RGB体系及XYZ体系,这里我们将介绍以下几种常见的色彩模型:RGB/CMYK、YUV/YCrCb、HS*、Lab、XYZ,下面将分别介绍下相关的颜色模型。

RGB & CMYK

RGB模型是典型的加法模型,其通过设立RGB为三个基色进行多种颜色的不同模型组合,其中R/G/B分别作为三维欧氏空间中的维度表示,对颜色进行相关的构建,如上图所示。

不同于RGB模型的加法合成,对于印刷相关的场景,则是典型的减法合成,而这里最常见的就是跟物质相关的基础颜料作为基础模型空间的维度,最常见的便是CMYK模型,其仍然是符合欧氏空间的模型构建,只是对于合成的算法过程中使用的是减法合成。

YUV & YCrCb

YUV模型作为RGB模型的变形形式,其常用于视频、电视领域的色彩表示。由于在视频及电视领域中,对于色调和饱和度的指标相对更为关键,因而使用U+V来表示色度,使用Y来表示明亮度。

随着视频编码技术的发展,YCbCr模型作为视频流采用的一种变形模型标准,其不再是通过u+v来表示色度,而是通过RGB输入信号的R与亮度的差异即Cr和通过RGB输入信号的B与亮度的差异即Cb进行维度构建,这相对于YUV或者YPrPb编码而言便是数字色差信号而不再是模拟色彩信号了。

YUV和YCrCb色彩模型常用于计算机视觉的相关分析中,对于视频及图像分析相关的同学可以更深入了解一下

HSV & HSL & HSB & HSI

对于人的视觉而言,其实通常最容易描述的就是基于色相(Hue)、饱和度(Saturation)以及最后这一个明度或者说亮度来区分,但是对于最后两个指标而言,不同模型的构建其实是不太一样的,这里我们将重点介绍两种模型,即:类HSL和类HSV模型

对于HSL模型而言,最后定义的指标是一个混入了黑白的量,其最后的形态在欧氏空间中,表现为一个全椎体,如上图所示。

而对于HSV模型而言,最后定义的指标只是混入了一个黑色的量,其最后形态在欧氏空间中,表现为一个倒立的圆锥体,如上图所示。

正是由于这种对于S和 * 的处理不同,导致出现了很多不同的名词及表示模型,这里我们用以下表格做一下常见的 HS* 模型的对比:

简写全称注释
HSVHue, Saturation, Value明度
HSLHue, Saturation, Lightness亮度
HSBHue, Saturation, Brightness明度
HSIHue, Saturation, Intensity亮度
结论:HSV = HSB,HSL ≈ HSI

如上图所示,后续我们不加特别说明的话,后续将以HSV和HSL这两种作为HS*的两种典型代表进行表述,作为RGB模型的变种,我们后续在色彩计算过程中对 HS* 和 RGB模型的换算进行详解。

LAB

随着发展,人们对色彩的研究不再局限于设备基础条件的限定,由此,CIE(Commission Internationale de Photométrie)国际照明协会提出了Lab模型,其不同于RGB的模型,其中L代表亮度,而a则是从深绿色(低亮)到灰色(中亮)再到亮粉红色(高亮)的过渡,b则是亮蓝色(低亮)到灰色(中亮)再到黄色(高亮)的过渡,其合成模型如上图所示。

XYZ

在上一个Lab模型中我们知道,CIE对色彩做了进一步的调研研究,其实Lab模型也是XYZ模型的一个衍生变种,其对RGB模型中的光源做了坐标系方面的区分,其对三元色进行了相关的修正,其是设备无关的,如上图所示,在欧氏空间中,两个坐标系发生了偏移。(ps:具体的变化,可以参考这篇文章RGB色彩体系和XYZ色彩体系

色彩空间

色彩空间又称为色域,在上一部分我们介绍了不同的色彩模型,那么对于实际生产过程中会遇到各种不同的实际情况,因而各个厂家或者组织基于各自的设备或者场景的不同而实际形成的色彩映射关系,从而提出了各自的色彩范围,这里我们结合wiki百科及百度百科,不严谨的给出如下定义:

色彩空间是基于色彩模型而对实际特定场景的色彩范围的映射关系。

对于常见的色彩空间,我们列举了以下几种:

色彩空间色彩模型注释
sRGBRGB模型微软联合HP、三菱等厂商开发的通用色彩标准,通用的色彩标准,色彩范围较小,也是网页中常用的色彩空间标准
adobe RGBRGB模型Adobe主导开发,尽可能使用计算机设备模拟印刷产品彩色样式
ProPhoto RGBRGB模型柯达公司制定的色彩空间标准,常用于高端相机
Japan Color 2001 CoatedCMYK模型日本印刷业协会制定的一种色彩空间标准
SWOP CMYKCMYK模型美国常用胶印墨色标准(US Web Coated),美国印刷业制定的一种色彩空间标准
CIE 1931 XYZXYZ模型CIE 1931年制定的标准
CIELABLab模型符合CIE 1931年的标准,从CIE LUV改进而来

色彩体系

在讲了关于色彩的一些基础理论和描述之后,我们来看一下设计领域对于色彩的相关运用和实践,这些对我们前端和设计同学协作也会有比较好的前置铺垫。

如果按照设计体系的标准制定,通常需要包含 愿景与原则(Vision & Principle)指南(Guidelines)库与工具(Libraries & Tools) 这三层,其中:

第一层:愿景与原则(Vision & Principle),是设计体系的核心价值观及总体纲领,指引整体设计体系的风格和调性。

第二层:指南(Guidelines),包含样式指南(Style Guideline)、模式指南(Patterns Guideline)、内容指南(Content Guideline)等更多通过文字和图像进行传达的内容,也是大部分设计中对色彩(Color)、版式(Layout)、。

第三层:库与工具(Libraries & Tools),包含组件库(Components Libraries)、工具包(Toolkits)、协同工具(Collaborative Tools)等可以直接进行使用的内容,一般会输出可开发使用的组件库、以sketch或者psd的设计资源以及产品使用的figma、axure等物料。(ps:大型设计团队也会协同前端制作对应的组件库,比如常见的antd、element组件库等都是对应的设计团队的前端资源,一般来说大型的团队可能会将设计和前端划入用户体验团队,当然这也需要看整体的组织架构)

之前做设计的时候,做过相关的设计体系,有兴趣的同学,可以看下这篇对应的设计体系实践——2018总结-多条业务线并行的UI基础框架规范(附案例)

在刚才介绍了设计体系之后,我们看到对于第二层的guidelines中,对于样式部分的规约,其中很重要的一个部分就是色彩,其实色彩是设计师展现视觉过程中最为重要的工具,在包豪斯体系中,作为三大构成之一的色彩构成是十分重要设计理论,而如果将色彩构建成符合商业化的体系,通常来说需要包含两大部分,即:通用色彩系统和商业色彩系统。

对于色彩系统的分类,这里我将以蚂蚁金服的ant design色彩体系作为样板来进行描述。

通用色彩系统,也就是antd中所说的系统级色彩体系,其是不包含任何关于商业及产品的特定色彩要求,只是设计师选出了几种特定的色彩,配合不同的视觉感受来表达不同的传达需求。

而商业色彩体系,也就是antd中所说的产品级色彩体系,通常需要配合品牌调性、产品功能等来从上述通用色彩系统中进行着重的筛选和设定,从而更好的服务商业化,用王受之先生的话讲就是:“设计是对外的,而艺术是对内的”。

现阶段的设计和工程结合的也越来越紧密,可以通过Design Token等手段将设计体系和工程体系进行相关的对接,从而化解设计和前端链路过程中的沟通成本问题,提升工程效能。关于设计方面的链路方面的提升,可以看看蚂蚁金服去年SEE Conf关于设计工程化的几场介绍--提效神器 Design Tokens 的探索与应用 - 昱星 & 元尧设计工程化三部曲 - 倏昱 & 闻冰

这里我列举了几个比较有名的设计团队所做的色彩体系风格,大家可以参考一下:

设计团队色彩体系备注
Ant DesignAnt Design色彩体系
Element DesignElement Design色彩体系
Material DesignMaterial Design色彩体系
Human Interface GuidelinesApple色彩体系
Fluent Design微软色彩体系

色彩计算

在理性的了解了色彩理论、色彩模型、色彩空间以及感性的体会了色彩体系之后,最后一部分我们来看一下之前所建立的理性与感性是如何通过计算进行融合的,这一部分我将着重介绍和我们前端相关的色彩模型换算(RGB与HSV/HSL),以及简单介绍下在换算过程中可能涉及到的数学计算方法(贝塞尔曲线),最后我们将通过ant design的色板实现来看一下色彩的具体应用。

RGB/HSL/HSV换算

在有了前边关于色彩模型的认识后,我们来看一下色彩模型之间是如何进行换算的,由于前端应用过程中主要涉及RGB向HS*的换算,因而这里我们仅仅介绍RGB模型是如何向HSL及HSV进行坐标体系换算的。

从视频中我们可以看出,RGB -> HSV 的过程为:

RGB倾斜 => 拉成六棱锥 => 转成六棱柱 => 转为圆柱

RGB -> HSL 的过程则为:

RGB倾斜 => 拉成双六棱锥 => 转成六棱柱 => 转为圆柱

从这个过程,我们经过一系列复杂的数学换算,可以得到如下转换公式:

注意:R、G、B都是换算到0-1区间的值,也就是这里的R/G/B是原本 0-255 区间的值除以255得到相应的值

Hue的换算

H的计算三者是一样的,即:

Lightness/Value/Intensity的换算

从上边的换算过程可知,L、V、I的对应方程为:

Saturation的换算

对于饱和度的换算,由于L、V、I的不同,导致换算过程中的S也发生了变化:

贝塞尔曲线

贝塞尔曲线作为数值计算中的重要方法,其对动态拟合不同运动轨迹有十分重要的作用,作为插值计算来处理伯恩斯坦多项式的重要方法,其对于科学计算十分重要。

在对色彩计算过程中,使用贝塞尔曲线来处理两个数据值也是一项十分重要的手段,可以更加接近对于色彩体系的构建和对真实色彩世界的拟合。

Ant Design 色板

在介绍了所有的色彩相关的模型、计算等等之后,我们来看一下前端中关于色彩计算的一些应用,这里我们以蚂蚁金服的 Ant Design 色板的生成算法作为案例进行一些简单的分析,来看一下色彩计算在组件库中的具体落地,对于更为详细的介绍,大家可以看一下偏右大佬所写的这篇《Ant Design 色板生成算法演进之路》,这里我仅仅做一下个人的理解与分析简述。

antd色板 1.x算法

// 变亮
@function tint($color, $percentage) {
    @return mix(white, $color, $percentage);
}
// 变暗
@function shade($color, $percentage) {
    @return mix(black, $color, $percentage);
}
// 使用
.useage {
    background-color: tint(#2db7f5, 80%);
}

第一版的方法很简单,我们看到直接使用了黑白的混合去处理,这里的mix是sass中的颜色混合方法,这里使用的是简单的RGB模型进行换算,具体换算方法我找到了dart-sass的中的方法:

/// Returns [color1] and [color2], mixed together and weighted by [weight].
SassColor _mixColors(SassColor color1, SassColor color2, SassNumber weight) {
  // This algorithm factors in both the user-provided weight (w) and the
  // difference between the alpha values of the two colors (a) to decide how
  // to perform the weighted average of the two RGB values.
  //
  // It works by first normalizing both parameters to be within [-1, 1], where
  // 1 indicates "only use color1", -1 indicates "only use color2", and all
  // values in between indicated a proportionately weighted average.
  //
  // Once we have the normalized variables w and a, we apply the formula
  // (w + a)/(1 + w*a) to get the combined weight (in [-1, 1]) of color1. This
  // formula has two especially nice properties:
  //
  //   * When either w or a are -1 or 1, the combined weight is also that
  //     number (cases where w * a == -1 are undefined, and handled as a
  //     special case).
  //
  //   * When a is 0, the combined weight is w, and vice versa.
  //
  // Finally, the weight of color1 is renormalized to be within [0, 1] and the
  // weight of color2 is given by 1 minus the weight of color1.
  var weightScale = weight.valueInRange(0, 100, "weight") / 100;
  var normalizedWeight = weightScale * 2 - 1;
  var alphaDistance = color1.alpha - color2.alpha;

  var combinedWeight1 = normalizedWeight * alphaDistance == -1
      ? normalizedWeight
      : (normalizedWeight + alphaDistance) /
          (1 + normalizedWeight * alphaDistance);
  var weight1 = (combinedWeight1 + 1) / 2;
  var weight2 = 1 - weight1;

  return SassColor.rgb(
      fuzzyRound(color1.red * weight1 + color2.red * weight2),
      fuzzyRound(color1.green * weight1 + color2.green * weight2),
      fuzzyRound(color1.blue * weight1 + color2.blue * weight2),
      color1.alpha * weightScale + color2.alpha * (1 - weightScale));
}

可以看到这里使用的是RGB模型的线性计算,由于RGB模型线性换算过程中对间隔的变化十分巨大,对于人眼的视觉效果十分不友好

antd色板 2.x算法

@import "bezierEasing";
@import "tinyColor";

// We create a very complex algorithm which take the place of original tint/shade color system
// to make sure no one can understand it 👻
// and create an entire color palette magicly by inputing just a single primary color.
// We are using bezier-curve easing function and some color manipulations like tint/shade/darken/spin
.colorPaletteMixin() {
@functions: ~`(function() {
  var warmDark = 0.5;     // warm color darken radio
  var warmRotate = -26;  // warm color rotate degree
  var coldDark = 0.55;     // cold color darken radio
  var coldRotate = 10;   // cold color rotate degree
  var getShadeColor = function(c) {
    var shadeColor = tinycolor(c);
    // warm and cold color will darken in different radio, and rotate in different degree
    // warmer color
    if (shadeColor.toRgb().r > shadeColor.toRgb().b) {
      return shadeColor.darken(shadeColor.toHsl().l * warmDark * 100).spin(warmRotate).toHexString();
    }
    // colder color
    return shadeColor.darken(shadeColor.toHsl().l * coldDark * 100).spin(coldRotate).toHexString();
  }
  var primaryEasing = colorEasing(0.6);
  this.colorPalette = function(color, index) {
    var currentEasing = colorEasing(index * 0.1);
    // return light colors after tint
    if (index <= 6) {
      return tinycolor.mix(
        '#ffffff',
        color,
        currentEasing * 100 / primaryEasing
      ).toHexString();
    }
    return tinycolor.mix(
      getShadeColor(color),
      color,
      (1 - (currentEasing - primaryEasing) / (1 - primaryEasing)) * 100
    ).toHexString();
  };
})()`;
}
// It is hacky way to make this function will be compiled preferentially by less
// resolve error: `ReferenceError: colorPalette is not defined`
// https://github.com/ant-design/ant-motion/issues/44
.colorPaletteMixin();

在第二版的算法中,使用的HSL模型进行的整体色板粒度变化,然后换算到RGB模型中。

其中在基于HSL模型分割粒度的时候,这里作者使用了自己定义的一个转化方法,对于灰度的判断,使用的是r与b的比较,而这里的旋转角度及darken比例个人以为应该是作者根据实际生产数据获得的经验值,这里我并没有从相关资料中获取到对应的推到依据。

这里的RGB的混合也不再使用sass中的方法,而是基于tinyColor中的混合方法,mix方法如下:

tinycolor.mix = function(color1, color2, amount) {
    amount = (amount === 0) ? 0 : (amount || 50);

    var rgb1 = tinycolor(color1).toRgb();
    var rgb2 = tinycolor(color2).toRgb();

    var p = amount / 100;

    var rgba = {
        r: ((rgb2.r - rgb1.r) * p) + rgb1.r,
        g: ((rgb2.g - rgb1.g) * p) + rgb1.g,
        b: ((rgb2.b - rgb1.b) * p) + rgb1.b,
        a: ((rgb2.a - rgb1.a) * p) + rgb1.a
    };

    return tinycolor(rgba);
};

mix过程中的比例也不再是线性,而是使用的一个固定的贝塞尔曲线进行绘制的曲线,从上图中大体看出其基本符合线性的拟合。

antd色板 3.x算法

前置算法,判断亮度,使用了转灰度的算法公式(ps:601校正公式,由NTSC亮度方程推导而来),即:

Y = 0.299 R + 0.587 G + 0.114 * B

tinycolor的库中,实现方式如下:

function getBrightness() {
    //http://www.w3.org/TR/AERT#color-contrast
    var rgb = this.toRgb();
    return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
},

在下边的 isLight 获取就是从上述的 getBrightness 转化而来

/* stylelint-disable no-duplicate-selectors */
@import "bezierEasing";
@import "tinyColor";

// We create a very complex algorithm which take the place of original tint/shade color system
// to make sure no one can understand it 👻
// and create an entire color palette magicly by inputing just a single primary color.
// We are using bezier-curve easing function and some color manipulations like tint/shade/darken/spin
.colorPaletteMixin() {
@functions: ~`(function() {
  var hueStep = 2;
  var saturationStep = 0.16;
  var saturationStep2 = 0.05;
  var brightnessStep1 = 0.05;
  var brightnessStep2 = 0.15;
  var lightColorCount = 5;
  var darkColorCount = 4;

  var getHue = function(hsv, i, isLight) {
    var hue;
    if (hsv.h >= 60 && hsv.h <= 240) {
      hue = isLight ? hsv.h - hueStep * i : hsv.h + hueStep * i;
    } else {
      hue = isLight ? hsv.h + hueStep * i : hsv.h - hueStep * i;
    }
    if (hue < 0) {
      hue += 360;
    } else if (hue >= 360) {
      hue -= 360;
    }
    return Math.round(hue);
  };
  var getSaturation = function(hsv, i, isLight) {
    var saturation;
    if (isLight) {
      saturation = hsv.s - saturationStep * i;
    } else if (i === darkColorCount) {
      saturation = hsv.s + saturationStep;
    } else {
      saturation = hsv.s + saturationStep2 * i;
    }
    if (saturation > 1) {
      saturation = 1;
    }
    if (isLight && i === lightColorCount && saturation > 0.1) {
      saturation = 0.1;
    }
    if (saturation < 0.06) {
      saturation = 0.06;
    }
    return Number(saturation.toFixed(2));
  };
  var getValue = function(hsv, i, isLight) {
    var value;
    if (isLight) {
      value = hsv.v + brightnessStep1 * i;
    }else{
      value = hsv.v - brightnessStep2 * i
    }
    if (value > 1) {
      value = 1;
    }
    return Number(value.toFixed(2))
  };

  this.colorPalette = function(color, index) {
    var isLight = index <= 6;
    var hsv = tinycolor(color).toHsv();
    var i = isLight ? lightColorCount + 1 - index : index - lightColorCount - 1;
    return tinycolor({
      h: getHue(hsv, i, isLight),
      s: getSaturation(hsv, i, isLight),
      v: getValue(hsv, i, isLight),
    }).toHexString();
  };
})()`;
}
// It is hacky way to make this function will be compiled preferentially by less
// resolve error: `ReferenceError: colorPalette is not defined`
// https://github.com/ant-design/ant-motion/issues/44
.colorPaletteMixin();

对于目前的antd 色板生成算法,这里是基于HSV模型进行的相关融合,其中:

  1. 对于色相,在60到240度的色相进行了色相的粒度分割;
  2. 对于饱和度,加深和减淡部分做了不同的粒度处理,其中减淡更快;
  3. 对于明度,明度减弱也比加和粒度要更大;

不同于2.x使用的贝塞尔曲线去拟合曲线,这里又改回线性组合来进行符合色彩体系的可控调整,从而使得整体的方案特别清晰明了,但又不同于1.x中的暴力组合,这里的灰度推算是基于亮度方程来作为科学依据的换算,算是融合了1.x和2.x各自的特点

总结

在前端开发过程中,我们在帮助设计师对于色彩体系的构建时,除了对于日常常见的一些感知层面的理解外,我们更应该注重对于深层原理的探索与探究,追问科学深层的认知,对于我们探索前端领域的深层有着至关重要的作用,比如在色彩中的计算机视觉方面的探索,让我们对于工程与设计链路的扩展提供了更高层次和维度的认识,希望各位同学在后续研发过程中,都能通过探索底层追问,获取到对于自己工作边界的认知探索。

色彩的研究绝不仅仅涉及到色彩理论、色彩模型、色彩空间、色彩计算等,其实色彩是一门十分有意思且可以很深入的学科,对于我们前端来讲则更为重要,作为连接设计与数据的纽带,也作为关联用户与企业的先锋,我们对前端理论学习的同时也要对相关科学理论知识作补充,做到能够对知识的灵活运用,帮助企业和用户提升更好的体验,这也是我们作为前端工程师的更高价值所在,共勉!!!

参考


维李设论
1.1k 声望4k 粉丝

专注大前端领域发展