Back to Blog
CSSPseudo-ElementsStylingLayout

CSS Pseudo-Elements Guide

Master CSS pseudo-elements ::before, ::after, and more for decorative and functional styling.

B
Bootspring Team
Engineering
March 22, 2020
6 min read

Pseudo-elements let you style specific parts of elements without extra markup. Here's how to use them.

Basic Syntax#

1/* Double colon syntax (CSS3) */ 2.element::before { 3 content: ''; 4} 5 6.element::after { 7 content: ''; 8} 9 10/* Single colon (CSS2, still works) */ 11.element:before { 12 content: ''; 13} 14 15/* Common pseudo-elements */ 16::before /* Insert before element content */ 17::after /* Insert after element content */ 18::first-line /* First line of text */ 19::first-letter /* First letter of text */ 20::selection /* User-selected text */ 21::placeholder /* Input placeholder text */ 22::marker /* List item markers */

::before and ::after Basics#

1/* Content is required */ 2.quote::before { 3 content: '"'; 4} 5 6.quote::after { 7 content: '"'; 8} 9 10/* Empty content for decorative elements */ 11.decorated::before { 12 content: ''; 13 display: block; 14 width: 50px; 15 height: 2px; 16 background: #007bff; 17} 18 19/* Using attr() */ 20.tooltip::after { 21 content: attr(data-tooltip); 22 position: absolute; 23 /* ... positioning styles */ 24} 25 26/* Counters */ 27.numbered::before { 28 counter-increment: section; 29 content: counter(section) '. '; 30}

Decorative Elements#

1/* Underline effect */ 2.fancy-underline { 3 position: relative; 4 display: inline-block; 5} 6 7.fancy-underline::after { 8 content: ''; 9 position: absolute; 10 left: 0; 11 bottom: -2px; 12 width: 100%; 13 height: 2px; 14 background: linear-gradient(90deg, #007bff, #00d4ff); 15 transform: scaleX(0); 16 transition: transform 0.3s ease; 17} 18 19.fancy-underline:hover::after { 20 transform: scaleX(1); 21} 22 23/* Corner decorations */ 24.corner-box { 25 position: relative; 26 padding: 2rem; 27 border: 2px solid #333; 28} 29 30.corner-box::before, 31.corner-box::after { 32 content: ''; 33 position: absolute; 34 width: 20px; 35 height: 20px; 36 border: 2px solid #007bff; 37} 38 39.corner-box::before { 40 top: -5px; 41 left: -5px; 42 border-right: none; 43 border-bottom: none; 44} 45 46.corner-box::after { 47 bottom: -5px; 48 right: -5px; 49 border-left: none; 50 border-top: none; 51}

Shapes and Icons#

1/* Triangle */ 2.arrow-right::after { 3 content: ''; 4 display: inline-block; 5 width: 0; 6 height: 0; 7 border-top: 5px solid transparent; 8 border-bottom: 5px solid transparent; 9 border-left: 8px solid currentColor; 10 margin-left: 0.5rem; 11} 12 13/* Circle bullet */ 14.custom-bullet { 15 list-style: none; 16} 17 18.custom-bullet li { 19 position: relative; 20 padding-left: 1.5rem; 21} 22 23.custom-bullet li::before { 24 content: ''; 25 position: absolute; 26 left: 0; 27 top: 0.5em; 28 width: 8px; 29 height: 8px; 30 background: #007bff; 31 border-radius: 50%; 32} 33 34/* Checkbox icon */ 35.custom-checkbox::before { 36 content: ''; 37 display: inline-block; 38 width: 18px; 39 height: 18px; 40 border: 2px solid #666; 41 border-radius: 3px; 42 margin-right: 0.5rem; 43 vertical-align: middle; 44} 45 46.custom-checkbox.checked::before { 47 background: #007bff; 48 border-color: #007bff; 49} 50 51.custom-checkbox.checked::after { 52 content: '✓'; 53 position: absolute; 54 color: white; 55 font-size: 12px; 56}

Overlays and Effects#

1/* Image overlay */ 2.image-card { 3 position: relative; 4 overflow: hidden; 5} 6 7.image-card::before { 8 content: ''; 9 position: absolute; 10 inset: 0; 11 background: linear-gradient( 12 to top, 13 rgba(0, 0, 0, 0.8), 14 transparent 15 ); 16 opacity: 0; 17 transition: opacity 0.3s ease; 18} 19 20.image-card:hover::before { 21 opacity: 1; 22} 23 24/* Shine effect */ 25.shine-button { 26 position: relative; 27 overflow: hidden; 28} 29 30.shine-button::before { 31 content: ''; 32 position: absolute; 33 top: 0; 34 left: -100%; 35 width: 50%; 36 height: 100%; 37 background: linear-gradient( 38 90deg, 39 transparent, 40 rgba(255, 255, 255, 0.3), 41 transparent 42 ); 43 transform: skewX(-25deg); 44 transition: left 0.5s ease; 45} 46 47.shine-button:hover::before { 48 left: 150%; 49} 50 51/* Glassmorphism border */ 52.glass-card { 53 position: relative; 54 background: rgba(255, 255, 255, 0.1); 55 backdrop-filter: blur(10px); 56} 57 58.glass-card::before { 59 content: ''; 60 position: absolute; 61 inset: 0; 62 border-radius: inherit; 63 padding: 1px; 64 background: linear-gradient( 65 135deg, 66 rgba(255, 255, 255, 0.4), 67 transparent 68 ); 69 mask: linear-gradient(#fff 0 0) content-box, 70 linear-gradient(#fff 0 0); 71 mask-composite: exclude; 72 pointer-events: none; 73}

Text Effects#

1/* Drop cap */ 2.article p:first-of-type::first-letter { 3 float: left; 4 font-size: 4rem; 5 line-height: 1; 6 font-weight: bold; 7 margin-right: 0.5rem; 8 color: #007bff; 9} 10 11/* First line styling */ 12.article p::first-line { 13 font-weight: bold; 14 font-variant: small-caps; 15} 16 17/* Custom selection */ 18::selection { 19 background: #007bff; 20 color: white; 21} 22 23.dark-theme ::selection { 24 background: #ffd700; 25 color: #333; 26} 27 28/* Placeholder styling */ 29input::placeholder { 30 color: #999; 31 font-style: italic; 32} 33 34input:focus::placeholder { 35 opacity: 0.5; 36}

Labels and Badges#

1/* Required field indicator */ 2.required::after { 3 content: '*'; 4 color: red; 5 margin-left: 0.25rem; 6} 7 8/* External link indicator */ 9a[href^="http"]::after { 10 content: ' ↗'; 11 font-size: 0.8em; 12} 13 14/* New badge */ 15.new-item::before { 16 content: 'NEW'; 17 display: inline-block; 18 padding: 0.125rem 0.5rem; 19 font-size: 0.625rem; 20 font-weight: bold; 21 background: #ff4444; 22 color: white; 23 border-radius: 3px; 24 margin-right: 0.5rem; 25 vertical-align: middle; 26} 27 28/* Price with currency */ 29.price::before { 30 content: '$'; 31} 32 33/* File type indicator */ 34a[href$=".pdf"]::before { 35 content: '📄 '; 36} 37 38a[href$=".zip"]::before { 39 content: '📦 '; 40}

Clearfix and Layout#

1/* Classic clearfix */ 2.clearfix::after { 3 content: ''; 4 display: table; 5 clear: both; 6} 7 8/* Divider line */ 9.divider { 10 display: flex; 11 align-items: center; 12 text-align: center; 13} 14 15.divider::before, 16.divider::after { 17 content: ''; 18 flex: 1; 19 height: 1px; 20 background: #ddd; 21} 22 23.divider::before { 24 margin-right: 1rem; 25} 26 27.divider::after { 28 margin-left: 1rem; 29} 30 31/* Section separator */ 32.section::after { 33 content: ''; 34 display: block; 35 width: 60px; 36 height: 3px; 37 background: #007bff; 38 margin: 2rem auto; 39}

Custom List Markers#

1/* Custom bullet with ::marker */ 2ul.custom::marker { 3 color: #007bff; 4 font-size: 1.2em; 5} 6 7/* Numbered list styling */ 8ol.fancy { 9 list-style: none; 10 counter-reset: list-counter; 11} 12 13ol.fancy li { 14 counter-increment: list-counter; 15 position: relative; 16 padding-left: 3rem; 17 margin-bottom: 1rem; 18} 19 20ol.fancy li::before { 21 content: counter(list-counter); 22 position: absolute; 23 left: 0; 24 width: 2rem; 25 height: 2rem; 26 background: #007bff; 27 color: white; 28 border-radius: 50%; 29 display: flex; 30 align-items: center; 31 justify-content: center; 32 font-weight: bold; 33}

Form Enhancements#

1/* Styled radio button */ 2.radio-custom { 3 display: flex; 4 align-items: center; 5 gap: 0.5rem; 6 cursor: pointer; 7} 8 9.radio-custom input { 10 position: absolute; 11 opacity: 0; 12} 13 14.radio-custom::before { 15 content: ''; 16 width: 20px; 17 height: 20px; 18 border: 2px solid #666; 19 border-radius: 50%; 20 transition: all 0.2s; 21} 22 23.radio-custom:has(input:checked)::before { 24 border-color: #007bff; 25 background: #007bff; 26 box-shadow: inset 0 0 0 4px white; 27} 28 29/* Focus ring */ 30.focus-ring:focus-visible::before { 31 content: ''; 32 position: absolute; 33 inset: -4px; 34 border: 2px solid #007bff; 35 border-radius: inherit; 36 pointer-events: none; 37}

Best Practices#

Usage: ✓ Use for decorative elements ✓ Always include content property ✓ Use position: relative on parent ✓ Prefer double colon syntax Performance: ✓ Keep pseudo-elements simple ✓ Use transform for animations ✓ Avoid excessive nesting ✓ Test on mobile devices Accessibility: ✓ Don't use for important content ✓ Decorative content only ✓ Screen readers may ignore ✓ Ensure color contrast Avoid: ✗ Critical content in ::before/::after ✗ Overusing for everything ✗ Complex layouts with pseudo-elements ✗ Replacing semantic HTML

Conclusion#

CSS pseudo-elements enable powerful styling without additional markup. Use ::before and ::after for decorations, icons, and effects. Remember that content property is required, and pseudo-element content is not accessible to screen readers. Use them for visual enhancements, not critical content.

Share this article

Help spread the word about Bootspring