• 一个“会”用代码调色的Web前端开发,绝对是一个吃香的设计师


    用代码着色,一种程序化的设计绝佳方法。学习创建美丽、鼓舞人心和独特的调色板/组合,所有都会让你的网页和文本编辑变得更加舒适!废话不多说,今天带着大家认识下LCH颜色表达方式!

    颜色是强大的——它可以从根本上改变我们的情绪,激励我们,并帮助我们以一种其他事物无法做到的方式表达自己。在设计中我们常听到的是RGB(常用的网页颜色三元素)以及打印的CMYK;为了更好的视觉效果,我们也需要了解LCH颜色!这样可以让我们的网页更加有层次感,高级感十足!当你了解了这篇文章后,绝对会提升你的审美观。老板看了你写的网页,绝对是赞不绝口。还要给你加薪!

    什么是LCH颜色

    LCH 代表亮度 (颜色的深/浅)色度 (颜色的鲜艳/饱和度)色调 (颜色是红色、绿色、蓝色……)

    简而言之,LCH 是一种与 RGB 或 HSL 一样的颜色表示方式,但有一些显着的优势——对于本教程来说最重要的是它的感知均匀性。在本教程中,我们几乎只使用 LCH 颜色。我知道这听起来有点吓人,但我保证不会;让我告诉你这意味着什么!

    首先,看看这两对 HSL 颜色: 

    请注意,尽管顶部和底部对具有相同的 20 度色相变化,但我们 实际 看到的差异却大不相同?这种不平衡的存在是因为 HSL 在感知上 并不 统一

    现在看看同样的实验,这次使用 LCH 颜色:

    HSL 和 LCH 之间的色调值不能完美对齐。在 LCH 中,0 的色调更粉红色,而在 HSL 中,它是纯红色。 啊,好多了!

    这里看到的色调变化更加平衡,因为 LCH 在 感知上是均匀的。 接下来,我们来看看另外两种 HSL 颜色: 

     

    这两种颜色具有相同的亮度值,但在我们的人眼看来却大不相同。左边的黄色比右边的蓝色“亮”得多。

    这是一个类似的设置,但使用的是 LCH 颜色而不是 HSL: 

     

    这还差不多!如上图所示,LCH 中的亮度值更准确地表示了我们所感知的内容——这与 LCH 的均匀色调分布相结合,将使我们 在创建和谐的调色板时更加轻松 。 

    目前,这就是我们需要知道的全部内容,但如果您想了解更多信息,我强烈推荐Lea Verou 撰写的这篇文章。 

    我们将在本教程中使用一个库,但本机 LCH 支持正在走向浏览器!事实上,它已经存在于 Safari 中,其他浏览器目前也在使用它。

    跟着

    在我们编写任何代码之前,我们需要一个简单的开发环境。此设置完全由您选择,但我建议您启动 CodePen 或者vscode以跟随示例,然后在需要时移至自定义设置/存储库。真的,我们在这里只需要一个 HTML/JavaScript 文件,我们将使用 Skypack 进行所有库导入,因此不需要任何花哨的构建过程等。

    功能#1——“科学”

    好的!首先,我们使用“传统”颜色理论生成颜色。要开始使用此方法,让我们看一下称为色轮的东西:

    看起来熟悉?

    色轮是色彩空间中色调的视觉表示。上面的轮子代表 LCH 中的色调,以 30 度的步长递增,从 0 度到 360 度——这是一种成熟的格式。事实上,数百年来,我们一直在使用轮子来寻找可以很好地协同工作的颜色!

    这是如何做:

    我们从基色开始。然后,我们围绕轮子旋转一定度数一定次数;为了完美 互补的 调色板,我们移动 180 度一次: 

    迷人的!对于 三元 调色板,我们移动 120 度,两次: 

     

    看看这是怎么回事?通过改变步数和旋转量,我们可以创建几个“经典”调色板:

     

    代码

     

    function adjustHue(val) {
      if (val < 0) val += Math.ceil(-val / 360) * 360;
    
      return val % 360;
    }
    
    function createScientificPalettes(baseColor) {
      const targetHueSteps = {
        analogous: [0, 30, 60],
        triadic: [0, 120, 240],
        tetradic: [0, 90, 180, 270],
        complementary: [0, 180],
        splitComplementary: [0, 150, 210]
      };
    
      const palettes = {};
    
      for (const type of Object.keys(targetHueSteps)) {
        palettes[type] = targetHueSteps[type].map((step) => ({
          l: baseColor.l,
          c: baseColor.c,
          h: adjustHue(baseColor.h + step),
          mode: "lch"
        }));
      }
    
      return palettes;
    }

    要打破这一点:

      1. 定义一个createScientificPalettes需要单个baseColor参数的函数。

      2. 定义几个“经典”调色板的色调步骤。

      3. 对于每种调色板类型:迭代每个色调步长,将步长值添加到基本色调,并存储生成的颜色——确保其chroma和lightness值与基本色调匹配。使用一个小adjustHue函数来确保所有色调值都在 0 到 360 之间。

      4. 以 LCH 格式返回调色板。  

    用法:

    惊人的!我们可以createScientificPalettes这样调用我们的函数:

    const baseColor = {
      l: 50,
      c: 100,
      h: 0,
      mode: "lch"
    };
    
    const palettes = createScientificPalettes(baseColor);

    在上面的示例中,我们传递一个baseColor对象,该函数返回各种调色板,所有这些调色板都以该基础为中心。多亏了 LCH,这些调色板中颜色的亮度和强度将在视觉上保持一致,并且色调调制高度准确;这对于可访问性非常有用,因为与其他颜色空间不同,调色板中的每种颜色都将具有相同的 感知 对比度。 

    凉爽的!现在剩下要做的就是将 LCH 颜色转换为更可用的格式。为此,我们可以使用Culori(本教程中使用的一个出色的颜色实用程序库)将 LCH 对象转换为 HEX:

    import { formatHex } from "https://cdn.skypack.dev/culori@2.0.0";
    
    const baseColor = {
      l: 50,
      c: 100,
      h: 0,
      mode: "lch"
    };
    
    const palettes = createScientificPalettes(baseColor);
    const triadicHex = palettes.triadic.map((colorLCH) => formatHex(colorLCH));
    
    // ["#ff007c", "#1f8a00", "#0091ff"]

     Culori 需要mode对所有颜色对象进行显式处理。您会注意到这包含在本教程的代码示例中。 

    对于我们的第一个函数,就是这样!让我们看看我们如何在现实生活中使用它。

    实际应用

    使用代码(以编程方式) 创建我们的调色板的一个好处 是它使快速原型设计/实验变得非常容易。比如说,我们正在做一个设计,完全不知道要使用什么调色板。使用我们的createScientificPalettes函数以及一些简单的 CSS 自定义属性,我们可以生成近乎无限的调色板并使用我们的 UI 实时测试它们! 

    这是一个 CodePen 来演示:

     

    挑战

    现在,我们的createScientificPalettes函数适用于所有调色板类型,除了 单色。您可以更新它以支持单色调色板吗? 

    功能#2——“发现”

    因此,此功能与前一个功能相似,但有 很大 的不同。我们仍在生成“经典”颜色组合,但不是科学地计算它们 (将设置“步骤”添加到基色的色调中), 我们正在 发现 它们!这是正确的; 我们的发现功能将采用一系列颜色并在其中找到最佳的调色板匹配——类似的、三色的、四色的等。 

    这是一个图解示例:

    使用此功能,我们可以在图像、颜色数据集等中发现漂亮的调色板!让我们看看它是如何工作的。

    代码

    import {
      nearest,
      differenceEuclidean,
    } from "https://cdn.skypack.dev/culori@2.0.0";
    
    function isColorEqual(c1, c2) {
      return c1.h === c2.h && c1.l === c2.l && c1.c === c2.c;
    }
    
    function discoverPalettes(colors) {
      const palettes = {};
    
      for (const color of colors) {
        const targetPalettes = createScientificPalettes(color);
    
        for (const paletteType of Object.keys(targetPalettes)) {
          const palette = [];
          let variance = 0;
    
          for (const targetColor of targetPalettes[paletteType]) {
            // filter out colors already in the palette
            const availableColors = colors.filter(
              (color1) => !palette.some((color2) => isColorEqual(color1, color2))
            );
    
            const match = nearest(
              availableColors,
              differenceEuclidean("lch")
            )(targetColor)[0];
    
            variance += differenceEuclidean("lch")(targetColor, match);
    
            palette.push(match);
          }
    
          if (!palettes[paletteType] || variance < palettes[paletteType].variance) {
            palettes[paletteType] = {
              colors: palette,
              variance
            };
          }
        }
      }
    
      return palettes;
    }
    1. 将 LCH 颜色数组传递给discoverPalettes函数。 

    2. createScientificPalettes对于每种颜色,使用我们的函数 基于它创建“最佳”目标调色板。

    3. 对于每个调色板,为其每种颜色找到最接近的匹配。我们在这里使用 Culori 的最接近和差分欧几里得函数计算颜色匹配。 

    4. 确定“发现”调色板与目标的相似/不同程度。记录最接近的调色板匹配。 

    5. 返回每个调色板类型最接近的匹配! 

    惊人的!这种方法非常令人兴奋,因为它的操作方式与人类非常相似——查看选择的颜色并找到最好的(但绝不是 完美的)调色板;这很棒,因为有时,纯粹的数学色彩理论可能会显得有些枯燥/可预测。 

    用法  

    作为快速参考,以下是我们如何使用discoverPalettes十六进制颜色数组: 

    import {
      converter,
    } from "https://cdn.skypack.dev/culori@2.0.0";
    
    const toLCH = converter("lch");
    
    const baseColors = [
      "#FFB97A",
      "#FF957C",
      "#FF727F",
      "#FF5083",
      "#F02F87",
      "#C70084",
      "#9A007F",
      "#6A0076",
      "#33006B"
    ];
    
    const baseColorsLCH = baseColors.map((color) => toLCH(color));
    
    const palettes = discoverPalettes(baseColorsLCH);
    
    // { analogous: [...], complementary: [...], ... }

     至少需要四种颜色才能正常工作。 discoverPalettes

     

    实际应用

    最引人注目的方面之一discoverPalettes是它能够从几乎任何来源中提取连贯的颜色组合。就是这样,根据Unsplash中的图像发现调色板:

    酷吧?从照片中提取调色板是一种奇妙的工作方式,当您遇到想法时,并且discoverPalettes使过程 非常容易。这种方法以前只能通过“神奇的”颜色生成器/应用程序获得,现在就在我们的指尖,可以进行调整、迭代和改进,以适应我们自己的个人用例和偏好!

    挑战

    现在,我们的discoverPalettes函数可以在一组颜色中找到最佳匹配,但控制起来并不容易。您可以为其选择添加一定程度的偏差/权重吗?例如,您如何修改函数以优先考虑更亮的颜色?

    功能#3——“色相转换”

    对于我们的第三个也是最后一个功能,我们将从像素艺术世界中汲取灵感!

    通常在向精灵添加阴影/高光时,像素艺术家不仅会调制颜色的亮度/色度(如果使用 HSL,则为饱和度),还会改变其色调。这是一个关于这个主题的优秀视频,但简而言之,这就是它的样子:

     真好看!当颜色变浅时,它的色调就会上移;当它变暗时,它会向下移动。当巧妙地应用时,这种技术有助于确保颜色的色调/色调生动而有影响力。当“拨号”一点时,它是生成令人惊叹的独立调色板的绝妙方式。

    代码

    function adjustHue(val) {
      if (val < 0) val += Math.ceil(-val / 360) * 360;
    
      return val % 360;
    }
    
    function map(n, start1, end1, start2, end2) {
      return ((n - start1) / (end1 - start1)) * (end2 - start2) + start2;
    }
    
    function createHueShiftPalette(opts) {
      const { base, minLightness, maxLightness, hueStep } = opts;
    
      const palette = [base];
    
      for (let i = 1; i < 5; i++) {
        const hueDark = adjustHue(base.h - hueStep * i);
        const hueLight = adjustHue(base.h + hueStep * i);
        const lightnessDark = map(i, 0, 4, base.l, minLightness);
        const lightnessLight = map(i, 0, 4, base.l, maxLightness);
        const chroma = base.c;
    
        palette.push({
          l: lightnessDark,
          c: chroma,
          h: hueDark,
          mode: "lch"
        });
    
        palette.unshift({
          l: lightnessLight,
          c: chroma,
          h: hueLight,
          mode: "lch"
        });
      }
    
      return palette;
    }

    将其分解为以下步骤: 

    1. 将基色、最小/最大亮度和色调步长参数传递给createHueShiftPalette函数。最小/最大亮度值决定了我们的调色板在任一极端时有多暗/多亮。该步骤控制每种颜色的色调变化量。

    2. 将基色存储在数组中。在上图中,这是中间颜色。 

    3. 创建一个迭代四次的循环。每次迭代,在数组的开头添加较深的阴影,在末尾添加较浅的色调。在这里,我们map用来计算亮度值——一个函数,它接受一个通常存在于一个范围内的数字并将其转换为另一个范围——并使用我们的hueStep变量增加或减少色调。同样,adjustHue这里使用 来确保所有色调值都在 0 到 360 之间。

    4. 归还调色板! 

    用法 

    一旦我们的createHueShiftPalette函数被定义,我们可以像这样使用它:

    import { formatHex } from "https://cdn.skypack.dev/culori@2.0.0";
    
    const hueShiftPalette = createHueShiftPalette({
      base: {
        l: 55,
        c: 75,
        h: 0,
        mode: "lch"
      },
      minLightness: 10,
      maxLightness: 90,
      hueStep: 12
    });
    
    const hueShiftPaletteHex = hueShiftPalette.map((color) => formatHex(color));
    
    // ["#ffb97a", "#ff957c", "#ff727f", "#ff5083", "#f02f87", "#c70084", "#9a007f", "#6a0076", "#33006b"]

    实际应用

    生成的调色板createHueShiftPalette非常 适合 图案/图形;这是一个使用它来创建随机/生成模式的示例,这些模式在每次渲染时都会略有不同: 

     

    挑战

    现在,亮度/色调值在我们的createHueShiftPalette函数中线性缩放。你可以对它们应用一些缓和吗?也许,从更大/更小的色调偏移开始,并随着每一步减少/增加它?好吧,伙计们,这就是现在的全部!我们已经学习了如何创建三个漂亮的颜色生成函数,了解如何应用它们并考虑如何改进/更改它们。从这里开始,我希望您采用这些功能并更改它们以适合您,甚至希望您自己编写!作为开发人员,我们拥有独特的技能组合, 非常 适合创建真正创新、令人惊叹的设计。无论这意味着为与您合作的设计师创建颜色生成工具,还是为您的网站添加令人兴奋的生成调色板——我们都应该对我们使用颜色的能力充满信心。

    如有相关前端方面的技术问题 ,欢迎主页添加我们微信群,我会定期在群里给大家分享最新技术和解答问题 。

  • 相关阅读:
    查询程序,统计文件每个单词出现几次,对应的出现在哪一行
    适配器 STL
    非关联容器|hash|unordered_map/multimap,unordered_set/multiset
    函数对象
    ACM-ICPC 2018 徐州赛区网络预赛 J. Maze Designer (最大生成树+LCA求节点距离)
    D. Connected Components Croc Champ 2013
    [Educational Codeforces Round 63 ] D. Beautiful Array (思维+DP)
    C. Vasily the Bear and Sequence Codeforces 336C(枚举,思维)
    Vasya and Beautiful Arrays CodeForces
    D. Happy Tree Party CodeForces 593D【树链剖分,树边权转点权】
  • 原文地址:https://www.cnblogs.com/icodingedu/p/16108334.html
Copyright © 2020-2023  润新知