Ian Marshall


Lesson 2: Units and Colors

Your browser window is a rectangle. It could be wider than tall, or taller than wide. Or, rarely, perfectly square. If I asked you to design a paper-printed poster for all possibilities, from extremely tall and narrow to extremely wide and squat, you'd think I was out of my mind. There are literally millions of different configurations! But when designing a website, you must consider all screen sizes, aspect ratios, and pixel depths. Designing for a browser is nothing like designing for print. Imagine a painter working with a canvas made of rubber, and that canvas is being held by a bunch of primates who cannot stop themselves from gleefully stretching it in different directions. That's sort of what it's like to design for the web.

Since we have no advance knowledge of the exact width and height of the browser window when the user opens our web page, we must use variables. These variable measurements are called relative units because their values are dependent on another value, one that can change at any time—like the width and height of the browser window. Sometimes, however, we may want to size something exactly, independent of the changing environment. For example, a font size, or a logo image, or a data table. For these occasions we still do have use of print designers' measurements called absolute units, which are not dependent on any browser variables. With both, we'll be able to position and size anything for a "rubber" browser window.

One other measurement value will help us make everything pretty. Or glaringly ugly. On web pages, colors are assigned by color values. Sometimes the value is a word, like "yellow," but usually colors are defined by numbers, either base ten or base sixteen (hex).

Relative Units

Relative units are based on some other measurement. If you want twice as much, the obvious question is, "twice as much as what? How much are you starting with?" In algebra you can just double an unknown. In CSS, too, you can do this, relying on the rendering engine to find the exact value to double, sometimes from a font size, or sometimes from the width or height of an element or the viewport itself.

Relative to Font Size

Let's start with the relative units in CSS that relate to font size and font family. For example, any single font at a specific size will have measurable widths and heights of every character.

UnitRelative Measurement
exheight of the lowercase "x" character
chwidth of the number "0" character

Change the font family and/or the font size and the ex and ch units will change accordingly. The ex and ch units are seldom used, however, because they're dependent on two values: font and font size. Perhaps more useful are the following:

UnitRelative Measurement
em1em is 100% of the inherited font size
rem1rem is 100% of the root font size

If, for a particular HTML element, the font-size is sixteen pixels, then 1em or 1rem will be sixteen pixels, 2em or 2rem will be thirty-two pixels, and 0.5em or 0.5rem will be eight pixels. These units are often used to scale font sizes so a primary headline, for example, is always twice the font size of paragraph text, no matter what size paragraph text is set to. The difference between em and rem is that em units can freely change throughout an HTML document as child elements may inherit font sizes from ancestor elements, but rem units are based on a single, document-wide font size declaration. We'll discuss the benefits of each in the next chapter, Text.


Font Size: 16px

ex units: 0.5ex1ex1.5ex2ex
ch units: 0.5ch1ch1.5ch2ch
em or rem units: 0.5em1em1.5em2em

Relative to the Viewport

Since we're dealing with an elastic viewport and designing for all aspect ratios (the ratio of width and height), it makes sense to have a unit that measures the width and height of the viewport at any given time. If the user rotates from portrait to landscape mode on a mobile device, or perhaps goes to fullscreen mode on a desktop browser, we want CSS to adjust appropriately. Our design needs to look good always.

Luckily, we have just the units we need.

UnitRelative Measurement
1vw1% of the current viewport width
1vh1% of the current viewport height
1vmin1% of the current viewport width or height, whichever is lesser
1vmax1% of the current viewport width or height, whichever is greater

Below are three ovals with specific widths and heights based on the viewport. Change the aspect ratio of your browser by making it taller or wider—or squarer.

1 2 3

1: { width: 10vw; height: 10vh; }
2: { width: 10vmin; height: 10vmax; }
3: { width: 10vmax; height: 10vmin; }

Relative to Parent Element

Percentage units (%) are used to measure distance, width or height, of an ancestor element like a parent. For example, if one HTML container is 300px wide and it has a child with width: 50%, then that child will have a width of 150px.

Sounds easy enough, but there are pitfalls. Parent elements without an explicit width or height will look to inherit from their parents, and so on. We get a series of nested boxes like Russian dolls. If there are no parents with an explicit width or height, then the HTML body's width and height will be used, which by default is slightly less than the entire viewport's width and height—but defaults vary from one browser to another. Also, percentages are cumulative. A child at 50% of its parent—which is 50% of its parent—will actually be 25% of its grandparent.

Additionally, height is notoriously difficult to manage using percentage units. This is because unless an explicit height is assigned to an element, its height will be defined by the content within it and set to a value of auto. Unfortunately, it's impossible to find fifty percent of auto, so height performs somewhat irrationally.

