CSS Pseudo-Elements: Complete Guide for Modern Web Development

Master the art of styling specific parts of elements without modifying HTML. Learn ::before, ::after, ::first-line, and more for cleaner, faster web interfaces.

What Are CSS Pseudo-Elements?

CSS pseudo-elements are a fundamental feature of modern CSS that allow developers to style specific parts of HTML elements without adding extra markup to the document. These abstract elements, represented by the double-colon syntax (::), enable precise control over styling first lines, first letters, generated content, and interactive states.

Unlike pseudo-classes that select elements based on their state, pseudo-elements create conceptual elements within the DOM structure that can be styled independently. This approach keeps your HTML clean and semantic while achieving sophisticated visual effects that would otherwise require additional markup.

For developers building with Next.js and modern CSS frameworks, understanding pseudo-elements is essential for creating professional, performant interfaces. They enable elegant typography, decorative effects, and interactive cues without bloating your component code.

Understanding Pseudo-Element Syntax

Basic Syntax Rules

The syntax for pseudo-elements follows a specific pattern: selector::pseudo-element { property: value; }. The pseudo-element must always be the rightmost component in your selector chain. This ordering is mandatory - incorrect placement results in invalid CSS that browsers ignore entirely.

When chaining pseudo-classes and pseudo-elements, the pattern p:hover::first-line is valid: the pseudo-class (:hover) targets the element's state, while the pseudo-element (::first-line) targets the specific portion to style. Understanding this relationship is key to writing correct CSS.

Pseudo-Classes vs. Pseudo-Elements

Pseudo-classes (single colon) select elements based on their state or relationship - like :hover, :first-child, or :nth-of-type(). Pseudo-elements (double colon) create and select abstract parts of elements, inserting conceptual elements into the DOM for styling purposes.

This distinction has practical implications: use pseudo-classes for interactive states and positional selection, use pseudo-elements for styling specific content portions or adding decorative elements without HTML modifications.

Basic Pseudo-Element Syntax
1/* Correct syntax */2p::first-line {3 color: blue;4 text-transform: uppercase;5}6 7/* Chaining pseudo-class and element */8p:hover::first-letter {9 font-size: 2rem;10}11 12/* Tree-abiding pseudo-elements */13.button::before {14 content: "→ ";15 margin-right: 0.5rem;16}17 18/* Invalid - pseudo-element not at end */19/* p::first-line > span { } */

Typographic Pseudo-Elements: First Lines and Letters

The ::first-line Pseudo-Element

The ::first-line pseudo-element targets the first line of text within a block-level element. Its length dynamically adjusts as the container's width changes - the browser automatically determines which text constitutes the first line based on available space and font metrics.

Properties available for ::first-line include font properties (font-family, font-size, font-weight), text properties (color, text-transform, letter-spacing), and text-decoration properties. Layout properties like margin, padding, or border cannot be applied, as the browser must maintain the pseudo-element's flow within the text content.

The ::first-letter Pseudo-Element

The ::first-letter pseudo-element targets the first character on the first line. Properties are more extensive - in addition to font and text properties, you can apply margin, padding, border, background, and float. This enables sophisticated drop cap designs that extend into margins.

Drop caps created with ::first-letter signal content beginnings, provide visual anchoring, and create professional polish. For articles, documentation, and editorial designs, this technique elevates visual design while maintaining semantic HTML.

Drop Cap Code Example

This example demonstrates a classic drop cap effect using ::first-letter. The float property allows the large letter to sit beside flowing text, while negative line-height pulls subsequent lines closer for that traditional editorial look.

The approach uses :first-of-type to target only the first paragraph, as drop caps typically appear only at the beginning of content blocks. This keeps the effect elegant and purposeful rather than overwhelming the reader.

