📝 Html Css

CSS Pseudo-classes and Pseudo-elements

P
Author
Pyland
📅
Published
30.06.2026
⏱️
Reading time
2 min
👁️
Views
78
🌿
Level
Medium

Pseudo-classes let you style elements based on their state or position in the DOM — without adding extra classes to the HTML. Pseudo-elements create virtual child elements using only CSS.

State pseudo-classes

:hover — on mouse hover

.nav-link:hover {
  color: #2563eb;
}

.post-card:hover {
  border-color: #2563eb;
  box-shadow: 0 4px 12px rgba(37, 99, 235, 0.1);
}

.btn:hover {
  background: #1d4ed8;
}

:focus — when focused (keyboard/click)

Essential for accessibility — keyboard users need to see where they are.

input:focus,
textarea:focus {
  outline: none;
  border-color: #2563eb;
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

.nav-link:focus {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
  border-radius: 2px;
}

Never use outline: none without a replacement — it breaks keyboard navigation.

:active — while being pressed

.btn:active {
  transform: scale(0.98);   /* slight "press" effect */
  background: #1e40af;
}

Structural pseudo-classes

:first-child and :last-child

/* Remove top border from the first card */
.post-card:first-child {
  border-top: none;
}

/* Remove bottom margin from the last card */
.post-card:last-child {
  margin-bottom: 0;
}

:nth-child()

/* Every other item (even) */
.post-card:nth-child(even) {
  background: #f9fafb;
}

/* Every third item */
.post-card:nth-child(3n) {
  border-top: 2px solid #2563eb;
}

/* First three items */
.post-card:nth-child(-n+3) {
  font-weight: 600;
}

:not() — negation

/* All links except the active one */
.nav-link:not(.nav-link--active):hover {
  text-decoration: underline;
}

/* All inputs except submit */
input:not([type="submit"]) {
  border: 1px solid #d1d5db;
}

:focus-within

Applied to a parent when focus is anywhere inside it — useful for forms:

.search-wrapper:focus-within {
  box-shadow: 0 0 0 2px #2563eb;
  border-radius: 6px;
}

Pseudo-elements

Pseudo-elements use a double colon :: and create supplementary content without changing the HTML.

::before and ::after

Insert a virtual element before/after the content. Require the content property.

/* Arrow before each table-of-contents link */
.toc-link::before {
  content: "→ ";
  color: #2563eb;
}

/* Horizontal line under a section heading */
.section-title::after {
  content: "";
  display: block;
  width: 40px;
  height: 3px;
  background: #2563eb;
  margin-top: 8px;
}

::placeholder

input::placeholder,
textarea::placeholder {
  color: #9ca3af;
  font-style: italic;
}

::selection

Color of text selected by the mouse:

::selection {
  background: #bfdbfe;
  color: #1e40af;
}

DevBlog: button with interaction effects

<a href="/articles/" class="btn btn-primary">All articles</a>
.btn {
  display: inline-block;
  padding: 10px 20px;
  border-radius: 6px;
  font-weight: 600;
  text-decoration: none;
  transition: all 0.15s ease;
  cursor: pointer;
}

.btn-primary {
  background: #2563eb;
  color: white;
}

.btn-primary:hover {
  background: #1d4ed8;
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(37, 99, 235, 0.3);
}

.btn-primary:active {
  transform: translateY(0);
  box-shadow: none;
}

.btn-primary:focus {
  outline: 2px solid #2563eb;
  outline-offset: 3px;
}

DevBlog: article list with ::after dividers

.post-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.post-list li {
  padding: 16px 0;
  position: relative;
}

/* Divider between items */
.post-list li:not(:last-child)::after {
  content: "";
  display: block;
  height: 1px;
  background: #e5e7eb;
  margin-top: 16px;
}

Quick reference

Pseudo-class/element When it applies
:hover Mouse hover
:focus Focus (keyboard/click)
:active Being pressed
:first-child First child element
:last-child Last child element
:nth-child(n) The nth element
:not(selector) Does not match selector
:focus-within Focus anywhere inside
::before Before content
::after After content
::placeholder Input placeholder
::selection Selected text

Your reaction to the article

💬 Comments (0)

🔐 Sign in to leave a comment
🚪 Login
💭

No comments yet

Be the first to share your opinion about this article!

🔗 Similar

Similar articles

Continue learning with these materials

📝

Event Loop in Python: How asyncio Achieves "Paral…

Event loop is the heart of asyncio. It doesn't run code in parallel across multiple...

📅 30.06.2026 👁️ 128
📝

Django: Template Tags

Template tags are logic inside HTML. Unlike {{ variable }} which only outputs a value,...

📅 30.06.2026 👁️ 85
📝

Colors and Fonts in CSS

The first thing a DevBlog reader sees is text. Well-chosen colors and fonts make a...

📅 30.06.2026 👁️ 75

Did you like the article?

Subscribe to our updates and receive new articles first. Grow with PyLand!