Chapter 5 of 17 · CSS for Beginners — Complete Free Tutorial
Pseudo-elements & Attribute Selectors
Sometimes you need to style a part of an element — the first letter, the text a user selected — or match elements by what their attribute contains. Pseudo-elements (::) and attribute selectors ([]) give you both powers without adding a single extra tag.
Pseudo-elements
A pseudo-element creates a virtual piece of the element you can style. The two most useful have exactly one :… modern syntax uses two: ::before and ::after.
::before and ::after
They insert generated content relative to the element. The content property is required — without it the pseudo-element does not render.
.badge {
position: relative;
background: #eef2ff;
color: #4338ca;
padding: 0.25rem 0.75rem;
border-radius: 999px;
font-size: 0.8rem;
font-weight: 600;
}
.badge::before {
content: "★ ";
color: #f59e0b;
}
.quote {
position: relative;
padding-left: 2.5rem;
font-style: italic;
}
.quote::before {
content: "“";
position: absolute;
left: 0;
top: -0.25rem;
font-size: 3.5rem;
line-height: 1;
color: #c7d2fe;
}
Expected output: every badge gains a gold star prefix; every quote gets an oversized decorative quotation mark — with no changes to the HTML.
Rule of thumb: decorative content (symbols, ornaments, quotes) belongs in
::before/::after. Real information — especially anything a screen reader should read — belongs in the HTML.
Other useful pseudo-elements
| Pseudo-element | Targets | Example |
|---|---|---|
::first-line | First rendered line of a block | Drop caps in a lead paragraph |
::first-letter | First letter of a block | Magazine-style big initial |
::placeholder | Input placeholder text | Lighter grey hints |
::selection | Text highlighted by the user | Custom highlight colour |
::marker | Bullet/number of a list item | Custom list markers |
::placeholder, ::file-selector-button | Form chrome | Style file-upload buttons |
::selection { background: #4f46e5; color: white; }
.lead::first-letter {
float: left;
font-size: 3.2em;
line-height: 0.8;
padding-right: 0.1em;
color: #4f46e5;
}
li::marker { color: #4f46e5; }
Attribute selectors
Match elements by the presence or value of an attribute — no extra classes needed:
| Syntax | Matches | Example |
|---|---|---|
[disabled] | Attribute present (any value) | input[disabled] |
[type="email"] | Exact value | input[type="email"] |
[class^="btn-"] | Value starts with | Legacy button classes |
[href$=".pdf"] | Value ends with | PDF links get a file icon |
[class*="col-"] | Value contains | Grid column helpers |
[rel~="nofollow"] | One word in a space list | External link styling |
a[href^="http"]::after { content: " ↗"; font-size: 0.8em; }
a[href$=".pdf"] { color: #dc2626; }
input[type="checkbox"] { accent-color: #4f46e5; }
img[alt=""] { outline: 2px solid red; } /* decorative images for quick audits */
[data-theme="dark"] { background: #0f172a; color: #e2e8f0; }
Expected output: every external link shows a small arrow, PDF links turn red, and checkboxes use your brand colour — all from three rules and zero HTML changes.
Combining everything: a tag list
<ul class="tags">
<li class="tag tag--new">Flexbox</li>
<li class="tag">Grid</li>
<li class="tag">Selectors</li>
</ul>
.tags { display: flex; gap: 0.5rem; list-style: none; }
.tag {
padding: 0.3rem 0.8rem;
border: 1px solid #cbd5e1;
border-radius: 999px;
font-size: 0.85rem;
}
.tag--new::after {
content: " new";
color: #16a34a;
font-weight: 700;
text-transform: uppercase;
font-size: 0.7em;
}
.tag[data-lang="css"] { border-color: #4f46e5; color: #4f46e5; }
Common mistakes
- Forgetting
content—::beforewith nocontentsimply does not exist for styling. - Generated content for real text — screen readers may skip it; keep copy in HTML.
- Icon fonts in pseudo-elements without aria-hidden care — decorative only, and never as the sole meaning.
- Case-sensitive attribute values —
[type="EMAIL"]will not match; values are matched exactly (unless you addiflag:[type="email" i]).
Practice checklist
- Add a star to every element with class
.badgeusing::before. - Give external links (
href^="http") a visible "↗" marker. - Style
::selectionwith your brand colour and check it by selecting text.
Rules shape elements — now the fun part: giving them colour. Next: Colors & Opacity.
Frequently Asked Questions
CSS (Cascading Style Sheets) is the language that controls how HTML content looks — colours, fonts, spacing, layout, responsiveness and animation. HTML provides structure and meaning; CSS provides presentation. One stylesheet can restyle an entire website at once.
The fundamentals (selectors, box model, Flexbox, media queries) take about 2–3 weeks of daily practice. Grid, animations and architecture come with a little more practice. This 17-chapter series is designed for 3–4 weeks at a relaxed pace — faster if you type out every example.
Yes. HTML first, then CSS, then JavaScript. CSS and HTML together let you build complete, good-looking static pages, and almost every JavaScript framework assumes you already know CSS layout and selectors.
No — CSS is a styling language with selectors and property-value declarations, not variables, loops or conditionals. You can get far without any programming logic, and JavaScript adds the behaviour later.
Flexbox distributes space along one axis (a row or a column) and is ideal for components — toolbars, navbars, card rows. Grid controls rows and columns together and is ideal for page structure and card grids. They are complementary: many layouts use a grid page shell with flex components inside.
Usually one of three reasons: the selector does not match (check class names), a more specific rule wins (use the browser inspector to see computed styles and specificity), or the file is not linked/loads in the wrong order. The specificity chapter explains how the cascade decides.
Every element is a box of four layers: content, padding (inner space), border, and margin (outer space). With box-sizing: border-box, the width you set includes padding and border — the universal reset every project uses.
Use relative units, flexible grids like repeat(auto-fit, minmax(260px, 1fr)), images with max-width: 100%, and mobile-first media queries. The goal is zero horizontal scrolling from 320px up — the responsive chapters show the full workflow.
Not to learn. Frameworks are productivity tools built on the same CSS you are learning here; understanding the fundamentals makes any framework easier to use (and to debug when it fights you). Learn vanilla CSS first, then evaluate frameworks with an informed eye.
JavaScript for interactivity, then a build tool and version control (Git). With HTML, CSS and JavaScript you can build complete websites; after that, frameworks like React or server-side tools like Laravel Blade build on these fundamentals.