Understanding Specificity of Pseudo-Classes in CSS
Pseudo-classes in CSS have a specificity that is treated similarly to class selectors. They are more specific than type selectors but less specific than ID selectors. Understanding this helps predict which styles will apply when multiple rules target the same element.
Pseudo-classes (e.g., :hover, :focus, :nth-child()) count as a single class in specificity calculations.
Type selectors (e.g., div, p) and pseudo-elements (e.g., ::before, ::after) have lower specificity than pseudo-classes.
ID selectors have higher specificity than pseudo-classes.
Inline styles override pseudo-classes regardless of specificity.
Here, the first <p> changes to orange on hover because the :hover pseudo-class has higher specificity than the type selector. The second <p> with an ID stays red since ID selectors override pseudo-classes.
Use pseudo-classes to enhance interactivity without unnecessarily increasing specificity conflicts.
Combine pseudo-classes with classes or IDs for precise targeting.
Avoid over-chaining selectors to keep specificity manageable.
Test across browsers to ensure expected style application.
You’re trying to style a button with :hover, but it’s not working — the base button style from a library is overriding it. What’s the most likely cause, and how would you fix it without using !important?
You wrote a rule like li:hover { color: red; } and another like .active li { color: blue; }. When you hover over an active list item, which color wins? Why?
A user reports that the dropdown menu’s :focus styles aren’t showing up on mobile — you’ve checked the CSS and it looks correct. What’s your debugging process, and how might specificity be involved?
Your team’s design system uses :nth-child(odd) for alternating row colors, but now a new component is injecting dynamic content that breaks the pattern. How do you diagnose whether specificity or structural changes are the root cause?
You’re designing a reusable card component that needs to support both :focus-within and :has() for accessibility, but legacy browsers don’t support :has(). How do you architect the CSS to maintain visual consistency while avoiding specificity wars across the component tree?
Your CSS architecture uses utility classes heavily, but now you need to add state-driven styles like :disabled or :invalid for form fields. How do you balance reusability, maintainability, and specificity without creating brittle overrides?
You’re leading a migration from a legacy CSS framework that relied on !important everywhere to a modern CSS-in-JS system. How do you handle the technical debt of pseudo-class specificity conflicts that were buried under global overrides, and what long-term governance do you put in place?
Your company has 12 product teams using a shared design system, but each team has their own CSS layer that injects pseudo-class styles. How do you design a specificity governance model that prevents visual regressions during independent deployments without stifling autonomy?