Hex to grayscale by lightness
Turn a hex color into gray the HSL way: #e74c3c has 231 as its highest channel and 60 as its lowest, so the lightness is (231 + 60) / 2 = 145.5 and the gray is #929292. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Color
- #e74c3c
- Value
- 146
- Input hex
- #e74c3c
- Input rgb
- 231, 76, 60
- Resistance (Ω)
- 231
A hex to grayscale by lightness converter maps one opaque hex color onto a single neutral gray using the classic HSL lightness definition: the average of the maximum and minimum red, green, and blue channels. Paste #e74c3c, #3498db, or three-digit shorthand such as #f0a; the tool expands the hex, reads each channel as an integer from zero through two hundred fifty-five, computes L equals max plus min over two, rounds to the nearest gray byte, and returns the gray hex triple, the numeric value, a CSS rgb() string, the max and min channels, and step-by-step arithmetic.
Why HSL lightness differs from luminosity grayscale
There is more than one standard way to collapse a color into gray, and picking the wrong formula silently changes contrast, print mockups, and monochrome themes. HSL lightness treats the brightest and darkest channels as the only inputs that matter: L equals the average of the maximum channel and the minimum channel among red, green, and blue.
Pure red #ff0000, pure green #00ff00, and pure blue #0000ff all share max two hundred fifty-five and min zero, so all three map to the same mid-gray under lightness even though they look very different to the eye. Luminosity weighting, by contrast, multiplies channels by fixed BT.601 coefficients that emphasize green and de-emphasize blue, so pure green becomes a lighter gray than pure blue. Neither method is wrong; they answer different search intents.
People who type hex to grayscale by lightness, HSL desaturate to gray, or max min average gray converter are asking for the HSL definition, not the television luma formula. This landing implements only the lightness path, documents the formula in every successful response, and leaves luminosity conversion to the sibling color to grayscale converter that uses weighted coefficients.
Classroom exercises and coding interviews often specify lightness explicitly as max plus min over two; having a deterministic reference removes ambiguity about whether channels were normalized to zero through one first, how half-integers are rounded, and whether three-digit hex shorthand was expanded before taking max and min.
Practical tips, limits, and related searches
Remember that lightness treats pure primaries as equally bright: if your product needs green-weighted perceived brightness, use the luminosity grayscale converter instead of this page. Do not pass alpha forms such as #RRGGBBAA—this landing converts opaque hex only, and unexpected lengths are rejected. Named CSS colors and rgb() strings should be resolved to hex first, then passed here, so the validation surface stays a single well-specified color string.
This page targets people searching for hex to grayscale by lightness, HSL lightness gray converter, max min average gray from hex, or free desaturate hex by lightness online; it is not a full image desaturator, not a multi-space converter for LAB or CMYK, and not a palette generator.
Prefer this capability when you already have one hex token and only need its HSL-lightness gray hex and integer value; if your pipeline must still emit HSL components, hue, or saturation, use a hex to HSL converter for those fields and this tool for the monochrome step.
What you can do with it
Monochrome tokens along the HSL axis
Designers paste brand hex codes and receive HSL-lightness gray hex values for monochrome themes that must match CSS desaturate-to-lightness behavior rather than luminosity weights.
Compare lightness vs luminosity grays
Convert the same hex with this tool and a luminosity converter to document how pure primaries diverge, then pick the method your design system documents.
FAQ
What formula does hex to grayscale by lightness use?
HSL lightness on 8-bit channels: L = (max(R,G,B) + min(R,G,B)) / 2, rounded to the nearest integer from 0 through 255. The gray hex repeats that byte three times as #YY.
How is this different from luminosity grayscale?
Lightness averages only the brightest and darkest channels. Luminosity weights R, G, and B (classically 0.299, 0.587, 0.114). Pure red, green, and blue share the same lightness gray but not the same luminosity gray.
Which color formats are accepted?
Hex #RGB or #RRGGBB with optional leading #, case-insensitive. Alpha hex, named CSS colors, and rgb() strings are not accepted on this landing.
Is hex to grayscale by lightness free?
The browser tool is free and runs locally.
What gray does #e74c3c give by lightness?
It gives #929292. Its channels are 231, 76 and 60; the highest and lowest are averaged, (231 + 60) / 2 = 145.5, and rounded to a gray value of 146.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/color/grayscale-lightness \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"color":"#e74c3c"}'const res = await fetch("https://api.kit.forhosting.com/color/grayscale-lightness", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"color": "#e74c3c"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/color/grayscale-lightness",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"color": "#e74c3c"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/color/grayscale-lightness", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"color":"#e74c3c"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"color":"#e74c3c"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/color/grayscale-lightness", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"color": "#e74c3c"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "color.grayscale_lightness",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Invalid color strings—empty input, wrong hex length, non-hex characters, a programming 0x prefix, or a missing field—fail with a clear invalid_input error instead of inventing a swatch.
How to call the API and what comes back
Surrounding whitespace is trimmed, hex letters may be upper or lower case, and the leading hash is optional. Only three-digit and six-digit hexadecimal bodies are accepted; eight-digit forms with alpha, named CSS colors such as rebeccapurple, rgb() function strings, and separate numeric channel fields are out of scope for this string-focused contract and will be rejected so you notice rather than silently dropping alpha or inventing a parse. Send a JSON body with a required color string. The color field accepts aliases hex, value, text, input, and code; valid examples include #e74c3c, e74c3c, #abc, and ABC. On success the response returns input_hex and input_rgb for the resolved source, integer gray and aliases gray_value and value, gray_hex and hex as the six-digit neutral code, gray_rgb as a three-element array, css as rgb(g, g, g), max_channel and min_channel, lightness as the pre-round average with fixed display precision, formula restating L equals max plus min over two, method equal to hsl_lightness, message as a short English summary, and steps as an ordered array of substitution lines for teaching or debugging. Failed validation—missing color, empty string, wrong hex length, non-hex characters, or a programming 0x prefix—returns invalid_input and is never charged. Pricing is a flat $0.002 per successful request with unit item. Prefer sending the exact token your design tool exported, including the hash if you have it; the response always normalizes the source to a lowercase six-digit input_hex so downstream diffs stay stable across clipboard formats.
Practical tips, limits, and related searches
Failed tasks that return invalid_input do not consume prepaid balance, which keeps exploratory scripts and form validation cheap while learners paste imperfect clipboard values. Pin the rounded gray and the gray_hex in automated tests so a future change to rounding policy cannot pass silently, and document that method is hsl_lightness when you store results next to luminosity-based grays from other systems.
Integration use cases
Unit tests for lightness desaturation
Generate known-good gray values from hex fixtures so theme engines assert stable (max+min)/2 math and catch regressions when switching from luminosity formulas.
Technical questions
What happens on an invalid color string?
The API returns invalid_input with a message describing the problem (empty input, bad hex length, non-hex characters, 0x prefix, and so on). Failed validation is not charged.