See Lesson 4: Box Model for more.

Outer Box: width: 90%
height: 90%
Middle Box: width: 90%
height: 90%
Inner Box: width: 90%
height: 90%

Absolute Units

Don't expect any sliders, buttons, or other interactives in this section. Absolute units are preset, and not dependent on anything. You cannot change a kilometer or a fluid ounce, for example, and you cannot change these units, either.

CSS and UnitAbsolute MeasurementProduces This Width
width: 1in;1 inch
width: 1cm;1 centimeter
width: 1mm;1 millimeter
width: 1pt;1 point (or 1⁄72 inch)
width: 1pc;1 pica (or 1⁄6 inch)
width: 1px;1 pixel (or 1⁄96 inch)

So what good are these unchanging units? Well, some HTML elements aren't supposed to adjust to the changing sizes and dimensions all around them. A video, for example, needs to play at a specific width and height—and stay at that size for its duration. Certain images like corporate logos sometimes fit into this category, as do graphs, charts, and tables that will not be able to convey information properly if too big or too small.

Most text also is set using absolute units. We'll deal more with typography in Lesson 3: Text.

There are other things that can be measured beside length or size, and they also have absolute units:

Time/Duration: used for timing animations
UnitAbsolute Measurement
1s1 second
1ms1 millisecond
Angles: used for arcs and colors
UnitAbsolute Measurement
1deg1 degree
1rad1 radian
1grad1 gradian
1turn1 turn (360°)
Pixel Density: used for screen resolution
UnitAbsolute Measurement
dpidots per inch
dpcmdots per centimeter
dppxdots per pixel

Pixel units of length (px) are very common, and they'll appear throughout this course. We'll discuss the timing measurements (s and ms) later in Lesson 8: Events and Effects. And we'll use degrees (deg) below with colors. I won't be bringing up the rest in this course, however.


Zero requires no unit. If the measurement is zero of something, it's zero of everything. For example, width: 0 is the same as width: 0px, which is the same as width: 0em, which is the same as width: 0%. Zero more on that subject.

Color Values

This paragraph text is black. That's the default value for text color, so I didn't have to do anything to change it. But I could have. It could have been green or blue or even peru. Wait, what? Yup, peru is an actual CSS color.

This text is peru color!

And here's how you'd use it on all paragraphs in CSS:

I don't at all recommend using peru color against a white background. There's not enough contrast for people with less-than-perfect vision. (I've actually added the tiniest of drop shadows to the text to make it more readable—we'll learn how to do that in Lesson 3: Text.) Color contrast is very important, and I'll discuss style and web design considerations in another course. But in the meantime, I'll show you peru against another color with a weird name (also not high enough contrast).

This text is peru color!

Wait…papayawhip is a color? Yup. Here's a great resource for seeing all the current named CSS colors. But it's a finite list, easily exhausted by a discerning web designer.

While it's great to have three different cyans to choose from:


There must be thousands, if not millions of colors in between each of these cyans.


And there are. They just don't have names. They're measured by the mixture of primary colors that go into making it. And I don't mean the red-blue-yellow primary colors you learned about in kindergarten. Those are the primary colors for subtractive color mixing only: ink, toner, paint, pigments, etc. When dealing with light, we need to use additive color mixing only: computer monitors, smart phones, televisions, theatrical lighting, etc. And the primary colors for additive color mixing are red-green-blue, or rgb.

No need to get into too much depth, but in computer systems a color value is represented by a triplet of binary bytes, each broken into two parts, each part representing the range 0–15. In an effort to represent 0–15 as a single digit, the number is often converted into a base 16, or hexadecimal (hex) value. The numbers zero through nine understandably represent 0–9, while the letters A–F (either uppercase or lowercase) represent 10–15. Two hex digits, then, represent the decimal range of 0 (00 in hex) through 255 (FF in hex). Set three pairs together (usually preceded by a hashtag) and you get values for red (first two digits), green (second two digits), and blue (last two digits).

Hex ValueRedGreenBlueColor Result

It is possible to use a shortened, three-digit hex value if each of red, green, and blue is represented by a double of the same digit.

6-digit Hex3-digit HexColor Result

Remember that the hex letters can be uppercase or lowercase.

Hex: #000000

Color Functions

Hex values (and color names, if available) are very common for defining colors. But if you'd like to stick with a decimal system that doesn't use letters for numbers, then you're in luck. You can define the values of red, green, and blue, each in the range of 0–255, using a CSS color function.

