This page starts with what every property has in common: a definition, an initial value, and a place in a family of longhands and shorthands. It then covers the keywords every property accepts, and works through the properties that style text, lists and backgrounds, ending with the different ways of hiding an element. Box and layout properties belong to the layout page; fonts and color each get a topic of their own.
1. Anatomy of a property
The anatomy of a rule showed that a declaration is a property and a value. The property is the part with rules of its own. Each one is defined in a specification by a small table, and that table is the property's type signature. Here is the one for color, from CSS Color Level 4:
Most of the time only a few of those rows matter, but when a property seems to do nothing, one of them usually explains why.
| Row | What it tells you |
|---|---|
| Value | The grammar the value must match. A value that does not match is dropped, silently, as forgiving parsing describes. |
| Initial | What the property is when no style sheet sets it at all. |
| Applies to | Which elements respect it. list-style only affects list items; vertical-align only inline and table-cell boxes. A declaration on the wrong kind of element is valid and does nothing. |
| Inherited | Whether descendants receive the value automatically. |
| Animation type | Whether the value can change smoothly in a transition, or only snaps from one value to the next. |
Initial values are not default looks
The initial value belongs to the property, not to the element. The initial value of display is inline for every element there is. A paragraph is a block only because the user-agent style sheet says p { display: block; }. Keep the two apart: the specification defines initial values, the browser ships the user-agent sheet, and the next section shows keywords that reach for each one separately.
Inherited or not
Whether a property inherits is decided once, by the people who designed it, and the choice follows a clear pattern. Properties about text (color, the font properties, line-height, text-align, letter-spacing, list-style, visibility) inherit, because the words inside a paragraph should look like the paragraph without anyone repeating the rule on every em and a. Properties about the box itself (margin, padding, border, background, sizes, display) do not, because a border that every descendant copied would be chaos. The cascade page follows a value through inheritance in detail.
Learn properties in families
CSS level 1 had about fifty properties; today there are several hundred, and nobody memorizes them. Learn them in families that share a prefix and a purpose, learn each family's shorthand, and look up the rest on MDN. Notice which properties live on and which have been replaced; old tutorials are full of the second kind.
| Family | Examples | Taught |
|---|---|---|
| Text | text-align, line-height, text-decoration, text-wrap | Here, section 3 |
| Lists and counters | list-style, counter-reset, ::marker | Here, section 4 |
| Backgrounds | background-color, background-image, background-size | Here, section 5 |
| Box and layout | margin, padding, border, display, overflow, flex, grid | The box model and layout |
| Fonts | font-family, font-size, font-weight, @font-face | The Fonts topic (coming) |
| Color | color spaces, oklch(), color-mix(), contrast | The Color topic (coming) |
| Motion | transition, animation, transform | The Animation topic (coming) |
Longhands and shorthands
Many properties are not single settings at all. A shorthand is notation for setting several longhands at once. border-block-end: 1px solid currentColor sets three longhands, border-block-end-width, border-block-end-style and border-block-end-color. margin-inline: auto sets margin-inline-start and margin-inline-end. background sets eight.
The browser expands a shorthand when it parses it. It reads the tokens you wrote, works out which longhand each one belongs to, and then sets every other longhand to its initial value. That second step is what makes a shorthand both convenient and dangerous.
The shorthand reset trap
Here is the bug that the diagram predicts. A base rule gives every aside a subtle pattern; a later rule tints the warning variant:
The warning asides lose their pattern. The cascade did exactly what it was asked: the nested rule is more specific, and its shorthand set background-image back to none, along with the repeat and the position. Nothing in the second rule mentions the image, which is what makes the bug hard to see.
The fix is to set only the longhand you mean to change:
The rule of thumb: use a shorthand when you want a clean slate, and a longhand when you are adjusting something already styled. A hover state that writes background: crimson says "forget everything about this background"; one that writes background-color: crimson says "change the color". The same holds for border, font (which also resets line-height), text-decoration, list-style and every other shorthand.
Logical shorthands follow the same rules. padding-block: 1rem sets the block-start and block-end padding; padding-inline: 1rem 2rem sets the start and end separately. The layout page covers the box properties and their logical names.
2. The five global keywords
Every property, whatever its own grammar, also accepts five keywords. They do not name a value. They tell the cascade where to get the value from, which makes them the closest thing CSS has to reserved words.
| Keyword | Takes the value from | Typical use |
|---|---|---|
inherit | The parent element's computed value, even for a property that does not normally inherit | border-color: inherit to match a parent's border |
initial | The property's initial value from the specification, skipping the user-agent sheet too | A known, context-free starting point |
unset | inherit for an inherited property, initial for any other | "Act as if this declaration were not here" |
revert | The previous origin: in an author sheet, the user's style or else the user-agent's | Restore the browser's own look for an element |
revert-layer | The previous cascade layer | Fall back to what a lower layer said |
The differences show only when the five are compared on the same property in the same place. Suppose a link sits inside a paragraph whose color is navy, the user-agent gives links LinkText (the familiar blue), and a base layer has set a { color: tomato; }. A hover rule in a later layer could then write any of the five:
unset depends on whether the property inherits.Choose by what you mean. unset is the everyday one: "forget this declaration". revert is right when you deliberately want the browser's default back. initial and inherit are precise tools for specific cases. revert-layer belongs to layered style sheets, and the cascade page shows it at work. All five are Baseline widely available; revert-layer, the newest, arrived in every major browser in 2022.
A common surprise: p { display: initial; } turns a paragraph into an inline element, because inline is the initial value of display. If you wanted "a normal paragraph", you wanted revert.
The all property
The shorthand all covers every property except direction, unicode-bidi and custom properties, and accepts only the five keywords. It is the largest hammer in CSS. all: revert returns an element to the browser's defaults, which is useful for undoing a site-wide button style inside one widget that wants the native look, or for shielding a component from styles injected by a third party.
Use it sparingly. all resets focus outlines and every other helpful default along with the unwanted ones, so anything it removes that a reader relies on must be put back.
3. Text
Text properties shape the words on the page: their alignment, their spacing, the space between their lines, their decoration and the way they wrap. Most of them inherit, so set them on a high-level element such as body or article and let them flow down.
Color and text
The color property sets the color of an element's text, and every element has one. It also does more than that: its value is available everywhere as currentColor, and several properties use it by default. border-color and text-decoration-color both start as currentColor, so a border or an underline matches the text unless you say otherwise. SVG icons drawn with fill="currentColor" follow the text color too.
Set text and background colors together, and check the pair for contrast: body text needs a contrast ratio of at least 4.5 to 1 against its background under WCAG AA. A page that sets only a text color can end up unreadable on a reader whose browser or system supplies a different background. The accessibility quality covers contrast, and color spaces, color functions and palettes belong to the Color topic (coming).
Alignment and indentation
text-align aligns the lines of text inside a block. Prefer the logical keywords start and end to left and right, for the reason given in normal flow: in a right-to-left language, start is on the right. center suits short headings and captions, and works badly for paragraphs, because the ragged start of every line makes the eye hunt for the next one.
justify stretches the spaces in each line so both edges are straight. In a narrow column the stretched spaces line up into white "rivers" running down the paragraph, which hurts reading and is worse for readers with dyslexia. If you justify, give the browser more ways to fill a line: a generous measure, and hyphenation.
hyphens: auto depends on knowing the language, so it works only when the document declares one, as <html lang="en"> should. Without a language the browser does not hyphenate.
text-indent indents the first line of a block, the traditional way to mark a new paragraph in print. Measure it in em so it scales with the text: p + p { text-indent: 1.5em; } indents every paragraph that follows another, the book convention.
Line height
line-height sets the height of each line box, which is how CSS expresses the typographer's leading, the space between lines. It accepts a number, a length or a percentage, and the difference matters because of inheritance.
A length or percentage is turned into a fixed length on the element that declares it, and descendants inherit that length. A bare number is inherited as a number, and each element multiplies it by its own font size:
Around 1.5 suits body text; large headings read better tighter. WCAG expects a page to survive a reader raising line height to 1.5, so never build a layout that breaks when lines grow.
Spacing letters and words
letter-spacing adds space between characters and word-spacing between words. Both accept lengths; use em so the spacing grows with the text. A little extra letter spacing helps text set in capitals, which looks cramped at normal spacing:
Is letter-spacing kerning? No. Kerning adjusts particular pairs of letters by amounts the type designer chose: the A and V in "AV" tuck together, the o slides under the arm of a T. letter-spacing adds the same amount between every pair, which typographers call tracking. Browsers apply the font's kerning automatically; tracking, kerning and the other font features are covered in Size, spacing and measure and The details.
Transforming case
text-transform changes the case of the rendered text: uppercase, lowercase, capitalize (the first letter of every word, not only the first in a sentence) or none. It raises a fair question about separation of concerns: is changing the letters presentation, or is it changing the content?
The answer that works is to keep the text correct in the HTML and treat the transform as styling. Write "Getting started" in the markup and transform it to capitals in CSS, rather than typing "GETTING STARTED". The source stays readable, a redesign can drop the capitals with one line, and screen readers, which work from the source text, are less likely to read capitals as an abbreviation to be spelled out.
Whitespace and wrapping
Normal flow collapses runs of whitespace into one space and wraps lines wherever a space allows. white-space changes that. pre keeps every space and line break and never wraps, which is what the pre element's user-agent style uses. pre-wrap keeps whitespace but still wraps, good for user-entered text such as a message. nowrap collapses whitespace and never wraps, good for a short label that must stay on one line.
Long unbroken strings, such as URLs, hashes and long German compounds, can overflow a narrow column because they have nowhere to break. overflow-wrap: anywhere lets the browser break them at any character when there is no other choice. What happens to content that still does not fit, with overflow and text-overflow: ellipsis, is on the layout page.
Two newer values of text-wrap let the browser wrap more carefully than one line at a time:
text-wrap: balanceevens out the line lengths of a short block, so a two-line heading does not end with one stranded word. Browsers limit it to a few lines, so it is for headings, captions and pull quotes, not paragraphs. It is Baseline newly available, since 2024.text-wrap: prettytakes more care over a paragraph's last few lines, mainly to avoid a lone word on the final line. It is supported in Chromium browsers and Safari but is not yet Baseline.
Both are pure enhancements: a browser that does not know them wraps the text the ordinary way, so they can be used today without a fallback.
Vertical alignment
vertical-align positions an inline box relative to the line it sits in: baseline (the default), middle, top, bottom, text-top, text-bottom, sub, super, or a length. It applies only to inline-level boxes and table cells. It does not center a block inside its container, the most common thing people try it for; the layout page does that with flexbox and grid.
Its real uses are small ones: lining up an icon with the text beside it (vertical-align: middle), or removing the gap under an inline image that sits on the baseline. For superscripts and subscripts that carry meaning, such as exponents, footnote references or chemical formulas, use the sup and sub elements rather than a styled span.
Decoration
text-decoration draws lines on text. It began as a single property with the values underline, overline, line-through and none, and is now a shorthand for four longhands:
| Longhand | Values |
|---|---|
text-decoration-line | underline, overline, line-through, none, or a combination |
text-decoration-style | solid, double, dotted, dashed, wavy |
text-decoration-color | Any color; currentColor by default |
text-decoration-thickness | A length, a percentage, auto or from-font |
A related property, text-underline-offset, moves the underline away from the text. With it and text-decoration-thickness, both Baseline widely available, a link can keep its underline and still look designed. The underline is a link's most reliable signal; readers who cannot tell colors apart depend on it, and removing it is the classic mistake:
The longhands are written separately here on purpose. Setting the thickness through the text-decoration shorthand has had uneven support, and the longhand leaves the line, style and color alone.
Decorations behave unusually with descendants. text-decoration does not inherit, but a decoration propagates: an underline on a paragraph is drawn across all the inline content inside it, and a child cannot remove it with text-decoration: none, because the line belongs to the parent. To get a different underline on part of the text, decorate the parts rather than the whole.
For struck-out text that means something, use the del or s element, which draws the line and also says why; a styled span does neither for a screen reader.
Hanging punctuation
hanging-punctuation: first lets an opening quotation mark hang into the margin so the letters, not the quote mark, line up with the text above, as in well-set print. Only Safari supports it, so treat it as a refinement for Safari readers that other browsers simply ignore.
A text baseline
Put together, a base layer for text needs only a few declarations, all on structural selectors:
4. Lists and counters
Lists are everywhere in good HTML: navigation, steps, tags, search results, footnotes. A list item gets display: list-item from the user-agent sheet, which gives it a marker: the bullet or the number beside it. The list-style family controls that marker, and because those properties inherit, setting them on the ul or ol reaches every item.
The list-style family
| Property | Values |
|---|---|
list-style-type | disc, circle, square, decimal, decimal-leading-zero, lower-roman, upper-roman, lower-alpha, upper-alpha, many language-specific systems, a string, or none |
list-style-position | outside (the marker hangs before the item's box) or inside (the marker sits within it, like the first word) |
list-style-image | An image to use as the marker, or none |
list-style | The shorthand for all three, in any order |
A string value such as "– " uses those exact characters as the marker, which replaces most uses of list-style-image. An image marker cannot be sized or aligned and stays one color in dark mode, so a string or ::marker is usually better.
The ::marker pseudo-element
::marker selects the marker box itself, so the bullet or number can be styled without touching the item's text. Only a short list of properties applies to it: color, the font properties, content, white-space, and animations and transitions. That is enough for the most common wish, a marker in the accent color:
Before ::marker, the usual trick was list-style: none plus a fake bullet drawn with ::before, which loses the real marker's alignment and, as above, can lose the list semantics too. Every current browser supports ::marker. The selectors page covers pseudo-elements in general.
Counters
The numbers in an ol come from a counter. CSS lets you create counters of your own and print them with generated content, which turns the style sheet, a little, into a program with variables:
counter-reset: namecreates a counter, starting at 0, on an element and its descendants.counter-increment: nameadds 1 (or another step) each time an element matches.counter(name)in acontentvalue prints the current value, optionally in a style:counter(name, upper-roman).counters(name, ".")prints every level of a nested counter joined by a string, giving outline numbers such as 2.1.3.
Numbering the sections of a document is the classic use:
And outline numbering for nested ordered lists:
The browser also keeps a built-in counter named list-item on every list, which is the one the default markers print. HTML's start and reversed attributes on ol and value on li set it, so prefer them when the numbers mean something.
Counters lead into dangerous territory, and it is worth seeing why. Generated content is not in the DOM. It cannot be selected and copied reliably, it is not found by every in-page search, it disappears if the style sheet fails to load, and assistive technologies treat it inconsistently. So keep counters for numbering that is presentation, such as section numbers on screen, and keep numbers that are content (a step the reader is told to go back to, a clause cited elsewhere) in the HTML.
Custom counter styles
When none of the built-in styles fits, @counter-style defines a new one, which list-style-type and counter() can then name. It can cycle through symbols, or extend an existing system with a different suffix:
@counter-style has been Baseline since 2023, when Safari added it. Many of the predefined styles exist so that languages with their own numbering, such as Armenian, Hebrew or Japanese, are numbered correctly.
5. Backgrounds
Every box can paint a background behind its content and padding, and by default under its border too. A background is decoration; it carries no meaning a reader can get at, so an image that carries content belongs in the HTML as an img with alternative text. Backgrounds are for color, texture and atmosphere.
The longhands
| Property | What it sets | Initial |
|---|---|---|
background-color | A color painted under everything else | transparent |
background-image | One or more images: url() files or gradients | none |
background-repeat | Whether a smaller image tiles: repeat, repeat-x, repeat-y, no-repeat, space, round | repeat |
background-position | Where the image is placed | 0% 0% |
background-size | How large it is drawn: a length, cover or contain | auto |
background-attachment | Whether it scrolls with the content: scroll, fixed, local | scroll |
background-origin | Which box positions are measured from | padding-box |
background-clip | How far the background is painted | border-box |
A few notes on the ones that need them:
- Color with an image. Always give a
background-colorunder a background image. It shows while the image loads, if it fails, and through its transparent parts, and it keeps text over the image readable in all three cases. - Repeat.
spacetiles the image without cutting off any copy, adding gaps between;roundscales the tiles so a whole number fits. - Position. Percentages line up the same point of the image and the box:
50% 50%(orcenter) puts the image's center on the box's center. Keywords with offsets, such asright 1rem bottom 1rem, measure from an edge. Background positions are still physical in practice: the logical keywords (x-start,y-endand friends) are specified, but only Safari 26 supports them so far, so they are not Baseline. - Size.
coverscales the image to fill the box, cropping what does not fit;containscales it to fit entirely, leaving gaps. - Attachment.
fixedpins the image to the viewport while the content scrolls over it, an old way to suggest depth. It forces extra painting as the page scrolls, and mobile Safari has long ignored it, so do not build a design that needs it.
The shorthand
background sets all eight, and the order of most values does not matter. Two rules do: a size must follow the position after a slash (center / cover), and when two box keywords appear, the first is the origin and the second the clip. As section 1 showed, everything you leave out is reset.
Layers
background-image takes a comma-separated list, and each image is a layer. The first image listed is painted on top, closest to the reader, and each later one sits underneath. The color sits below them all, and there can be only one, so in the shorthand it may appear only in the last layer. The other longhands take lists too, matched to the images in order.
A gradient is an image, generated by the browser, so it can be a layer anywhere in the list and costs no download. Here it darkens the photograph behind the header so white text keeps its contrast. The gradient functions and the colors inside them belong to the Color topic (coming).
What causes a request
A url() in a style sheet does not download anything by itself. Browsers fetch a background image only when an element that uses it is actually rendered, so an image in a rule that matches nothing costs nothing. The flip side is that the browser discovers a background image late: it must download the CSS, build the page and match the rule first. A large image at the top of a page loads sooner as an img in the HTML, where the browser can see it right away. The performance quality explains why that matters for how fast a page feels.
6. Visibility and display: none
There are several ways to make an element disappear, and they differ in what disappears. The questions are whether the element still takes up space, whether it is still in the accessibility tree that screen readers use, and whether it can still be focused and clicked.
| Technique | Takes space | Seen | Read by screen readers | Focusable and clickable |
|---|---|---|---|---|
display: none | No | No | No | No |
The hidden attribute | No | No | No | No |
visibility: hidden | Yes | No | No | No |
opacity: 0 | Yes | No | Yes | Yes |
| Visually hidden pattern | No | No | Yes | Yes |
display: none and visibility: hidden
display: none removes the element from the page entirely: it generates no box, takes no space, and is gone for every reader. visibility: hidden keeps the box and its space but paints nothing, so the layout does not move. Compare them in one sentence:
The first word vanishes and the sentence closes up; the second leaves a gap the width of "properties". Unlike display, visibility inherits, and a descendant can set visibility: visible to reappear inside a hidden parent. The value collapse hides a table row or column without disturbing the rest of the table.
The hidden attribute
For content that is hidden as a matter of state, such as a panel that is not open yet, the HTML hidden attribute says so in the markup, and scripts can toggle it. It works through the user-agent sheet, which contains [hidden] { display: none; }. That is also its weakness: any author rule that sets display on the same element beats the user-agent sheet, and the hidden element appears. A rule in your last layer restores it:
Hidden from the eye, not from the ear
opacity: 0 hides an element only from sight. It can still be clicked and focused, so a keyboard user can tab into something invisible, which is a trap rather than a technique. Sometimes, though, that half-hidden state is what you want: a label that sighted readers do not need, but that a screen reader should announce, such as "opens in a new tab". The visually hidden pattern shrinks the element to nothing without removing it from the accessibility tree:
The :not(:focus-within, :active) clause brings the element back into view when it or something inside it has focus, which is how "Skip to main content" links appear only for the keyboard users who need them.
Overflow, briefly
When content is larger than its box, overflow decides whether the extra shows, is clipped or scrolls. That is a layout question, and the layout page covers it, including why scrolling regions print badly.
7. Summary
| Concept | Key points |
|---|---|
| Property definitions | Each property has a value grammar, an initial value, the elements it applies to, an inheritance flag and an animation type. The initial value belongs to the property; an element's default look comes from the user-agent sheet. |
| Inheritance | Text properties inherit; box properties do not. The property's designer decided, and the keywords can override it for one declaration. |
| Shorthands | A shorthand sets every longhand it covers and resets the ones you leave out. Use a shorthand for a clean slate and a longhand to adjust. |
| Global keywords | inherit, initial, unset, revert and revert-layer name where a value comes from. unset is the everyday one; all applies one keyword to every property. |
| Text | Logical alignment, unitless line-height, spacing in em, case in the HTML and transforms in CSS, text-wrap: balance for headings, and underlines kept and styled with offset and thickness. |
| Lists and counters | list-style sets the marker type, position and image; ::marker styles it; counters and @counter-style number things that are presentation, while numbers that are content stay in the HTML. |
| Backgrounds | Decoration only. Always set a color under an image. Layers stack with the first listed on top and the color at the bottom. Images are fetched only when used, and found late. |
| Hiding | display: none and hidden remove an element; visibility: hidden keeps its space; opacity: 0 leaves it focusable; the visually hidden pattern hides it from sight only. |
