Why does my WooCommerce mini cart stop showing when I turn on Remove Unused CSS?
The one-sentence summary: your mini cart panel is hidden until someone hovers it, so a used-CSS pass removes its styles and a JavaScript delay stops it from opening. It comes back once you keep its styles in a safelist and let its scripts, cart fragments included, run.
You optimize the store, the PageSpeed report looks better, and a few hours later a customer emails: the cart icon does nothing. They hover it, nothing opens. Or it opens empty, or with no styling at all. You never touched the cart. You turned on a CSS optimization. So what happened?
The mini cart is the small cart icon in your header, usually with a count of items, and the panel that opens when you hover or tap it, listing what is in the basket. That panel is the part that breaks, and there are two reasons it breaks, often together.
What a mini cart actually is (and why it is fragile)
At page load, the panel is not meant to be seen. It sits hidden: display:none, or opacity:0 with visibility:hidden, or pushed off-screen. Nothing shows until you interact.
Two things make it appear. The CSS holds its hidden state and its open state, the rules that flip it to visible and position the panel. The JavaScript does the flipping: on hover or tap it adds a class that switches the panel on, or it builds and injects the cart contents on the fly. On WooCommerce that building is usually wc-cart-fragments.js, the script that keeps the mini cart and the item count in sync over AJAX.
Take away the right CSS, or stop the right script from running, and the panel never appears. Both happen when you optimize without telling the tool to leave the cart alone.
Cause 1: the CSS is hidden, so it gets removed
A used-CSS or remove-unused-CSS pass keeps the styles for what is visible when it renders the page, and drops the rest. Your mini cart panel is hidden at that moment, so the tool decides its styles are dead weight and strips them.
Two things break as a result. The rule that made the panel appear on open is gone, so hovering does nothing you can see. Or the panel’s own styling is gone, so it opens unstyled: a bare list with no positioning and no background, spilling into the page.
This is the same mechanism that strips a hidden mobile menu or a search overlay. The full explanation, and the fix that lasts, is in our guide on critical CSS breaking menus and overlays.
Cause 2: the JavaScript never fires
Even with the styles intact, the panel needs its script to open. If you delay or defer JavaScript, the script that adds the open class, or the one that builds the cart, may not be there when the visitor hovers.
On WooCommerce the usual suspect is wc-cart-fragments.js, plus the theme or side-cart script that handles the hover, plus jQuery underneath them. Delay the chain and the count stops updating, or the panel stays empty, or the icon is simply dead.
Deferring JavaScript is worth doing, but the cart interaction has to keep running. The method, excluding the whole dependency chain by URL fragment with a guard so it tolerates loading early, is the same one that fixes a two-tap burger menu, covered in the burger-menu guide.
One caution: do not disable wc-cart-fragments.js to save the AJAX request. That request has a real cost on every page, and you can limit where it runs, but killing it kills a live mini cart. Exclude it from the delay, do not remove it.
Diagnose it in 30 seconds
Turn the used-CSS option off for a moment. If the mini cart works again, the CSS is your culprit. Turn it back on and go straight to the safelist.
If the styles are clearly there but the panel still will not open, watch the Network tab: hover the icon and see whether wc-cart-fragments.js and the theme script load and run. If they fire late, or not at all, the delay is the culprit.
And check both mobile and desktop. Many engines keep a separate optimized version per device, so a cart that works on desktop can still be broken on mobile.
The exceptions to add
Keep the CSS (safelist). Protect the mini cart’s selectors from the pruning. The common WooCommerce ones:
- the core widget:
.widget_shopping_cart,.widget_shopping_cart_content,.woocommerce-mini-cart,.mini_cart_item,.cart_list,.cart-contents - the block cart, if you use it:
.wc-block-mini-cartand its children - the open state, which matters most: whatever class flips the panel to visible on your site (often
.active,.is-open,.open,.show) - your theme or side-cart plugin’s wrapper, which you will need to read off the page
A safelist depends on the plugin and the config, so it drifts. The version that survives a rebuild is to inline the hidden state and the full open styling in a block the optimizer is told to leave alone, placed after wp_head(). That method is in the critical-CSS guide.
Keep the JS (exclusions). Take the cart’s scripts out of the delay, as a chain:
wc-cart-fragments.js, the one that builds and updates the mini cartjQueryandjQuery Migrate, which it depends on- your theme’s or side-cart plugin’s script that handles the hover or toggle
Target them by a unique piece of their URL, not the internal handle, and make sure the excluded script tolerates loading early. Exclude the whole chain together, or you get the “excluded but dead” result: the cart is listed as excluded and still does not work.
A note for theme and plugin builders
If you build the cart, you can turn all of this into a one-line exception. Give the component a single namespace class, say minicart, and scope every rule under it: the hidden state, the open state, and every child.
.minicart { opacity: 0; visibility: hidden; }
.minicart.is-open { opacity: 1; visibility: visible; }
.minicart .item { /* ... */ }
.minicart .count { /* ... */ }Now the whole component is safelisted with one token, .minicart, and no optimizer can split it apart. Scatter the same styles across generic selectors like .cart-item or .flyout.open and each one needs its own safelist entry, which breaks the first time someone forgets one. This helps any optimizer, not only Mantys.
With Mantys Core
Mantys Core can run your whole performance layer, cache included, or sit next to the setup you already have. On a store, the mini cart is exactly the kind of thing it is built to protect.
it respects blocks you mark as non-optimizable, so the hidden and open styles of the cart survive;
it keeps JavaScript exceptions declared by URL fragment with a state guard, so cart fragments and the hover script keep running while the rest is delayed;
it regenerates CSS page by page, so your shop templates are not trimmed like a plain landing page;
and it handles mobile and desktop separately, so a cart that works on one is not broken on the other.
You keep the store working while the weight comes off, without babysitting a safelist.
In summary
- The mini cart is hidden until someone hovers it, so a used-CSS pass removes its styles and a JS delay stops it opening.
- Cause one is CSS: the hidden panel is judged useless and stripped. Cause two is JS: the script that opens or builds the cart never runs.
- Fix the CSS with a safelist, or better, a non-optimizable inline block for the hidden and open styles.
- Fix the JS by excluding the whole chain, cart fragments plus jQuery plus the theme script, from the delay, and never remove cart fragments.
- If you build the theme, put the cart under one namespace class so the exception is a single line.