这是一个我正在工作的函数,以编程方式使十六进制颜色变亮或变暗。只需要传入一个像“3F6D2A”这样的字符串来表示颜色(col),并传入一个base10整数(amt)来表示要变亮或变暗的量。为了变暗,传入一个负数(即-20)。

我这么做的原因是,到目前为止,我找到的所有解决方案似乎都把问题复杂化了。我有一种感觉,只需几行代码就可以完成。请让我知道,如果你发现任何问题,或有任何调整,以加快它。

有趣的灯光 上校(16号); return键(col . & 0x0000FF) + amt) | ((((col > > 8) & 0x00FF) + amt) < < 8) | (16 (col > >) + amt) < < 16) . toString (16); 的 / /测试 控制台(照明颜色(“3F6D2A”,40);

对于开发人员来说,这里有一个更容易阅读的版本:

函数 LightenDarkenColor(col, amt) { var num = parseInt(col, 16); var r = (num >> 16) + amt; var b = ((num >> 8) &0x00FF) + amt; var g = (num & 0x0000FF) + amt; var 新颜色 = g |(b << 8) |(第16<<条); 返回 newColor.toString(16); } 测试 console.log(LightenDarkenColor(“3F6D2A”, -40));

最后一个版本可以处理开头可能有(也可能没有)“#”的颜色。加上调整不适当的颜色值:

function LightenDarkenColor(col,amt) {
    var usePound = false;
    if ( col[0] == "#" ) {
        col = col.slice(1);
        usePound = true;
    }

    var num = parseInt(col,16);

    var r = (num >> 16) + amt;

    if ( r > 255 ) r = 255;
    else if  (r < 0) r = 0;

    var b = ((num >> 8) & 0x00FF) + amt;

    if ( b > 255 ) b = 255;
    else if  (b < 0) b = 0;
    
    var g = (num & 0x0000FF) + amt;

    if ( g > 255 ) g = 255;
    else if  ( g < 0 ) g = 0;

    return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
}

好了,现在它不只是几行,但它看起来更简单,如果你不使用“#”,不需要检查颜色超出范围,它只是几行。

如果不使用“#”,你可以像这样在代码中添加它:

var myColor = "3F6D2A";
myColor = LightenDarkenColor(myColor,10);
thePlaceTheColorIsUsed = ("#" + myColor);

我想我的主要问题是,我说的对吗?这不是包括大多数(正常)情况吗?如果是的话,最快最小的方法是什么?我想在动画和小环境中使用,所以速度是这里的第一个最重要的因素,尺寸第二,准确性第三,可读性?嗯?不在要求清单上(对不起,我知道你们中有一半人正在泪眼汪汪!)


当前回答

你的方法是可以的:)我简化了你的最短版本一点点(饱和度控制看这里)

(col,amt)=> (+('0x'+col)+amt*0x010101).toString(16).padStart(6,0)

// Similar to OP shortest version, we not have here # and colors range checking var LightenDarkenColor = (col,amt) => (+('0x'+col)+amt*0x010101).toString(16).padStart(6,0); // ------ // TEST // ------ function update() { let c= col.value.padEnd(6,'0').slice(0,6); let color = '#'+LightenDarkenColor(c, +amt.value); oldColor.innerHTML = 'Old: #'+c; oldColor.style = `background: #${c}`; newColor.innerHTML = 'New: '+color newColor.style = `background: ${color}`; } update(); .box{ width: 100px; height: 100px; margin: 10px; display: inline-block} <input id="col" value="3F6D2A" oninput="update()"> <input id="amt" value="30" oninput="update()"><br> <div id="oldColor" class="box"></div> <div id="newColor" class="box"></div>

和版本#和颜色范围检查

// # and colors range checking var LightenDarkenColor = (col,amt) => '#'+col.slice(1).match(/../g) .map(x=>(x=+`0x${x}`+amt,x<0?0:(x>255?255:x)) .toString(16).padStart(2,0)).join``; // ------ // TEST // ------ function update() { let c= col.value.padEnd(6,'0').slice(0,7); let color = LightenDarkenColor(c, +amt.value); oldColor.innerHTML = 'Old: '+c; oldColor.style = `background: ${c}`; newColor.innerHTML = 'New: '+color newColor.style = `background: ${color}`; } update(); .box{ width: 100px; height: 100px; margin: 10px; display: inline-block} <input id="col" value="#3F6D2A" oninput="update()"> <input id="amt" value="40" oninput="update()"><br> <div id="oldColor" class="box"></div> <div id="newColor" class="box"></div>