rgb Color FunctionRed ValueGreen ValueBlue ValueColor Result
rgb(143, 21, 14)1432114
rgb(94, 201, 188)94201188
rgb(37, 246, 112)37246112
rgb(225, 236, 66)22523666

Syntactically, the parentheses make this color measurement a function. That is, the set of numbers you provide for red, green, and blue values is first converted into another format by the rendering engine before displaying the color. The engine is very, very good at this, however, so the addition of the extra step is a negligible hit to efficiency.

Using rgb() mixes color values together before rendering. But there's another way of defining colors, one that is intended to represent colors more as we humans see them rather than as a mixture of primary colors we don't actually see. For example, picture a circular rainbow of gradients.

Since it's a circle, we can think of colors as degrees on this wheel. Red is 0deg (or just 0), yellow is 60deg, lime green is 120deg, etc. But are we stuck with lime green, for example? No, of course not. We'll have to add some white or black or grey to the lime green to produce a new color from a hue of 120 degrees. We represent tints (adding white) and shades (adding black) and saturation (adding grey) to a color using the hsl system.

By HSL_color_solid_cylinder.png: SharkDderivative work: SharkD  Talk 
- HSL_color_solid_cylinder.png, CC BY-SA 3.0, Link

HSL can measure any CSS color. The hue value (H) represents the angle on the color wheel. Remember that red is 0deg, etc. The other values are measured as a percentage. The saturation value (S) changes the amount of medium grey there is in the color. A high saturation produces a more vibrant color, a low saturation produces a grey, washed-out color. A saturation of 100% doesn't change the color from the color wheel. The lightness value (L) changes the amount of white and black. A high lightness has more white, a low lightness has more black. A lightness of 50% doesn't change the color from the color wheel at all. So a true lime green, for example, would be hsl(120deg, 100%, 50%).

rgb(0, 0, 0)

hsl(0deg, 0%, 0%)

Like most new technologies, a lot of tinkering is required to understand color values. Until such time as you can see a color and intuit its values or, in reverse, read values and see that color in your head, you can always look it up. Or use a color picker like the ones above.


Both of the color functions we explored above have the means to change a color's opacity, or how much of any colors underneath it show through. Opacity, or conversely transparency, is measured by a color's alpha value, which is a normalized value in the range of 0–1. So an alpha of 0 is completely transparent, an alpha of 1 is completely opaque, and an alpha of 0.5 is exactly semi-transparent.

While opacity cannot be set using named colors, and not all browsers support using alpha with hex values, it's very easy to adjust opacity with color functions. You can simply use rgba or hsla ("a" for alpha) and add a fourth number to the list in parentheses:

rgbahslaColor Result
rgba(255, 0, 0, 0.1)hsla(0deg, 100%, 50%, 0.1)
rgba(255, 0, 0, 0.2)hsla(0deg, 100%, 50%, 0.2)
rgba(255, 0, 0, 0.3)hsla(0deg, 100%, 50%, 0.3)
rgba(255, 0, 0, 0.4)hsla(0deg, 100%, 50%, 0.4)
rgba(255, 0, 0, 0.5)hsla(0deg, 100%, 50%, 0.5)
rgba(255, 0, 0, 0.6)hsla(0deg, 100%, 50%, 0.6)
rgba(255, 0, 0, 0.7)hsla(0deg, 100%, 50%, 0.7)
rgba(255, 0, 0, 0.8)hsla(0deg, 100%, 50%, 0.8)
rgba(255, 0, 0, 0.9)hsla(0deg, 100%, 50%, 0.9)
rgba(255, 0, 0, 1)hsla(0deg, 100%, 50%, 1)

Gradient Functions

Notice the black rectangle above…the one with the black–white color gradient? It's an effective tool for showing opacity. And for segueing into gradients! Here's the code I used:

The above code creates a linear gradient and starts with a direction, then lists out color stops. We'll be moving to the left (from the right), and at 0px (the right edge) we'll have black. We'll also have black at 90px, which means the right-most ninety pixels will be solid black without any gradation. But at 140px (from the right edge) we'll have solid white. So between ninety and one-forty we'll have a gradient from black to white. There are no other color stops, so the rest of the background will be white.

You can get very creative with gradients.

