Skip to content
πŸ› οΈToolsShed

CSS Specificity Calculator

Calculate and compare CSS selector specificity values.

Try an example:

About this tool

CSS specificity determines which style rule wins when multiple selectors target the same element. Understanding specificity is crucial for debugging styling conflicts and writing maintainable CSS. This tool calculates the specificity value of any CSS selector, breaking it down into its component parts (inline styles, IDs, classes, and elements) so you can compare and predict which rule will actually apply to your elements.

Enter any valid CSS selector into the input field and the calculator instantly computes its specificity value as a three-part number (a,b,c) where 'a' represents IDs, 'b' represents classes and pseudo-classes, and 'c' represents elements and pseudo-elements. You can also enter multiple selectors to compare their specificity values side by side, making it easy to identify which rule takes precedence. This is especially helpful when refactoring stylesheets or resolving cascading style conflicts.

Web developers, CSS authors, and designers benefit most from this tool when working with complex stylesheets or third-party CSS frameworks where specificity conflicts are common. Knowing exactly how specific your selector is helps you avoid the !important trap and write cleaner, more predictable CSS. This tool is ideal for both beginners learning CSS fundamentals and experienced developers optimizing stylesheet architecture.

Frequently Asked Questions

Code Implementation

import re

def parse_specificity(selector: str) -> tuple[int, int, int, int]:
    """
    Returns (inline, ids, classes, elements) specificity tuple.
    Inline styles are not detectable from a selector string,
    so 'a' is always 0 here.
    """
    # Remove :not() contents but count what's inside
    not_contents = re.findall(r':not\(([^)]+)\)', selector)
    selector_no_not = re.sub(r':not\([^)]*\)', '', selector)

    ids = len(re.findall(r'#[\w-]+', selector_no_not))
    classes = len(re.findall(r'\.[\w-]+', selector_no_not))
    attrs = len(re.findall(r'\[[^\]]*\]', selector_no_not))
    pseudo_classes = len(re.findall(r':[\w-]+', selector_no_not))
    pseudo_elements = len(re.findall(r'::[\w-]+', selector_no_not))
    elements = len(re.findall(r'(?<![#.\[\]:*])[a-zA-Z][\w-]*', selector_no_not))

    # Count inside :not()
    for inner in not_contents:
        inner_spec = parse_specificity(inner)
        ids += inner_spec[1]
        classes += inner_spec[2]
        elements += inner_spec[3]

    c = classes + attrs + pseudo_classes - pseudo_elements
    d = elements + pseudo_elements

    return (0, ids, max(c, 0), max(d, 0))

selectors = [
    "#header .nav a",      # (0,1,1,1)
    "div#main .content p", # (0,1,1,2)
    ":not(#id)",           # (0,1,0,0)
    ".btn.active",         # (0,0,2,0)
    "h1",                  # (0,0,0,1)
]

for sel in selectors:
    spec = parse_specificity(sel)
    print(f"{sel!r:35} => {spec}")

Comments & Feedback

Comments are powered by Giscus. Sign in with GitHub to leave a comment.