CSS syntax is built from selectors and declarations. The selector chooses what to style, and each declaration says which property should receive which value.
Selectors are the first debugging skill every CSS learner needs. If the selector does not match the intended element, the declaration block can be perfectly written and still do nothing.
CSS Syntax and Selectors needs more than a syntax memory trick. The important idea is to understand selector matching, declaration blocks, class selectors, id selectors, attribute selectors, pseudo selectors, and cascade order in the exact situation where the page topic appears, then prove the behavior with a small working example and one edge case.
A CSS rule consists of a selector and a declaration block. The selector targets HTML elements; the declaration block contains one or more property-value pairs separated by semicolons.
Whitespace is mostly flexible in CSS, but punctuation matters. Missing braces, colons, or semicolons can cause later declarations to be ignored or parsed incorrectly.
selector {
property: value;
property: value;
}
| Selector | Syntax | Targets |
|---|---|---|
| Universal | * | Every element |
| Element (Type) | h1 | All <h1> elements |
| Class | .classname | Elements with that class |
| ID | #idname | Element with that ID (unique) |
| Attribute | [type="text"] | Elements with matching attribute |
| Descendant | div p | <p> inside any <div> |
| Child | div > p | Direct <p> children of <div> |
| Adjacent Sibling | h1 + p | <p> immediately after <h1> |
| General Sibling | h1 ~ p | All <p> siblings after <h1> |
| Group | h1, h2, h3 | All listed elements |
/* Universal selector - applies to ALL elements */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Element (type) selector */
h1 { color: #2c3e50; }
p { line-height: 1.6; }
/* Class selector - reusable */
.btn {
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
}
.btn-primary { background-color: #3498db; color: white; }
.btn-danger { background-color: #e74c3c; color: white; }
/* ID selector - unique per page */
#navbar {
background-color: #2c3e50;
position: sticky;
top: 0;
}
/* Attribute selectors */
input[type="text"] { border: 1px solid #ccc; }
input[type="password"] { border: 1px solid #e74c3c; }
a[href^="https"] { color: green; } /* href starts with https */
a[href$=".pdf"] { color: red; } /* href ends with .pdf */
a[href*="example"] { font-weight: bold; } /* href contains "example" */
/* Combinators */
div p { color: #555; } /* descendant: any p inside div */
div > p { color: #333; } /* child: direct p children of div */
h2 + p { font-size: 1.1em; } /* adjacent sibling: p right after h2 */
h2 ~ p { color: #666; } /* general sibling: all p after h2 */
/* Grouping */
h1, h2, h3, h4 {
font-family: 'Georgia', serif;
font-weight: bold;
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="selectors.css">
</head>
<body>
<nav id="navbar">Navigation</nav>
<h1>Page Title</h1>
<h2>Section</h2>
<p>This p is adjacent sibling of h2</p>
<p>This p is general sibling of h2</p>
<div>
<p>Direct child p of div</p>
<section>
<p>Descendant p (not direct child)</p>
</section>
</div>
<button class="btn tl-btn-primary">Save</button>
<button class="btn tl-btn-danger">Delete</button>
<input type="text" placeholder="Username">
<input type="password" placeholder="Password">
</body>
</html>
Pseudo-classes select elements based on their state or position. They use the : prefix.
/* State pseudo-classes */
a:link { color: blue; } /* unvisited link */
a:visited { color: purple; } /* visited link */
a:hover { color: red; text-decoration: underline; } /* mouse over */
a:active { color: orange; } /* being clicked */
input:focus { outline: 2px solid #3498db; } /* focused input */
input:disabled { opacity: 0.5; cursor: not-allowed; }
input:checked { accent-color: #3498db; }
/* Structural pseudo-classes */
li:first-child { font-weight: bold; } /* first list item */
li:last-child { color: gray; } /* last list item */
li:nth-child(2) { background: #f0f0f0; } /* 2nd item */
li:nth-child(odd) { background: #fff; } /* odd items */
li:nth-child(even) { background: #f9f9f9; } /* even items */
p:first-of-type { font-size: 1.2em; } /* first p in parent */
p:last-of-type { margin-bottom: 0; }
/* Negation */
li:not(:last-child) { border-bottom: 1px solid #eee; }
input:not([type="submit"]) { border: 1px solid #ccc; }
Pseudo-elements style a specific part of an element. They use the :: prefix (double colon).
/* ::before - insert content before element */
.required-field::before {
content: "* ";
color: red;
}
/* ::after - insert content after element */
.price::after {
content: " USD";
font-size: 0.8em;
color: gray;
}
/* ::first-letter - style first letter */
p::first-letter {
font-size: 2em;
font-weight: bold;
float: left;
margin-right: 4px;
color: #3498db;
}
/* ::first-line - style first line */
p::first-line {
font-weight: bold;
color: #2c3e50;
}
/* ::selection - style selected text */
::selection {
background-color: #3498db;
color: white;
}
/* ::placeholder - style input placeholder */
input::placeholder {
color: #aaa;
font-style: italic;
}
CSS syntax has two main parts: a selector and a declaration block. The selector chooses which elements receive the style, and the declarations describe what visual properties change. A small typo in either part can make the rule look ignored even when the browser is simply matching something different.
Selectors should be learned as matching patterns. A class selector matches class names, an id selector matches one id, an attribute selector matches an element with a specific attribute, and pseudo selectors match states or generated parts. Once selector matching is clear, specificity and cascade behavior become much easier.
.card[data-status="active"] .card-title {
color: #1d4ed8;
font-weight: 700;
}
.card:hover {
border-color: #60a5fa;
}
Writing .card title when the HTML class is card-title.
Match the selector exactly: .card-title.
Using #id selectors for every visual style.
Use classes for styles that may repeat across the page.
Using div p when only direct child paragraphs should be styled.
Use div > p for direct children only.
Changing property values repeatedly when the real problem is that the selector does not match.
Verify the matched element and winning rule in browser DevTools before changing the style.
A space means descendant. For example, .card p targets any p inside .card.
.box targets a class. #box targets an ID, which should be unique on the page.
Check whether the selector matches, whether another rule overrides it, and whether the syntax is valid.
Usually no. Short class-based selectors are easier to maintain and override.
The selector may not match, another rule may override it, the property may be invalid, or the stylesheet may not be loaded.
Explore 500+ free tutorials across 20+ languages and frameworks.