16 CSS Features That Eliminate JavaScript
JavaScript is powerful, but overused. Modern CSS handles many UI patterns that previously required JS. Here are 16 features that reduce JavaScript dependencies.
1. Dialog Element
<dialog>
<p>Native modal, no JS required for basic usage.</p>
<form method="dialog">
<button>Close</button>
</form>
</dialog>
<button onclick="document.querySelector('dialog').showModal()">Open</button>
CSS handles the backdrop:
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
}
2. Details/Summary Accordion
<details>
<summary>Click to expand</summary>
<p>No JavaScript needed for toggle.</p>
</details>
Style with CSS:
details[open] summary {
border-bottom: 1px solid #e0e0e0;
}
3. Popover API
<button popovertarget="menu">Menu</button>
<div id="menu" popover>
<a href="#">Item 1</a>
<a href="#">Item 2</a>
</div>
No JavaScript for show/hide logic.
4. CSS Scroll-Driven Animations
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animated {
animation: fade-in linear;
animation-timeline: view();
animation-range: entry 0% cover 30%;
}
Replaces IntersectionObserver for scroll animations.
5. View Transitions
::view-transition-old(page),
::view-transition-new(page) {
animation: fade 0.3s ease-in-out;
}
No JavaScript for page transitions in MPAs.
6. CSS Container Queries
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
Replaces JavaScript resize observers for responsive components.
7. CSS :has() Selector
/* Style parent based on children */
.card:has(img) {
display: grid;
grid-template-rows: auto 1fr;
}
/* Form validation */
.form-group:has(input:invalid) {
border-color: red;
}
No JavaScript for parent selection.
8. CSS Focus-Within
.menu:focus-within {
background: #f0f0f0;
}
.dropdown:focus-within .dropdown-content {
display: block;
}
Keyboard navigation without JavaScript.
9. CSS Nested Selectors
.card {
& .title {
font-size: 1.5rem;
}
&:hover {
transform: scale(1.02);
}
}
No preprocessor needed.
10. CSS Masonry Layout
.gallery {
display: grid;
grid-template-rows: masonry;
}
Replaces Masonry.js library.
11. CSS Subgrid
.parent {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.child {
display: grid;
grid-template-columns: subgrid;
}
Complex alignment without JavaScript calculations.
12. CSS Anchor Positioning
.tooltip {
position: anchor;
top: anchor(bottom);
left: anchor(center);
}
No JavaScript for tooltip positioning.
13. CSS Scroll-Snap
.carousel {
scroll-snap-type: x mandatory;
}
.slide {
scroll-snap-align: start;
}
Carousel without JavaScript libraries.
14. CSS Gap Decorations
.grid {
display: grid;
gap: 20px;
gap-decoration-row: 1px solid #e0e0e0;
}
Visual separators without pseudo-elements.
15. CSS Field Sizing
textarea {
field-sizing: content;
}
Auto-growing textarea without JavaScript.
16. CSS Color Functions
.button {
background: oklch(0.7 0.15 200);
}
.button:hover {
background: oklch(from current l c h / 0.8);
}
Color manipulation without JavaScript libraries.
Comparison Table
| Feature | Before | After |
|---|---|---|
| Modals | JS + CSS | CSS dialog |
| Accordions | JS toggle | <details> |
| Popovers | JS click handlers | popover attribute |
| Scroll animations | IntersectionObserver | animation-timeline |
| Page transitions | JS frameworks | View Transitions |
| Responsive components | ResizeObserver | Container Queries |
| Parent selection | JS traversal | :has() |
| Dropdowns | JS show/hide | :focus-within |
| Masonry | Masonry.js | grid-template-rows: masonry |
| Tooltips | JS positioning | Anchor Positioning |
| Carousels | Swiper.js | scroll-snap |
| Auto-growing inputs | JS height calc | field-sizing |
Performance Benefits
- Zero JavaScript bundle cost for these patterns
- No layout thrashing from JavaScript calculations
- GPU-accelerated CSS animations
- Native browser optimizations
When to Still Use JavaScript
- Complex state management
- API interactions
- Custom gesture handling
- Real-time updates
- Complex drag-and-drop
Conclusion
CSS has evolved into a complete UI language. For many common patterns, JavaScript is now optional. The result: smaller bundles, better performance, and simpler maintenance.
The pendulum swings toward CSS. After years of JavaScript-heavy solutions, the platform provides native alternatives.