Introduction
CSS has evolved dramatically over the past few years. Features that used to require JavaScript or complex hacks are now built into the language. Here are five techniques that have transformed my workflow.
1. CSS Grid for Layouts (Finally!)
Stop fighting with floats and flexbox for page layouts. CSS Grid was made for this:
.container {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
gap: 20px;
height: 100vh;
}
.header { grid-column: 1 / -1; }
.sidebar { grid-row: 2; }
.main { grid-row: 2; }
.footer { grid-column: 1 / -1; }
That's a complete page layout in just a few lines. No frameworks needed.
2. Custom Properties (CSS Variables)
Stop duplicating colors and spacing values. Define them once:
:root {
--primary-color: #667eea;
--spacing-unit: 8px;
--border-radius: 6px;
}
.button {
background: var(--primary-color);
padding: calc(var(--spacing-unit) * 2);
border-radius: var(--border-radius);
}
Want to change your entire color scheme? Update one variable. Plus, you can modify these with JavaScript for dynamic themes.
3. Container Queries
Media queries are great, but what if a component needs to adapt based on its container size, not the viewport?
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: flex;
flex-direction: row;
}
}
This makes components truly reusable. A card adapts whether it's in a sidebar or taking up the full width.
4. The :has() Selector
This one is wild. Style a parent based on its children:
/* Style the form if it has an invalid input */
form:has(input:invalid) {
border: 2px solid red;
}
/* Style a card differently if it has an image */
.card:has(img) {
display: grid;
grid-template-columns: 200px 1fr;
}
No JavaScript needed for parent-child relationships anymore.
5. Logical Properties
Stop thinking in terms of top/right/bottom/left. Use logical properties for better internationalization:
/* Old way */
.box {
margin-left: 20px;
padding-right: 10px;
}
/* New way */
.box {
margin-inline-start: 20px;
padding-inline-end: 10px;
}
When you switch to a right-to-left language, logical properties automatically adjust. Your layout just works.
Bonus: Cascade Layers
Manage CSS specificity properly with @layer:
@layer reset, base, components, utilities;
@layer reset {
* { margin: 0; padding: 0; }
}
@layer components {
.button { /* your styles */ }
}
Layers let you control precedence without increasing specificity. Utility classes can override components, which override base styles.
Why This Matters
These aren't just clever tricks - they represent a fundamental shift in how we write CSS. The language is becoming more powerful, more logical, and more developer-friendly.
I've been able to delete thousands of lines of JavaScript and complex CSS hacks by using these features. My stylesheets are smaller, more maintainable, and easier to understand.
Browser Support
All these features work in modern browsers. Grid and custom properties have been stable for years. Container queries and :has() are newer but widely supported. Always check caniuse.com for your specific use case.
What CSS features have changed your workflow? Let me know through the contact form!