其他回答

下面是一个基于Eric的回答的超级简单的一行代码

function adjust(color, amount) {
    return '#' + color.replace(/^#/, '').replace(/../g, color => ('0'+Math.min(255, Math.max(0, parseInt(color, 16) + amount)).toString(16)).substr(-2));
}

例子:

adjust('#ffffff', -20) => "#ebebeb"
adjust('000000', 20) => "#141414"

我一直希望能够产生色彩的色调/深浅,这是我的JavaScript解决方案:

const varyHue = function (hueIn, pcIn) {
    const truncate = function (valIn) {
        if (valIn > 255) {
            valIn = 255;
        } else if (valIn < 0)  {
            valIn = 0;
        }
        return valIn;
    };

    let red   = parseInt(hueIn.substring(0, 2), 16);
    let green = parseInt(hueIn.substring(2, 4), 16);
    let blue  = parseInt(hueIn.substring(4, 6), 16);
    let pc    = parseInt(pcIn, 10);    //shade positive, tint negative
    let max   = 0;
    let dif   = 0;

    max = red;

    if (pc < 0) {    //tint: make lighter
        if (green < max) {
            max = green;
        }

        if (blue < max) {
            max = blue;
        }

        dif = parseInt(((Math.abs(pc) / 100) * (255 - max)), 10);

        return leftPad(((truncate(red + dif)).toString(16)), '0', 2)  + leftPad(((truncate(green + dif)).toString(16)), '0', 2) + leftPad(((truncate(blue + dif)).toString(16)), '0', 2);
    } else {    //shade: make darker
        if (green > max) {
            max = green;
        }

        if (blue > max) {
            max = blue;
        }

        dif = parseInt(((pc / 100) * max), 10);

        return leftPad(((truncate(red - dif)).toString(16)), '0', 2)  + leftPad(((truncate(green - dif)).toString(16)), '0', 2) + leftPad(((truncate(blue - dif)).toString(16)), '0', 2);
    }
};

我在TypeScript中把这个答案https://stackoverflow.com/a/13542669/4537906重写成一对可读的函数。

原因是在现代JavaScript中,我们不再需要关心保存字符。这是由编译器完成的。在我看来,我们的目标应该是编写可读性和可理解的代码。

这是我的方法:

tint.ts

type ColorObject = Record<"r" | "g" | "b" | "a", number>;
const singleColorSpace = 16 * 16; // 256
const blueSpace = singleColorSpace;
const greenSpace = blueSpace * singleColorSpace; // 65536
const redSpace = greenSpace * singleColorSpace; // 16777216
/* eslint-disable regex/invalid */
// adapted to TS from https://github.com/PimpTrizkit/PJs/wiki/12.-Shade,-Blend-and-Convert-a-Web-Color-(pSBC.js)
export const toColorObject = (rgbOrHex: string): ColorObject => {
    const { length } = rgbOrHex;
    const outputColor = {} as ColorObject;
    if (length > 9) {
        const rgbaColor = rgbOrHex.split(",");
        const [rgbaAndRed, green, blue, alpha] = rgbaColor;

        if (rgbaAndRed.slice(0, 3) !== "rgb") {
            throw new Error("Invalid color format");
        }
        const red = rgbaAndRed[3] === "a" ? rgbaAndRed.slice(5) : rgbaAndRed.slice(4);

        const rgbaLength = rgbaColor.length;
        if (rgbaLength < 3 || rgbaLength > 4) {
            return null;
        }
        outputColor.r = parseInt(red, 10);
        outputColor.g = parseInt(green, 10);
        outputColor.b = parseInt(blue, 10);
        outputColor.a = alpha ? parseFloat(alpha) : -1;
    } else {
        if (length === 8 || length === 6 || length < 4) {
            throw new Error("Invalid hex color format");
        }
        let HexColor = rgbOrHex;
        if (length < 6) {
            HexColor = `#${rgbOrHex[1]}${rgbOrHex[1]}${rgbOrHex[2]}${rgbOrHex[2]}${rgbOrHex[3]}${rgbOrHex[3]}${
                length > 4 ? rgbOrHex[4] + rgbOrHex[4] : ""
            }`;
        }
        if (length === 9 || length === 5) {
            const hexRed = parseInt(HexColor.slice(1, 3), 16);
            outputColor.r = hexRed;

            const hexGreen = parseInt(HexColor.slice(3, 5), 16);
            outputColor.g = hexGreen;

            const hexBlue = parseInt(HexColor.slice(5, 7), 16);
            outputColor.b = hexBlue;

            const hexAlpha = parseInt(HexColor.slice(7, 9), 16);
            outputColor.a = Math.round((hexAlpha / 255) * 100) / 100;
        } else {
            const hexRed = parseInt(HexColor.slice(1, 3), 16);
            outputColor.r = hexRed;

            const hexGreen = parseInt(HexColor.slice(3, 5), 16);
            outputColor.g = hexGreen;

            const hexBlue = parseInt(HexColor.slice(5, 7), 16);
            outputColor.b = hexBlue;

            outputColor.a = -1;
        }
    }
    return outputColor;
};

const black: ColorObject = { r: 0, g: 0, b: 0, a: -1 };
const white: ColorObject = { r: 255, g: 255, b: 255, a: -1 };
export const tint = (
    ratio: number,
    inputColor: string,
    { toColor, useLinear, reformat }: { toColor?: string; useLinear?: boolean; reformat?: boolean } = {}
) => {
    const { round } = Math;
    const clampedRatio = Math.min(Math.max(ratio, -1), 1);
    if (ratio < -1 || ratio > 1) {
        // eslint-disable-next-line no-console
        console.info(`Ratio should be between -1 and 1 and it is ${ratio}. It will be clamped to ${clampedRatio}`);
    }
    let baseColor = inputColor;
    if (inputColor[0] !== "r" && inputColor[0] !== "#") {
        baseColor = "#000";
        // eslint-disable-next-line no-console
        console.info(
            `Invalid input color format. "${inputColor}" should be rgb(a) or hex. It will fallback to "${baseColor}"`
        );
    }
    let isRGBformat = baseColor.length > 9 || baseColor.includes("rgb(");
    isRGBformat = reformat ? !isRGBformat : isRGBformat;

    if (toColor) {
        const isToColorRgbFormat = (toColor && toColor?.length > 9) || toColor?.includes("rgb(");
        isRGBformat = reformat ? !isToColorRgbFormat : isToColorRgbFormat;
    }
    const formattedBaseColor = toColorObject(baseColor);
    const isNegativeRatio = clampedRatio < 0;
    const toColorDefault = isNegativeRatio ? black : white;
    const formattedToColor = toColor && !reformat ? toColorObject(toColor) : toColorDefault;
    const toColorRatio = Math.abs(clampedRatio);
    const baseRatio = 1 - toColorRatio;

    const outputColor = {} as ColorObject;
    if (useLinear) {
        outputColor.r = round(baseRatio * formattedBaseColor.r + toColorRatio * formattedToColor.r);
        outputColor.g = round(baseRatio * formattedBaseColor.g + toColorRatio * formattedToColor.g);
        outputColor.b = round(baseRatio * formattedBaseColor.b + toColorRatio * formattedToColor.b);
    } else {
        outputColor.r = round((baseRatio * formattedBaseColor.r ** 2 + toColorRatio * formattedToColor.r ** 2) ** 0.5);
        outputColor.g = round((baseRatio * formattedBaseColor.g ** 2 + toColorRatio * formattedToColor.g ** 2) ** 0.5);
        outputColor.b = round((baseRatio * formattedBaseColor.b ** 2 + toColorRatio * formattedToColor.b ** 2) ** 0.5);
    }

    const blendedAlpha = formattedBaseColor.a * baseRatio + formattedToColor.a * toColorRatio;

    outputColor.a = formattedToColor.a < 0 ? formattedBaseColor.a : blendedAlpha;

    const hasAlpha = formattedBaseColor.a >= 0 || formattedToColor.a >= 0;
    if (isRGBformat) {
        return `rgb${hasAlpha ? "a" : ""}(${outputColor.r},${outputColor.g},${outputColor.b}${
            hasAlpha ? `,${round(outputColor.a * 1000) / 1000}` : ""
        })`;
    }
    return `#${(
        outputColor.r * redSpace +
        outputColor.g * greenSpace +
        outputColor.b * blueSpace +
        (hasAlpha ? round(outputColor.a * 255) : 0)
    )
        .toString(16)
        // If no Alpha, we remove the last 2 hex digits
        .slice(0, hasAlpha ? undefined : -2)}`;
};

还有一个笑话测试的集合

tint.test.ts

import { tint, toColorObject } from "./tint";

const rgbBlue = "rgb(20,60,200)";
const rgbaBlue = "rgba(20,60,200,0.67423)";
const hex6Cyan = "#67DAF0";
const hex3Pink = "#F3A";
const hex4Pink = "#F3A9";
const rbgBrown = "rgb(200,60,20)";
const rgbaBrown = "rgba(200,60,20,0.98631)";

describe("tint", () => {
    describe("Logarithmic blending", () => {
        describe("Shades", () => {
            it("lightens rgb color", () => {
                expect(tint(0.42, rgbBlue)).toEqual("rgb(166,171,225)");
            });
            it("darkens hex color", () => {
                expect(tint(-0.4, hex3Pink)).toEqual("#c62884");
            });
            it("lightens rgba color", () => {
                expect(tint(0.42, rgbaBrown)).toEqual("rgba(225,171,166,0.986)");
            });
            it("returns black with ratio -1", () => {
                expect(tint(-1, rgbBlue)).toEqual("rgb(0,0,0)");
            });
        });
        describe("converts color notation", () => {
            it("converts from rgba to hexa", () => {
                // expect(tint(0.42, color2, "c")).toEqual("#a6abe1ac");
                expect(tint(0.42, rgbaBlue, { reformat: true })).toEqual("#a6abe1ac");
            });
            it("converts from hexa to rgba", () => {
                // expect(tint(0, color6, "c", true)).toEqual("rgba(255,51,170,0.6)");
                expect(tint(0, hex4Pink, { reformat: true })).toEqual("rgba(255,51,170,0.6)");
            });
            it("converts and returns white with ratio 1", () => {
                expect(tint(1, hex3Pink, { reformat: true })).toEqual("rgb(255,255,255)");
            });
        });
        describe("Blends two colors", () => {
            it("blends rgba with rgba", () => {
                expect(tint(-0.5, rgbaBlue, { toColor: rgbaBrown })).toEqual("rgba(142,60,142,0.83)");
            });
            it("blends rgba with rgb", () => {
                expect(tint(0.7, rgbaBlue, { toColor: rbgBrown })).toEqual("rgba(168,60,111,0.674)");
            });
            it("blends hex with rgb", () => {
                expect(tint(0.25, hex6Cyan, { toColor: rbgBrown })).toEqual("rgb(134,191,208)");
            });
            it("blends rgb with hex", () => {
                expect(tint(0.75, rbgBrown, { toColor: hex6Cyan })).toEqual("#86bfd0");
            });
        });
    });
    describe("Linear Blending", () => {
        describe("Shades", () => {
            it("lightens rgb color", () => {
                expect(tint(0.42, rgbBlue, { useLinear: true })).toEqual("rgb(119,142,223)");
            });
            it("darkens hex color", () => {
                expect(tint(-0.4, hex3Pink, { useLinear: true })).toEqual("#991f66");
            });
            it("lightens rgba color", () => {
                expect(tint(0.42, rgbaBrown, { useLinear: true })).toEqual("rgba(223,142,119,0.986)");
            });
            it("returns black with ratio -1", () => {
                expect(tint(-1, rgbBlue, { useLinear: true })).toEqual("rgb(0,0,0)");
            });
        });
        describe("converts color notation", () => {
            it("converts from rgba to hexa", () => {
                expect(tint(0.42, rgbaBlue, { reformat: true, useLinear: true })).toEqual("#778edfac");
            });
            it("converts from hexa to rgba", () => {
                expect(tint(0, hex4Pink, { reformat: true, useLinear: true })).toEqual("rgba(255,51,170,0.6)");
            });
            it("converts and returns white with ratio 1", () => {
                expect(tint(1, hex3Pink, { useLinear: true, reformat: true })).toEqual("rgb(255,255,255)");
            });
        });
        describe("Blends two colors", () => {
            it("blends rgba with rgba", () => {
                expect(tint(-0.5, rgbaBlue, { toColor: rgbaBrown, useLinear: true })).toEqual("rgba(110,60,110,0.83)");
            });
            it("blends rgba with rgb", () => {
                expect(tint(0.7, rgbaBlue, { toColor: rbgBrown, useLinear: true })).toEqual("rgba(146,60,74,0.674)");
            });
            it("blends hex with rgb", () => {
                expect(tint(0.25, hex6Cyan, { toColor: rbgBrown, useLinear: true })).toEqual("rgb(127,179,185)");
            });
            it("blends rgb with hex", () => {
                expect(tint(0.75, rbgBrown, { toColor: hex6Cyan, useLinear: true })).toEqual("#7fb3b9");
            });
        });
    });
    describe("Error handling", () => {
        describe("When invalid hex color provided", () => {
            it.each([1, 2, 5])("throws error if hex color has %s characters", (n) => {
                const correlativeNumbers = Array.from(Array(n).keys()).join("");
                expect(() => tint(0, `#${correlativeNumbers}`)).toThrow("Invalid hex color format");
            });
        });

        describe("When ratio is not between -1 and 1", () => {
            it("clamps ratio to -1", () => {
                expect(tint(-43, rgbBlue)).toEqual("rgb(0,0,0)");
            });
            it("clamps ratio to 1", () => {
                expect(tint(42, rgbBlue)).toEqual("rgb(255,255,255)");
            });
        });
    });
});

describe("toColorObject function", () => {
    it("should return a color object from hex", () => {
        expect(toColorObject("#fff")).toEqual({
            r: 255,
            g: 255,
            b: 255,
            a: -1,
        });
    });
    it("should return a color object from hex with alpha", () => {
        expect(toColorObject("#fff6")).toEqual({
            r: 255,
            g: 255,
            b: 255,
            a: 0.4,
        });
    });
    it("should return a color object from rgb", () => {
        expect(toColorObject("rgb(255,255,255)")).toEqual({
            r: 255,
            g: 255,
            b: 255,
            a: -1,
        });
    });
    it("should return a color object from rgba", () => {
        expect(toColorObject("rgba(255,255,255,1)")).toEqual({
            r: 255,
            g: 255,
            b: 255,
            a: 1,
        });
    });
    describe("Error handling", () => {
        it("should throw error if invalid color provided", () => {
            expect(() => toColorObject("foo")).toThrow("Invalid hex color format");
        });
        it("should throw error if invalid color provided", () => {
            expect(() => toColorObject("invalid color")).toThrow("Invalid color format");
        });
    });
});

希望你喜欢。这很简单,但效果很好

如何简单的阴影颜色在PHP?

<?php
function shadeColor ($color='#cccccc', $percent=-25) {

  $color = Str_Replace("#",Null,$color);

  $r = Hexdec(Substr($color,0,2));
  $g = Hexdec(Substr($color,2,2));
  $b = Hexdec(Substr($color,4,2));

  $r = (Int)($r*(100+$percent)/100);
  $g = (Int)($g*(100+$percent)/100);
  $b = (Int)($b*(100+$percent)/100);

  $r = Trim(Dechex(($r<255)?$r:255));  
  $g = Trim(Dechex(($g<255)?$g:255));  
  $b = Trim(Dechex(($b<255)?$b:255));

  $r = ((Strlen($r)==1)?"0{$r}":$r);
  $g = ((Strlen($g)==1)?"0{$g}":$g);
  $b = ((Strlen($b)==1)?"0{$b}":$b);

  return (String)("#{$r}{$g}{$b}");
}

echo shadeColor(); // #999999

在David Sherret和Pablo的基础上,上面的答案将解决方案转换为更安全的Typescript版本

/**
 * @param color Hex value format: #ffffff or ffffff
 * @param decimal lighten or darken decimal value, example 0.5 to lighten by 50% or 1.5 to darken by 50%.
 */
static shadeColor(color: string, decimal: number): string {
    const base = color.startsWith('#') ? 1 : 0;

    let r = parseInt(color.substring(base, 3), 16);
    let g = parseInt(color.substring(base + 2, 5), 16);
    let b = parseInt(color.substring(base + 4, 7), 16);

    r = Math.round(r / decimal);
    g = Math.round(g / decimal);
    b = Math.round(b / decimal);

    r = (r < 255)? r : 255;
    g = (g < 255)? g : 255;
    b = (b < 255)? b : 255;

    const rr = ((r.toString(16).length === 1)? `0${r.toString(16)}` : r.toString(16));
    const gg = ((g.toString(16).length === 1)? `0${g.toString(16)}` : g.toString(16));
    const bb = ((b.toString(16).length === 1)? `0${b.toString(16)}` : b.toString(16));

    return `#${rr}${gg}${bb}`;
}