CSS 伪元素 ::before/::after 实战:5 个场景替代 10 行 JavaScript 代码
CSS 伪元素 ::before/::after 实战5 个场景替代 10 行 JavaScript 代码前端开发中我们常常依赖 JavaScript 来实现各种交互效果和动态内容。然而CSS 伪元素::before和::after提供了一种更轻量、更高效的解决方案。本文将介绍 5 个实际开发场景展示如何用纯 CSS 方案替代常见的 JavaScript 实现显著减少代码量并提升性能。1. 加载失败占位图优雅处理图片错误传统 JavaScript 方案通常需要监听onerror事件动态创建错误提示元素const img document.querySelector(img); img.onerror function() { const errorDiv document.createElement(div); errorDiv.textContent 图片加载失败; img.parentNode.replaceChild(errorDiv, img); };CSS 替代方案img { position: relative; min-height: 100px; } img::before { content: ; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: #f5f5f5; border: 1px dashed #ddd; border-radius: 4px; } img::after { content: 图片加载失败: attr(alt); position: absolute; top: 50%; left: 0; width: 100%; text-align: center; transform: translateY(-50%); color: #999; font-size: 14px; }优势对比方案代码行数性能影响SEO友好JavaScript~6行需要DOM操作是CSS~15行零JS开销是提示attr()函数可以获取元素的任意属性值这是实现动态内容的关键2. 自定义复选框无JS的UI组件传统实现需要 JavaScript 来同步原生复选框与自定义样式const checkboxes document.querySelectorAll(input[typecheckbox]); checkboxes.forEach(checkbox { checkbox.addEventListener(change, function() { this.nextElementSibling.classList.toggle(checked, this.checked); }); });纯CSS解决方案label classcustom-checkbox input typecheckbox span同意条款/span /label.custom-checkbox { position: relative; padding-left: 28px; cursor: pointer; } .custom-checkbox input { position: absolute; opacity: 0; width: 0; height: 0; } .custom-checkbox span::before { content: ; position: absolute; left: 0; top: 2px; width: 18px; height: 18px; border: 2px solid #ccc; border-radius: 3px; transition: all 0.3s; } .custom-checkbox input:checked span::before { background: #2196F3; border-color: #2196F3; } .custom-checkbox input:checked span::after { content: ; position: absolute; left: 6px; top: 8px; width: 5px; height: 10px; border: solid white; border-width: 0 2px 2px 0; transform: rotate(45deg); }技术要点使用:checked伪类捕获复选框状态::before创建复选框外框::after创建选中标记原生input被隐藏但仍保持可访问性3. Tooltip 提示纯CSS信息气泡传统JS方案需要计算位置并管理显示/隐藏状态const elements document.querySelectorAll(.has-tooltip); elements.forEach(el { const tooltip document.createElement(div); tooltip.className tooltip; tooltip.textContent el.dataset.tooltip; document.body.appendChild(tooltip); el.addEventListener(mouseenter, () { const rect el.getBoundingClientRect(); tooltip.style.left ${rect.left}px; tooltip.style.top ${rect.top - 30}px; tooltip.style.display block; }); el.addEventListener(mouseleave, () { tooltip.style.display none; }); });CSS 实现方案button>.css-tooltip { position: relative; } .css-tooltip:hover::after { content: attr(data-tooltip); position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: 8px; padding: 6px 12px; background: #333; color: white; border-radius: 4px; font-size: 14px; white-space: nowrap; opacity: 0; transition: opacity 0.3s; } .css-tooltip:hover::before { content: ; position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%); margin-bottom: 2px; border-width: 6px; border-style: solid; border-color: #333 transparent transparent transparent; opacity: 0; transition: opacity 0.3s; } .css-tooltip:hover::after, .css-tooltip:hover::before { opacity: 1; }性能对比JavaScript方案需要DOM操作、事件监听和位置计算CSS方案仅使用CSS渲染零运行时开销4. 步骤指示器自动编号系统传统实现需要JavaScript动态生成序号const steps document.querySelectorAll(.step); steps.forEach((step, index) { const number document.createElement(div); number.className step-number; number.textContent index 1; step.insertBefore(number, step.firstChild); });CSS计数器方案div classsteps div classstep填写信息/div div classstep确认订单/div div classstep完成支付/div /div.steps { counter-reset: step-counter; } .step { position: relative; padding-left: 40px; margin-bottom: 20px; } .step::before { counter-increment: step-counter; content: counter(step-counter); position: absolute; left: 0; width: 30px; height: 30px; line-height: 30px; text-align: center; background: #2196F3; color: white; border-radius: 50%; }进阶样式添加连接线和当前状态指示.step:not(:last-child)::after { content: ; position: absolute; left: 15px; top: 30px; height: calc(100% - 30px); width: 2px; background: #ddd; } .step.current::before { background: #4CAF50; box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.3); }计数器功能counter-reset初始化计数器counter-increment递增计数counter()显示当前值5. 动态角标实时数据展示传统JavaScript实现需要手动更新DOMfunction updateBadge(count) { const badge document.querySelector(.cart-badge); badge.textContent count; badge.style.display count 0 ? block : none; }纯CSS方案button classcart-icon 购物车 span classbadge>.cart-icon { position: relative; } .badge::before { content: attr(data-count); position: absolute; top: -10px; right: -10px; min-width: 20px; height: 20px; line-height: 20px; text-align: center; background: #f44336; color: white; border-radius: 10px; font-size: 12px; padding: 0 4px; } .badge[data-count0]::before { display: none; }动态更新技巧通过修改>/* 不推荐的写法 */ .button::after { content: 重要提示!; /* 屏幕阅读器可能跳过 */ } /* 推荐的写法 */ button aria-label重要提示提交/button通过合理运用::before和::after伪元素我们不仅能够减少 JavaScript 代码量还能获得更好的性能表现和更简洁的代码结构。这些技术特别适合对性能敏感的项目和需要快速响应的用户界面。