Web Styling Time Travel: What Is Making Tailwind Top 1 Today?
"Time is money" has never been more relevant. Since 2022, front-end developers have prioritized speed over perfection, adopting a "good enough UI" approach that meets these key criteria:
- 80%+ Lighthouse score – ensuring performance, accessibility, and SEO.
- Smooth, responsive UI – free of lags or glitches.
- Well-designed UX/UI – visually appealing and user-friendly.
- Mobile-friendly – optimized for most web traffic.
- Minimal JS – reducing performance overhead.
I'm not saying you should follow this approach—just highlighting the current market trend. Companies are tired of waiting weeks for UI development. It’s an oversimplification, but the shift feels inevitable—much like the adoption of calculators (which, yes, mathematicians once protested! 😄).
Tailwind emerged from this trend and gained momentum with AI's rise—in 2025, UI delivery speed is lightning-fast. Like any tool, it has pros and cons, but its modern design and market alignment have made it the top choice for most new websites.
As the community embraced Tailwind, an ecosystem of tools—Figma plugins, AI assistants, IDE extensions, and low-code platforms—emerged to streamline UI development. This momentum makes dethroning Tailwind a challenge.
I called it Top 1 in the title not because it’s flawless—it has drawbacks—but because its unique combination of features and balance perfectly aligns with market trends. To explain why, we need to dive deep into the history, context, and iterations of web styling.
Let’s do that today!
This timeline highlights key solutions, with estimated dates, as pinpointing exact occurrences is difficult. Also, keep in mind that many of these developments happened in parallel.
Stage 1: Early Styling (The Wild West of Websites)
Have you ever seen websites like these?
Before the CSS3 specification, this was common due to significant limitations in web technologies. Code like this was widespread:
// The beginning... Early 1990s - Mid-1990s
<font color="red" size="4">Hello, World!</font>
// Mid-1990s Inline CSS
<p style="color: blue; font-size: 16px;">This is a paragraph.</p>
Imagine the "WOW" effect when this arrived:
// Internal & External Stylesheets (Late 1990s - Early 2000s)
<style>
p { color: blue; font-size: 16px; }
</style>
// or
<link rel="stylesheet" href="styles.css">
Back then, styling was extremely limited and often felt "dirty."
Stage 2: CSS3 Arrival and Everything Changed
CSS3 evolved as a series of modules, with features being introduced over time. While development started in the mid-2000s, full standardization and widespread adoption occurred gradually, with many features becoming mainstream in the 2010s. Here’s a small overview of important changes and features:
- Modularization
- JS Reduction
- Box Model Changes
- Flexbox
- CSS Grid
- ... and an insane amount of new stuff each month.
The styling codebase started to look like this:
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
And websites' look and feel improved as well:
CSS continues to evolve through new modules under the CSS3 umbrella. Rather than following a versioning system, CSS is constantly updated and refined. This process is still ongoing today.
Stage 3: CSS Methodologies to the Rescue
As CSS3 was widely adopted, developers began to encounter recurring problems in larger codebases:
- Naming collisions: Overlapping class names can cause styling conflicts in a shared codebase.
- Fragile UI: Poor structure makes small changes risky, potentially breaking large sections.
- Style leaks: Unintended styles can affect unrelated components.
- Inconsistent naming: Different naming conventions lead to confusion and maintenance issues.
- No clear layering: Mixing global, base, and component styles makes management harder.
To tackle these challenges, CSS methodologies emerged to introduce structure and consistency. Let’s explore some popular approaches that help organize large-scale projects.
OOCSS in 2009 by Nicole Sullivan
To address these issues, Object-Oriented CSS was introduced, laying the foundation for future methodologies. Its key principles are:
- Separation of Structure from Skin – Keep layout (e.g., spacing, positioning) separate from visual styles (e.g., colors, fonts).
/* Structure: Defines reusable layout and spacing */
.card {
display: flex;
flex-direction: column;
width: 300px;
padding: 16px;
}
/* Skin: Defines appearance (color, typography) */
.card-default {
background-color: #fff;
color: #333;
}
.card-dark {
background-color: #333;
color: #fff;
}
/* Typography (Reusable styles for text) */
.card-title {
font-size: 20px;
}
- Separation of Container from Content – Ensure components are reusable and not dependent on specific parent elements.
/* Problem: Card styles depend on a specific container */
.card-container .card {
width: 300px;
padding: 16px;
}
.card-container .card h2 {
font-size: 20px;
}
<div class="card-container">
<div class="card">
<h2>Card Title</h2>
<p>Card content goes here.</p>
</div>
</div>
/* Good: Reusable card structure */
.card {
width: 300px;
padding: 16px;
}
/* Reusable typography */
.card-title {
font-size: 20px;
}
<!-- Card used independently -->
<div class="card">
<h2 class="card-title">Standalone Card</h2>
<p>Can be placed anywhere.</p>
</div>
This methodology suited grouped UI components but lacked guidance for smaller elements like fonts, positioning, and layout. As a result, it was applied selectively, leaving other styles unstructured.
BEM Methodology in 2010 by Yandex
BEM (Block, Element, Modifier) was another approach to solving the problem of chaotic CSS structures. It tackled the issue by introducing strict naming conventions:
- Block: A standalone entity (e.g.,
.card
). - Element: A child of a block (e.g.,
.card__title
). - Modifier: A variation of a block or element (e.g.,
.card--featured
).
/* Block */
.card {
border: 1px solid #ddd;
border-radius: 8px;
}
/* Elements */
.card__image {
width: 100%;
border-radius: 8px 8px 0 0;
}
.card__title {
font-size: 1.5rem;
margin: 8px 0;
}
/* Modifier */
.card--featured {
background-color: #ffefc3;
}
BEM reduced naming conflicts and added structure, but its verbosity quickly became frustrating, often cluttering HTML...
<nav class="navbar">
<ul class="navbar__menu">
<li class="navbar__menu-item navbar__menu-item--active">Home</li>
<li class="navbar__menu-item">About</li>
<li class="navbar__menu-item navbar__menu-item--disabled">Contact</li>
</ul>
</nav>
While BEM structured CSS, managing deep nesting became tedious, and debugging felt like deciphering a puzzle of underscores and hyphens. It was progress, but developers sought a simpler approach. A common complaint was handling edge cases where multiple classes applied to different blocks, leading to frequent refactoring in larger projects.
<div class="profile">
<div class="profile__header">
<!-- Issue here -->
<h2 class="card__title">John Doe</h2>
</div>
<div class="profile__content">
<p class="profile__text">Web Developer</p>
</div>
</div>
The issue mentioned in OOCSS also exists here—there are no guidelines for smaller elements that aren't related to "chunks of UIs."
SMACSS in 2011 by Jonathan Snook
An approach already existed to address the lack of separation of concerns and real architectural division—SMACSS (Scalable and Modular Architecture for CSS). It introduced a layered structure to CSS:
- Base – Default styles for HTML elements.
- Layout – Major layout components.
- Module – Reusable, modular parts of the UI.
- State – Styles for different states (active, expanded, etc.)
- Theme – Swappable visual styles.
Unlike BEM or OOCSS, SMACSS wasn’t about strict naming conventions but rather about organizing styles into separate layers for better maintainability.
/* 1. BASE - Default styles */
body { font-family: Arial, sans-serif; }
/* 2. LAYOUT - Major site sections */
.l-container { max-width: 1200px; margin: 0 auto; }
/* 3. MODULE - Reusable components */
.btn { display: inline-block; padding: 8px 16px; border-radius: 4px; }
/* 4. STATE - Different states */
.is-active { font-weight: bold; }
/* 5. THEME - Swappable visual styles */
.theme-dark { background-color: #222; color: #eee; }
SMACSS was often combined with BEM or OOCSS, providing structure while relying on other methodologies for naming.
However, managing layers meant frequently shifting styles between categories. Even a simple color change could require moving a class to a different file, making refactoring a constant challenge.
Atomic CSS in 2013 by Yahoo
Atomic CSS (also known as Functional CSS) introduced single-purpose classes, each handling just one styling property. An early example from Yahoo’s Atomic CSS framework:
<... class="Bfc P(10px) M(20px) C(#333) Fz(20px)">
This approach was controversial... When developers first saw websites being styled this way, the lament began.
Nonetheless, it paved the way for utility-first frameworks like Bootstrap and Tailwind. Whether the idea emerged independently elsewhere or not, atomic styling gained traction because it simply worked. However, at the time, its design was still too immature to achieve widespread adoption.
Enduring CSS by Ben Frain in 2014
ECSS focuses on strong encapsulation, avoiding global styles, and enforcing component-based naming for maintainability. Here’s what it offered:
- Scoped selectors (Component-based naming).
- No global styles except resets.
- Minimal nesting for better maintainability.
/* Instead of using generic `.button`, we scope it */
.article__button {
background: green;
color: white;
}
/* Strong encapsulation avoids leaks */
.profile-card__image {
width: 100px;
}
This approach was also less popular… As you can see, many methodologies were just developers iterating on each other’s ideas—tweaking solutions for specific problems while inevitably creating new ones in the process. 😆
Inverted Triangle CSS by Harry Roberts in 2015
ITCSS structures CSS in a layered hierarchy, making it scalable and maintainable. It moves from generic, low-specificity styles to highly specific ones.
Layered structure of ITCSS:
- Settings – Global variables, colors, typography, etc.
- Tools – Mixins, functions (if using a preprocessor like SCSS).
- Generic – Like Resets.css, Normalize.css, base styles.
- Elements – Default styling for HTML tags (
h1
,p
,a
, etc.). - Objects – Reusable design patterns (e.g.,
.container
). - Components – Specific UI elements (
.card
,.button
). - Trumps – Utility classes that override everything (
.hidden
,.text-center
).
/* Settings */
:root {
--primary-color: #3498db;
--font-main: Arial, sans-serif;
}
/* Tools */
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
/* Generic */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Elements */
h1 {
font-family: var(--font-main);
color: var(--primary-color);
}
/* Objects */
.container {
max-width: 1200px;
margin: 0 auto;
}
/* Components */
.button {
background: var(--primary-color);
color: white;
padding: 10px 20px;
border-radius: 5px;
}
/* Trumps */
.hidden {
display: none !important;
}
Still, it was just a convention and remained less popular. However, I’ve seen projects adopt similar ideas—not strictly following these guidelines but clearly inspired by them. I can’t say for sure they were based on this exact approach, but they shared common principles.
Composition, Utility, Block, Exception by Andy Bell in 2021
CUBE CSS is a structured approach that balances layout composition, reusable components, and utility classes with scoped exceptions.
/* Composition (Layout rules) */
.flex {
display: flex;
gap: 1rem;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
/* Utility */
.text-center {
text-align: center;
}
.margin-lg {
margin: 2rem;
}
/* Block */
.card {
padding: 1rem;
background: #f5f5f5;
}
/* Exception */
.card.featured {
background: yellow;
}
As you can see, the author addressed edge cases by treating them as exceptions. This approach explicitly accounted for necessary deviations, whereas earlier methodologies struggled with rigid structures—making any deviation feel like breaking the rules. CUBE CSS tackled this issue directly.
Stage 4: The Preprocessors Era
As the name suggests, preprocessors transform meta-syntax into plain CSS during the build process, as browsers only interpret standard CSS.
Alongside the previously mentioned methodologies, CSS preprocessors like Sass (2006), Less (2009), and Stylus (2010) became essential tools, providing:
-
Variables for consistent values
$primary-color: #3498db; button { background-color: $primary-color; }
-
Vendor-prefixing (adding alternative directives for different browsers via plugins)
-
Nesting for clearer selector relationships
.navbar { background: #333; a { color: inherit; } }
-
Mixins for reusable style patterns
@mixin flex-center { display: flex; align-items: center; justify-content: center; } .container { @include flex-center; height: 100vh; }
-
Functions for parameterized calculations
@function generate-list($count) { $output: ''; @for $i from 1 through $count { $output: #{$output} 'li:nth-child(#{$i}) { font-size: #{$i * 2}px; } '; } @return unquote($output); } ul { @include generate-list(10); }
-
…and many other features missing in plain CSS
Preprocessors solved many issues but required careful organization to avoid messy CSS. Developers often paired them with methodologies like BEM, SMACSS, or ITCSS for better structure and scalability.
// Sass preprocessor example + BEM
$primary-color: #3490dc;
.card {
&__title {
color: $primary-color;
}
&--featured {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
}
The mix of preprocessors and conventions improved UI maintainability, but real encapsulation was still missing. Styles could still leak across components, making independent work tricky...
Stage 5: Encapsulation with CSS Modules
CSS Modules emerged around 2015, introduced by Glen Maddern and Mark Dalgleish to enable scoped styles in modular front-end applications. Tobias Koppers and Johannes Ewald played a key role through their work on Webpack, which made CSS Modules practical by bundling styles modularly.
This approach let developers import CSS files directly into JavaScript, bundle styles separately, or inject them into a <style>
tag. Classes could be referenced via classnames.nameOfClass
, with automatic transformations applied if configured.
Encapsulation was achieved by generating unique class names, like dasda-dad-dasd-123
, ensuring styles remained isolated in each build. Here’s an example:
/* button.module.css */
.primary {
background-color: blue;
}
// In a "button.jsx" React file
import styles from './button.module.css';
function Button() {
// In code, "styles.primary", but after the build, it becomes "dasda-dad-dasd-123"
return <button className={styles.primary}>Click me</button>;
}
By combining CSS Modules with preprocessors, developers started using .module.scss
files to leverage preprocessor features while maintaining encapsulated styles.
At the same time, TypeScript had matured, impressing developers with its capabilities. Someone (exactly who is unclear) introduced type generation for CSS Modules via a Webpack plugin. This allowed TypeScript to perform static checks when importing classes, catching typos and incorrect class usage automatically. This approach became known as Typed CSS Modules, further enhancing the reliability of CSS in TypeScript projects.
/* button.module.scss */
.primary {
background-color: blue;
}
// In a "button.tsx" React file
import styles from './button.module.scss';
function Button() {
// TypeScript throws an error 💢 due to the typo
return <button className={styles.pimarlyms}>Click me</button>;
}
For 1–2 years, Typed CSS Modules gained traction at conferences and in new projects. It offered encapsulation, worked well with preprocessors, and was combined with methodologies. It seemed like the perfect solution—until new challenges arose.
Stage 6: The Impact of CSS-in-JS
All of this stemmed from a single presentation—Christopher Chedeau (vjeux) from Facebook in his 2014 talk, "CSS in JS." It's hard to determine who originally came up with the idea, but it's definitely worth acknowledging that he played a significant role in its popularization.
As component-based frameworks like React and Vue gained popularity, CSS-in-JS emerged as a new way to address the challenges of styling within a component-centric architecture.
The question arose: "Can I use CSS syntax inside React components while maintaining the same level of composition and encapsulation as React component logic?" The answer was yes! This became easier to implement thanks to tagged template literals (introduced in ECMAScript 2015).
// This is what you write with styled-components or similar CSS-in-JS libraries
const StyledButton = styled.button`
background-color: ${props => props.primary ? "blue" : "gray"};
color: white;
padding: ${props => props.size === "large" ? "10px 20px" : "5px 10px"};
`;
// This is roughly what happens under the hood when the template literal is processed
const StyledButton = styled.button(
["background-color: ", ";\n color: white;\n padding: ", ";\n"],
props => props.primary ? "blue" : "gray",
props => props.size === "large" ? "10px 20px" : "5px 10px"
);
Imagine doing it explicitly in the way from the second snippet. Total nightmare to maintain...
The goal was to merge structure, styling, and logic into a single, fully encapsulated component, challenging the traditional separation of HTML, CSS, and JS. The community focused on coding aspects like maintenance and encapsulation but often overlooked the performance impact of early CSS-in-JS solutions, which added significant JavaScript to the bundle. This led to poor Lighthouse scores on larger pages. I personally saw this when I switched greenonsoftware.com from CSS-in-JS (styled-components) to plain CSS, boosting the performance score from 54% to 92%.
This lesson sparked improvements in CSS-in-JS, with new versions focusing on reducing JavaScript and generating static styles. To understand CSS-in-JS evolution, let’s dive into its history and the solutions developed along the way.
React's Arrival in 2014 and Inline Styles
It's strange, but this period is worth mentioning. In the early stages of React, developers aimed for the best encapsulation by defining inline styles. Anything that needed to be reused was provided via globally exported objects... It was a nightmare!
const styles = {
container: {
padding: '20px',
},
};
function Component() {
return (
<div style={styles.container}>
<h1>Hello World</h1>
</div>
);
}
This approach had major limitations, including the inability to use media queries, pseudo-selectors, or keyframe animations (just a few of the many issues), along with other drawbacks.
Radium in 2014: A Basic Version of CSS-in-JS
The previously mentioned React codebase was far from ideal, leading to the creation of real tools. One of the first was Radium, which extended inline styles to support pseudo-selectors and media queries, while still using JavaScript objects for styling.
import Radium from 'radium';
const styles = {
button: {
':hover': {
backgroundColor: 'darkblue'
},
'@media (max-width: 768px)': {
padding: '12px'
}
}
};
function Button() {
return <button style={styles.button}>Click Me</button>;
}
Modern CSS-in-JS: Styled-Components and Emotion in 2016–2017
Styled Components and Emotion marked an ongoing paradigm shift, allowing developers to write actual CSS syntax within JavaScript. It was a breath of fresh air.
import styled from 'styled-components';
const Button = styled.button`
&:hover {
background-color: darkblue;
}
@media (max-width: 768px) {
padding: 12px;
}
`;
function Component() {
return <Button>Click Me</Button>;
}
Both solutions introduced modern syntax and great possibilities. While some argued these technologies were unnecessary, many teams adopted them. However, many soon regretted their decision. The runtime impact of CSS-in-JS was huge, especially when developers applied it to every JSX node, leading to a bloated and inefficient styling codebase.
const ButtonContainer = styled.div`
display: flex;
`;
const Button = styled.button`
padding: 10px 20px;
&:hover {
background-color: #0056b3;
}
`;
const ButtonLabel = styled.span`
font-weight: bold;
`;
// Usage
const App = () => {
return (
<ButtonContainer>
<Button>
<ButtonLabel>Click Me</ButtonLabel>
</Button>
</ButtonContainer>
);
};
This doesn’t mean it’s a bad solution. The real issue was that developers often used it without much thought—especially when they were tired. Encapsulation is great until it isn’t—sometimes, it’s just not necessary. The same code could have been easily implemented using the OOCSS methodology and plain CSS, but some developers were too rigid, insisting on following the new trend 100%.
StyleX by Facebook in 2020
StyleX emerged to address the pain point of the previously mentioned huge runtime overhead.
import React from 'react';
import { stylex } from 'stylex';
// Define styles
const buttonStyles = stylex.create({
base: {
padding: '10px 20px',
},
primary: {
backgroundColor: '#007bff',
},
});
const Button = ({ children }) => (
<button className={stylex(buttonStyles.base, buttonStyles.primary)}>
{children}
</button>
);
StyleX aimed to balance dynamic styling creation at runtime with avoiding bloated performance and excessive JavaScript generation. It was a compromise—providing encapsulation while prioritizing performance over encapsulation at all costs.
Vanilla-Extract in 2021: Zero Runtime Overhead
Leveraging TypeScript and lessons from previous approaches, the authors of Vanilla-Extract went all-in on achieving zero JavaScript runtime overhead. The styling codebases are fully transpiled into CSS during the build phase.
import { style } from '@vanilla-extract/css';
const button = style({
// ...
cursor: 'pointer',
':hover': { backgroundColor: '#0056b3' },
});
const Button = ({ children }) => (
<button className={button}>{children}</button>
);
Vanilla-Extract offers a zero-runtime solution by shifting all style processing to the build phase, ensuring no additional JavaScript impact on runtime performance.
Other CSS-in-JS solutions, like Linaria and Stitches, are also similar. I’ll just mention them to save space in this article.
Stage 7: The Arrival of Tailwind CSS (History Made a Circle)
More about history: Who crafted Tailwind?
Tailwind CSS emerged in 2019 as a response to the growing complexity and verbosity of traditional component-based frameworks. By using utility classes within a structured design system, it addressed several key challenges:
- Eliminated the runtime overhead of CSS-in-JS.
- Offered greater flexibility than component-based frameworks like Bootstrap.
- Reduced reliance on custom CSS compared to methodologies like BEM.
- Enforced design consistency through a configurable system of values (design tokens).
- Provided an easy-to-use styling layer.
- Maximized performance and speed of delivery.
Its popularity surged alongside the rise of AI tools like ChatGPT and the broader OpenAI ecosystem. Seamless integration with modern tools like V0 from Vercel further fueled its widespread adoption.
Many platforms also began offering strong support for Tailwind, including design tools like Figma and various low-code platforms. Tailwind's simplicity made it an excellent fit for AI-assisted workflows, reducing the need for complex reasoning and minimizing context switching.
Eventually, IDE extensions enhanced the developer experience. This led to a modern approach for crafting UIs quickly, efficiently, and in a "good enough" way. By reusing mostly pre-written code and making basic customizations, developers could build interfaces at lightning speed!
// tailwind.config.js
module.exports = {
content: ['./src/**/*.{html,js,jsx,ts,tsx}'],
theme: {
extend: {},
},
plugins: [],
}
/* .main.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
const Button = ({ children }: { children: React.ReactNode }) => (
<button className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-700 transition-colors">
{children}
</button>
);
Clean code gurus started to yield again. It's hard to understand why people struggle with the basic principle of programming and real-life rules: you can't have everything. Instead of getting stuck in endless debates about conventions, paradigms, or class names—just install Tailwind.
Yes, this framework is designed to give you almost everything you need, following design principles through tokens, while allowing customization where necessary. It’s not a dictator—it gives you the freedom to write simple CSS, use a pre-processor, or even merge it with a CSS-in-JS approach if you need more encapsulation.
All features and pros/cons of Tailwind are covered in my article Tailwind is a Real Game Changer.
Interestingly, newer tools like UnoCSS and WindiCSS have emerged. We've seen similar iterations in CSS-in-JS and other methodologies—people keep refining ideas. However, I’d be cautious when using them; they have decent popularity but remain somewhat niche.
Answering the Question: Why is Tailwind Top 1?
BECAUSE DEVELOPERS ARE TIRED AND WANT THINGS TO GET DONE ASAP IN A GOOD ENOUGH WAY – that’s my bold statement, and it’s 100% legitimate.
But seriously, as we've seen, time changes, people change, and requirements change. Tailwind has successfully adapted to the modern needs of web development. While it’s true that technology is constantly evolving and developers sometimes change their preferences (often based on new trends or personal mistakes), Tailwind has carved out its place in the development landscape for several reasons. Here’s why I believe Tailwind is currently #1:
-
Focused on Good Enough Performance: Tailwind strikes a balance between performance and functionality. Unlike some alternatives, it doesn’t burden your projects with unnecessary overhead, and it delivers solid results without compromising speed.
-
Allowing Flexibility: Tailwind gives developers the freedom to customize and control their styles, allowing them to adapt the framework to suit their specific needs. It’s not restrictive, unlike some opinionated frameworks.
-
Enforcing Design Principles and System Conventions: Tailwind is built around a design system that includes a set of principles and values that ensure design consistency across projects. Its utility-first approach ensures that every piece of styling aligns with these principles.
-
Providing Out-of-the-Box Resets, Components, and Utility Classes: Tailwind includes a vast set of utility classes that speed up development. Additionally, it provides ready-to-use resets and components that save time on foundational design work.
-
Focused on Delivery Speed: Tailwind’s design is geared toward rapid prototyping and production. By simplifying the development process with pre-defined utility classes and integration with modern tools, it allows teams to build and deploy projects faster than many alternatives.
-
Huge Ecosystem: Tailwind’s ecosystem is robust and continues to grow. Tools like ShadCN, Headless UI, and countless others complement the core framework, expanding its capabilities and making it even more powerful for developers.
While technology trends will continue to evolve, these foundational features make Tailwind a strong contender in web development today.
Summary & Conclusions
Please, please, and please... In current software development, we need to be pragmatic. All of the mentioned techniques, technologies, and tools come with different sets of pros, cons, and features that should be carefully considered before choosing something for your project.
By walking through the historical context, I’ve shown how things have changed over the years in web development, and I can guarantee that it will change again. It's just the natural law of being a web developer. There’s even a formula (crafted by me) that proves it’s true (LOL):
2024 Web Developer =
2023 Web Developer +
1 New Framework +
3 New Tools +
2 New Design Systems +
5% More Coffee
The key takeaway here is that you should always be pragmatic, fact-check, and constantly experiment. My default choice is Tailwind, for the reasons I shared with other Tailwind fans. I have a limited amount of time and want to save brainpower for more advanced topics instead of constantly figuring out how to start a new project with newly developed conventions.
You might share the same perspective or a different one, but that's the beauty of our profession—we can still express our opinions freely. And I hope that never changes ☜(゚ヮ゚☜).