I'd like to share with you a handy little code snippet that creates Material Design-like User Avatars.
I want to color code my users, so each name has to have a unique color. I've seen some lazy approaches that assign a color to each letter of the alphabet, but I want to include numbers and non-latin characters as well. So we need to find a way to support the whole unicode table.
But before we get there, let's start with something simple. The avatar itself. Burt's avatar, to be precise.
<p class="chip" aria-label="Burt's user picture">Burt</p> Burt
.chip {
--chip-size: 48px;
--bg-color: gray;
display: inline-block;
width: var(--chip-size);
height: var(--chip-size);
border-radius: 50%;
font-family: sans-serif;
font-size: 0;
font-weight: normal;
line-height: var(--chip-size);
text-align: center;
vertical-align: middle;
overflow: hidden;
color: white;
background: var(--bg-color);
&::first-letter {
font-size: calc(var(--chip-size) / 2);
}
}
Wait... why is his avatar inside a p
-tag? To show only his inital, we use the ::first-letter
pseudoclass, and that requires a paragraph.
Right now, Burt has just a boring grey circle. That makes him very sad, so let's give him some color!
Using traditional color models like Hex or RGB would require us to get a suited color by mixing three color channels while keeping track of the luminosity. But luckily there's also HSL. HSL stands for hue/saturation/lightness and lets us control these three values independently. That's perfect for us, because we can manage the contrast between background and font separately from the color itself by pre-defining saturation and lightness and then calculating a hue. The hue value represents a clockwise rotation of a color wheel. That means that any value between 0 and 360 produce an individual hue.
generateColor() {
let hsl = [
hueValue,
this.string.length > 0 ? "100%" : "0%",
"42%"
];
return "hsl(" + hsl.join() + ")";
}
Now we need hueValue
. But we only have the name. How do we get a color value from a plain old string?
A string is a series of characters, and each character has a numerical value in the unicode table. That's a nice start. We could simply add all the unicode positions, but we could end up with fairly large numbers. The only sensible numbers to feed into our hue value are between 0 and 360, so we're going to transform our value.
To prevent large numbers, we'll spin the color wheel for each character and go on to the next character from there. To spin the wheel (read: to serialize the position of our character value on a circle) we'll use some quick maths: the sine function. That gives us a number between -1 (270°) and 1 (90°). We use the absolute value of that to get rid of the negatives and multitply it with 360 to have a degree to for our HSL value.
let hash = 0;
for (let i = 0; i < this.string.length; i++) {
hash = Math.abs(
Math.sin(
this.string.charCodeAt(i) + hash
) * 360
)
}
There we go! We can generate a unique and seemingly random color value from any string while still maintaining its readability.
Burt is very happy now.
Here's the full codepen:
Top comments (0)