Creating Drop Caps with ::first-letter
1/* Target first paragraph's first letter */2.article-content > p:first-of-type::first-letter {3 float: left;4 font-size: 3.5rem;5 line-height: 1;6 padding-right: 0.5rem;7 padding-top: 0.1rem;8 font-weight: bold;9 color: #1e40af;10}11 12/* First line styling for emphasis */13.article-content > p::first-line {14 font-weight: bold;15 color: #2563eb;16 text-transform: uppercase;17 letter-spacing: 0.05em;18}

Tree-Abiding Pseudo-Elements: Generated Content

Understanding ::before and ::after

The ::before and ::after pseudo-elements create conceptual children of the originating element that appear before or after the actual content. These pseudo-elements exist within the element's box model and can be styled like any other element, making them incredibly versatile.

The key to using these pseudo-elements is the content property, which is required for generating visible content. Without content, ::before and ::after exist but are invisible. This property accepts text strings, attribute values via attr(), counter values, and more.

Generated content excels for icon overlays, decorative elements, and interactive cues without modifying HTML. For Next.js applications, this means cleaner component code - styling decisions stay in CSS rather than polluting JSX with presentation markup.

The content Property in Depth

The content property supports text strings, attr(data-attribute) for dynamic values, counter functions for automatic numbering, and URL values for images. This flexibility enables complex designs without JavaScript.

::before and ::after Examples
1/* Arrow icon before button text */2.button::before {3 content: "→ ";4 margin-right: 0.5rem;5 transition: transform 0.2s ease;6}7 8.button:hover::before {9 transform: translateX(4px);10}11 12/* Icon from external file */13.icon::after {14 content: "";15 display: inline-block;16 width: 1em;17 height: 1em;18 background-image: url("/icons/arrow.svg");19 background-size: contain;20 vertical-align: middle;21 margin-left: 0.5rem;22}23 24/* Attribute-based content */25[data-label]::after {26 content: attr(data-label);27 font-size: 0.75rem;28 color: #6b7280;29 margin-left: 0.5rem;30}
Advanced: Gradient Border with ::before
1/* Gradient border using mask compositing */2.card::before {3 content: "";4 position: absolute;5 inset: 0;6 border-radius: inherit;7 padding: 2px;8 background: linear-gradient(135deg, #3b82f6, #8b5cf6);9 -webkit-mask:10 linear-gradient(#fff 0 0) content-box,11 linear-gradient(#fff 0 0);12 mask:13 linear-gradient(#fff 0 0) content-box,14 linear-gradient(#fff 0 0);15 -webkit-mask-composite: xor;16 mask-composite: exclude;17 pointer-events: none;18}

Highlight Pseudo-Elements: User Selection and Focus

Styling User Selection with ::selection

The ::selection pseudo-element applies styles when users highlight text. Custom selection styling reinforces brand identity and improves readability. Properties are limited to color, background-color, text-decoration, and text-shadow.

The ::target-text Pseudo-Element

This pseudo-element styles text targeted by URL fragments (#:~:text=). When users navigate via shared text fragment links, ::target-text provides visual feedback about their arrival point. For documentation and long-form content, this enhances the sharing experience.

Custom Highlights with ::highlight()

The CSS Custom Highlight API's ::highlight() enables JavaScript-managed custom highlight regions. Developers register named highlights in CSS.highlights, then style them with CSS - perfect for search result highlighting and collaborative editing indicators.

Spelling and Grammar Error Pseudo-Elements

::spelling-error and ::grammar-error style browser-identified errors. Browser support is limited, but these pseudo-elements promise better integration of error styling with design systems as support expands.

Custom Selection Styling
1/* Brand-colored text selection */2::selection {3 background-color: #bfdbfe;4 color: #1e3a8a;5}6 7/* Dark mode selection */8.dark-mode ::selection {9 background-color: #1e40af;10 color: #dbeafe;11}12 13/* Text fragment targeting */14:target-text {15 background-color: #fef08a;16 color: #854d0e;17 padding: 0.125rem 0.25rem;18 border-radius: 0.25rem;19}20 21/* Custom highlight styling */22::highlight(search-results) {23 background-color: #fef08a;24 color: #854d0e;25 border-bottom: 2px solid #eab308;26}

Form-Related Pseudo-Elements

Styling Placeholder Text with ::placeholder

The ::placeholder pseudo-element targets placeholder text in form inputs, allowing customization independent of user-entered content. Placeholder styling uses a limited property set but effectively communicates the hint's temporary nature.

Customizing File Input Buttons

The ::file-selector-button pseudo-element targets file input buttons, enabling custom styling without hiding inputs and creating JavaScript fallbacks. This approach maintains full accessibility while achieving professional design integration.

Other Form Pseudo-Elements

Additional form pseudo-elements include ::checkmark for select options, ::picker() for dropdown interfaces, and ::picker-icon for picker icons. These enable comprehensive form customization matching modern design standards.

Placeholder Styling
1/* Placeholder text styling */2input::placeholder,3textarea::placeholder {4 color: #9ca3af;5 font-style: italic;6 opacity: 1;7}8 9input:focus::placeholder,10textarea:focus::placeholder {11 color: #d1d5db;12}
Custom File Input Button
1input[type="file"]::file-selector-button {2 margin-right: 1rem;3 padding: 0.5rem 1rem;4 border: none;5 border-radius: 0.375rem;6 background-color: #3b82f6;7 color: white;8 font-weight: 500;9 cursor: pointer;10 transition: background-color 0.2s ease;11}12 13input[type="file"]::file-selector-button:hover {14 background-color: #2563eb;15}16 17input[type="file"]::file-selector-button:active {18 background-color: #1d4ed8;19}

Element-Backed Pseudo-Elements

Styling Shadow DOM with ::part()

The ::part() pseudo-element styles elements inside shadow DOM from outside the shadow tree. Web components use the part attribute to expose elements for external styling, enabling component customization while maintaining encapsulation.

Targeting Slotted Content with ::slotted()

The ::slotted() pseudo-element styles elements placed into <slot> elements within shadow DOM. This enables component authors to apply base styles to slotted content while allowing consumers to override them.

These pseudo-elements are essential for working with web components and custom elements, providing the flexibility needed for reusable component libraries while respecting the boundary between component internals and external consumers.

Styling Web Component Parts
1/* Styling shadow DOM from outside */2custom-button::part(button) {3 background-color: #6366f1;4 color: white;5 padding: 0.75rem 1.5rem;6 border-radius: 0.5rem;7 font-weight: 600;8 transition: all 0.2s ease;9}10 11custom-button::part(button):hover {12 background-color: #4f46e5;13 transform: translateY(-1px);14}15 16custom-button::part(icon) {17 width: 1.25rem;18 height: 1.25rem;19 margin-right: 0.5rem;20}
Styling Slotted Content
1/* Base styles for slotted content */2::slotted(*) {3 font-family: inherit;4 color: inherit;5}6 7/* Highlight specific slotted elements */8::slotted(span.highlight) {9 background-color: #fef08a;10 padding: 0.125rem 0.25rem;11 border-radius: 0.25rem;12}13 14/* Style links within slots */15::slotted(a) {16 color: #3b82f6;17 text-decoration: none;18}19 20::slotted(a:hover) {21 text-decoration: underline;22}

Modern and Experimental Pseudo-Elements

View Transition Pseudo-Elements

CSS View Transitions introduce ::view-transition, ::view-transition-group, ::view-transition-image-pair, ::view-transition-new, and ::view-transition-old. These enable smooth animated transitions between page states without JavaScript animation libraries. These APIs are particularly valuable for Next.js applications that require seamless page transitions.

Scroll Marker Pseudo-Elements

Newer pseudo-elements like ::scroll-marker, ::scroll-marker-group, and ::scroll-button() address scroll container styling. These enable custom scroll navigation without JavaScript, with browser support evolving.

These experimental features represent the future of CSS styling capabilities, enabling effects that previously required substantial JavaScript while maintaining the declarative, performant nature of CSS.

Performance and Best Practices

Rendering Performance

Pseudo-elements don't add actual DOM nodes - they exist conceptually during rendering. This makes them generally performant. However, certain combinations with expensive CSS properties can impact performance, especially with animations.

When animating pseudo-elements, stick to transform and opacity for GPU acceleration. Avoid animating width, height, margin, or padding, which trigger layout recalculations.

Accessibility Considerations

Content added through ::before and ::after isn't accessible to screen readers since it's not in the DOM. Use real HTML elements for important content or functional elements. Ensure ::selection colors maintain sufficient contrast.

Code Organization

Group pseudo-element styles near their originating elements. This improves maintainability and helps developers understand element relationships. Use comments to document complex pseudo-element patterns.

Performance-Conscious Animations
1/* GOOD: GPU-accelerated properties */2.card::before {3 transition: opacity 0.3s ease, transform 0.3s ease;4}5 6.card:hover::before {7 opacity: 0;8 transform: scale(0.95);9}10 11/* AVOID: Layout-triggering properties */12/* .card:hover::before {13 width: 100%; // Triggers layout14 margin-left: 10px; // Triggers layout15} */

Frequently Asked Questions

Ready to Build Better Web Interfaces?

Master CSS pseudo-elements and modern styling techniques for faster, cleaner, more maintainable websites.