In 2015, frontend developers faced a real problem. CSS class names existed in a single global namespace, which meant .button in one component could accidentally override .button somewhere else. As codebases grew, teams invented elaborate naming schemes—.header-navigation-primary-button-active—just to avoid accidentally styling the wrong element.
Then CSS Modules arrived with an elegant fix: automatically generate unique class names for every component. Write .button in your stylesheet, and the build system transforms it into Widget1_button_1FUOu. That hash guarantees uniqueness. No more naming conflicts. Developers could use simple, descriptive names and let tooling handle the rest.
Styled-components followed in 2016, generating dynamic class names at runtime. The pitch was compelling: write styles in JavaScript, get automatic scoping, never worry about CSS collisions. By 2017, component-based architecture with autogenerated selectors was becoming standard practice.
The problem was real. The solution worked. Nobody was thinking about what it would mean for systematic automation.
What Looks Stable Isn't
Most enterprises approaching web automation miss something fundamental: a website's visual design might stay consistent for months, but the underlying selectors—the identifiers automation relies on—regenerate constantly.
A site's visual design can remain unchanged for months while the selectors automation depends on regenerate with every build.
When we're building enterprise web agent infrastructure at TinyFish, this shows up everywhere. Those autogenerated class names that solved naming conflicts? They regenerate on every build. The hash changes whenever styles update or the build system runs. Widget1_button_1FUOu today becomes Widget1_button_2KpLm tomorrow.
For frontend teams, this is invisible. Components work. Tests pass. The site looks identical. But for systematic web monitoring—price checking across thousands of sites, competitive intelligence, compliance verification—every site update breaks the selectors automation depends on.
CSS Modules and styled-components generate class names to ensure uniqueness within an application. "Unique" means "different from other classes here," not "stable across builds." The hash comes from component path, styles, sometimes build timestamp. Change any input, the output changes.
At scale, this compounds. A single retailer might update their frontend weekly. Across an entire competitive landscape, you're managing constant selector volatility. Manual selector updates don't scale to thousands of sites. Elaborate fallback logic becomes its own maintenance burden. The infrastructure requirements are deeper than most teams expect.
One automation engineer put it plainly:
"brittle CSS selectors that break every time sites updated—a nightmare for web scraping."
When we're operating web agents across thousands of sites, we encounter this daily: monitoring for site structure changes, maintaining resilience strategies, codifying learning about how different sites evolve. It's not enough to have agents that navigate a site today. You need infrastructure that adapts as sites change tomorrow.
Optimizing for the 99%
Frontend developers made the right choice for their use case. Component-based architecture with autogenerated selectors genuinely solved workflow problems and made applications more maintainable. They weren't wrong.
But architectural decisions optimize for someone. Frontend tooling optimized for internal development teams—the 99% use case. Enterprise web automation operates in the 1% that nobody was designing for. The web wasn't built for systematic monitoring at scale. It was built for humans browsing with browsers.
Reliable web automation requires infrastructure depth most teams underestimate. The selector volatility that's invisible to frontend developers becomes an operational reality when you're maintaining reliability SLAs across thousands of properties, turning the live web into structured, reusable data. The challenge isn't technical cleverness. It's building systems that handle the consequences of optimization choices made for entirely different goals.
The web outgrew its original design, and the tools that made it better for developers made it harder for the systematic automation that enterprises now depend on.
Things to follow up on...
-
React's rapid adoption: By 2017, just four years after its 2013 release, React was loved by 67% of surveyed developers according to Stack Overflow—showing how quickly component-based architecture became standard.
-
CSS-in-JS philosophy shift: The move to CSS-in-JS represented a fundamental rethinking where "the main building block of our app is now the component" and styling became an integral part of the component itself, not a separate concern.
-
Resilient selector strategies: Automation engineers developed coping mechanisms like targeting stable parent elements and navigating to child selectors rather than direct targeting, though this adds complexity to maintain.
-
The maintenance treadmill: What practitioners describe as "the biggest hidden cost" of web automation—every site update risks breaking scripts, forcing developers to spend hours debugging instead of scaling workflows.