CSS GradientColor Result
background: linear-gradient(black, navy, cyan)
background: linear-gradient(45deg, goldenrod, gold, gold, lightgoldenrodyellow, goldenrod, goldenrod)
background: linear-gradient(to top, indigo, magenta, darkmagenta, magenta, white, darkmagenta)
background: linear-gradient(to right, green 30px, lime 30px, honeydew)
background: linear-gradient(-50deg, black 20%, white 22%, silver 25%, black 50%, silver 75%, white 78%, black 80%)


  1. The default direction is top to bottom.
  2. For angle, you can use keywords to top, to right, to bottom, or to left, or use angle measurements (even negative angles).
  3. You can list a color multiple times in a row, which produces a solid color between those stops.
  4. You can use any color value: named colors, hex, rgb, rgba, hsl, or hsla.
  5. If one color stops at exactly the same place another starts, there will be no gradient between them.
  6. You can use any unit: pixels, percentages, etc.

As if that's not cool enough, you can use a repeating linear gradient!

CSS GradientColor Result
background: repeating-linear-gradient(red 0, red 10px, yellow 20px)
background: repeating-linear-gradient(15deg, pink 0, hotpink 25px, pink 50px)
background: repeating-linear-gradient(70deg, black 0, black 20px, yellow 20px, yellow 30px)
background: repeating-linear-gradient(to right, powderblue 0, powderblue 49px, darkturquoise 49px, darkturquoise 50px)
background: repeating-linear-gradient(-45deg, olive, seagreen 15px)


  1. With a repeating gradient, the end of a gradient pattern acts as if it were at 0px, and continues until the entire background is filled.

This is just too much fun: all of this coolness can be done with a radial gradient!

CSS GradientColor Result
background: radial-gradient(red, pink, crimson, pink, brown, orchid)
background: radial-gradient(circle at right bottom, white 20%, teal 25%, white 45%, mediumaquamarine, black 100%)
background: radial-gradient(circle closest-side, chocolate, burlywood, bisque, papayawhip, peru, blanchedalmond, saddlebrown, brown)
background: radial-gradient(circle at top left, yellow 15%, orange 25%, skyblue 60%)
background: radial-gradient(farthest-side at right center, gold, yellow, white, orange, purple, black)


  1. The default radial shape is an ellipse, following the aspect ratio of the element's width and height.
  2. You can force a circular gradient by starting the function with the word circle.
  3. You can assign distances and percentages to radial gradients just as you can with linear gradients.
  4. You can change the origin point, or center of the ellipse/circle, with the at word followed by a distance offset from left, right, top, or bottom.
  5. You can constrain the size of the radial gradient, forcing it to stop as soon as it hits the closest-side, farthest-side, closest-corner, or farthest-corner.

You probably saw this one coming: repeating radial gradient!

CSS GradientColor Result
background: repeating-radial-gradient(darksalmon, darkviolet 50%)
background: repeating-radial-gradient(blue 10px, white 15px)
background: repeating-radial-gradient(circle at top left, white 0, white 10px, black 10px, black 20px)
background: repeating-radial-gradient(at bottom center, black 10px, red 30px)
background: repeating-radial-gradient(farthest-side at top 20px right 20px, palegreen, darkslategrey)


  1. Using closest-side or farthest-corner, etc., will force that stop to be the start of the next repeating gradient.

But you definitely did not see this one coming: you can have more than one! In fact, you can have as many as you like. Using stacked gradients as a part of multiple element backgrounds is a subject we'll discuss again in Lesson 5: Images. What's most important to remember is that the first item in the list of backgrounds will be on top of all the others, and the last will be underneath all the others.

CSS GradientColor Result
background: linear-gradient(to top, dodgerblue, aqua, lightcyan 30px, transparent 30px), radial-gradient(circle 100px at center 90%, gold, yellow, cyan)
background: radial-gradient(transparent, transparent, black), radial-gradient(10px at 45% 35%, green, transparent), radial-gradient(11px at 46% 49%, green, transparent), radial-gradient(13px at 51% 40%, green, transparent), white
background: radial-gradient(at bottom right, transparent 60%, black), radial-gradient(pink, transparent), linear-gradient(20deg, fuchsia, transparent 15%), radial-gradient(100px at left bottom, black 20%, blue 93%, cyan 99%, transparent 96%), radial-gradient(at left bottom, black 40%, white 45%, lightpink 50%, hotpink 52%, purple 58%, black 80%)


  1. What?! transparent is an actual color? Yes, yes it is. And it's useful when you're working with stacked gradients and you need one to show through another. It's also possible to use any rgba or hsla color with an alpha of zero.
  2. Much more boring, but much more useful: you can simply assign a solid color as a background. We'll discuss this more in Lesson 3: Text.

That last stacked gradient example has four radial gradients and one linear gradient! No images, just CSS code! You can create some amazing works of art, if you get to learn CSS. Okay, maybe works of art aren't must-know CSS, but still…cool, right?