We've all been here at some point:
— It doesn't work for me, the layout is broken.
— Have you cleared your browser cache?
— Oh, yes, I cleared it, now it works, thank you very much!
Nice, it feels like you've solved the problem and you're a good boy. However, the further we get from the 2000s, the more often instead of a simple "thank you very much" you hear:
— Thanks, I cleared it, it works now. Now please help me call all the site's visitors and tell them to clear theirs too.
Not so nice anymore. But, as they say, where is the client wrong? Cache busting techniques have existed for many years, and not using them in the mid-'20s is, well, meh.
So what's the point here. The point is that once the browser has downloaded the site's styles bundled into a single file (style.css, for example), it doesn't want to download it a second time. So that the page opens and renders faster for the user. And when you've changed the stylesheet — fixed something, added something, improved something — the browser won't download it again. Well, because it already has a copy, why bother. And only when you tell the browser (with Ctrl+F5 or Ctrl+Shift+R) to reload the page, downloading everything again, will the updated styles.css get downloaded.
But we obviously can't and don't want to make all our visitors do that. And we do want them to see our beautiful new styles. So we somehow need to tell each visitor's browser that the file is outdated and needs to be downloaded again. How do we do that?
Don't cache anything
You can configure the server to send headers telling the browser not to cache assets (styles, scripts, images) at all. This solution is terrible, of course: page load speed will drop, and the PageSpeed score along with it, which will affect SEO. And it's kind of weird anyway.
Cache busting via the file URL
Browsers treat a URL with some junk added to the query as unique. For example, https://mysite.ru/styles/all.css and https://mysite.ru/styles/all.css?some-junk are two different URLs. So if you add some junk to the URL every time you update the styles, the browser will download the file again. Only the junk has to be new every time. Some hash, for example, or a timestamp.
By the way, this is a universal way to quickly check if you suspect something isn't working right because of server-side caches. Add ?abcdef to the URL and see if anything changes.
Of course, you don't have to add it to the query, you can change the path or the file name. Say, rename all.css to all.v.1.0.css, all.v.1.1.css and so on.
What, by hand?
No, of course not. Frontend bundlers — Mix, Vite and the like — use exactly this technique to update scripts and styles. They generate some unique string (a hash) and add it to the URL of the aggregated JS and CSS files, or change the file name itself. You can see how it works by simply installing any Laravel Starter Kit.
In Drupal, aggregated JS and CSS files also busted the cache by changing the file name. But in recent versions they got too clever with library versions for some reason, so now if a library whose CSS has changed hasn't changed its version, the engine won't rebuild it, or will rebuild it with the same name. And cache busting won't work. So in D10/11 you need to be more careful.
One more thing
Besides CSS and JS, browsers also cache images just as aggressively by default. So if you're replacing, say, a logo, use the same technique, or simply use a different file name — otherwise users will have to clear their browser cache to find out that anything has changed at all. This is especially true for site icons (favicons): browsers cache them especially fiercely.
And do you still ask clients to clear their browser cache on live sites?