Most “the theme is broken” tickets are one of six things. You edited extra.less on the parent and you are serving the child. A template went outdated and nobody merged it. A framework rebuild hit too many open files. A hard-coded hex survived into the dark variation. A portal slider is fighting lazy-load. Guests still have last week’s CSS because LSCache or guest page cache was never purged.
This is the cookbook. Symptom, cause, first move. It assumes you already ran the pre-flight checklist or that you skipped it and now you are here. It is not how to enable 2.3 variations. It is not a buy-versus-commission argument. If the board is down because you replaced internal_data/ during an upload, that is the backup article, not a style bug.
Official sources: styles, style properties, and the upgrade note that customized templates are not overwritten — they go outdated. Community sources fill extra.less, UI.X file limits, XenPorta sliders, and LiteSpeed Cache. If a knob is not in those places, this article does not invent it.
How to use this page
Reproduce the bug as a guest in a private window before you touch the ACP. Then as a throwaway Registered. Then as staff. The configuration mistakes article already told you that an admin session is a different site.
Write down:
- Which style is the public default (Appearance options).
- Whether you are looking at the child or the vendor parent.
- Whether variations are on, and which half is broken.
- Whether guest page cache or LiteSpeed Cache is on.
Then jump to the symptom. Do not import a second style to “fix” the first.
1. extra.less does nothing
Symptom. You saved CSS. The public site ignores it. Staff insist the file “has the rules.” View-source or the browser inspector shows the old sheet.
Usual cause. You edited extra.less on a style you are not serving. Community standard: custom CSS lives in the child’s extra.less. It is not a page in the official styles manual. It is also not overwritten by core upgrades when you keep it in the child. If you typed the rules into Default or into the vendor parent, and Appearance default is the child, the child inherits the parent’s templates only until the child has its own extra.less. A customized empty (or old) child extra.less overrides the parent’s, so the parent’s new rules never arrive.
The other usual cause: you edited Master in a tool you should not have used, or you put the CSS in a template modification that no longer matches.
First moves.
- Appearance → Styles. Note the default. Open that style, not the one with the pretty name.
- Open Templates, find
extra.lesson that style. Confirm your rule is actually there. - If the rule lives on the parent, copy it into the child’s
extra.lessand save. Do not keep two copies that will drift. - Hard refresh a guest window. If guests still miss it, skip to §6 cache.
- If you split files, include them from the child’s
extra.less:
<xf:include template="your_custom_file.less" />
The include is community practice. The included template must exist on the same style (or be inherited and not overridden with an empty child copy).
TMS into extra.less. A template modification that appends to extra.less is how you share a tweak across several colour children without pasting. If the TMS is disabled, or bound to an add-on that is disabled, the rule is gone. Appearance → Template modifications — look for a row on extra.less.
What not to do. Do not paste the same CSS into PAGE_CONTAINER. Do not add a second style “just for this rule.” Do not put a novel of page-specific CSS in global extra.less — 2.3 unbundled CSS; a huge global sheet invalidates more than you think. Page-only CSS belongs in <xf:css> on that page.
2. The header (or one page) looks like last year’s style
Symptom. Logo row is the new parent. Thread view is the old markup. Or a single template still has your 2022 hero.
Usual cause. A directly edited template. Official: customized templates are not overwritten on upgrade or on a parent update. They become outdated. Until you merge them, the board runs your old HTML against new PHP.
Appearance → Outdated templates.
- Blue — auto-merged. Still read it. Auto-merge is not a personality test.
- Yellow — conflict. You must merge by hand. This is the one that leaves a missing 2.3 control or a doubled wrapper.
Official warning, already in the upgrade article: important or new functionality may be broken or missing if an outdated template remains unmanaged. A style parent swap is the same queue.
First moves.
- Open the outdated list on the child you serve, and on the parent if you customized the parent (you should not have).
- Merge immediately. Do not “leave it until the weekend.”
- For each yellow: take the parent/core version as the base, re-apply only the lines you still need. Do not paste your entire 2.2
PAGE_CONTAINERback to “restore the hero.” - Prefer a template modification (find/replace, simple or regex) over a direct edit next time. Bind it to an add-on ID if the tweak belongs to that add-on.
What not to do. Do not revert the parent ZIP over the live tree to “make outdated go away.” That is how you replace data/ and internal_data/ if an FTP client is sloppy. Merge in the ACP.
If the list is empty and one page is still old, you are looking at a widget or a page node with hardcoded HTML. Those are not templates in the style tree. Open Appearance → Widgets and the page node. Inline style="color:#…" will not follow a new palette.
3. Style rebuild dies: too many open files
Symptom. UI.X (or another framework) rebuild spins, whitescreens, or the host logs too many open files. The public site may be half-compiled: missing CSS, missing icons, ACP still up.
Usual cause. Community: a UI.X rebuild can open more files than a cheap host’s open_files_limit allows. Shared hosting defaults are often a few thousand. A framework style is a lot of templates.
First moves.
- Do not hit Rebuild again from three browser tabs.
- Raise
open_files_limit(community example that has worked: 50000) at the PHP / LiteSpeed / Apache level your host actually uses. On a VPS you control this. On shared hosting you open a ticket and you do not invent a XenForo option that does not exist. - Rebuild via CLI if you have SSH. Community practice is to let the rebuild run in a shell so the HTTP request cannot time out. This article will not invent a
xf:command name the vendor did not print in front of us — runphp cmd.phpon the XenForo root and read the list, or use the vendor’s documented rebuild. If you are not already a CLI board, ask the host to raise the file limit and use the ACP once. - When it finishes, purge guest CSS (§6) and walk both variations.
Prevention. Rebuild frameworks on staging first, which is why the checklist exists. Production should be “the rebuild already completed on a clone.”
This is not a XenForo core bug and not a reason to abandon the parent. It is a host limit. The premium-versus-custom piece is where you decide whether a framework’s rebuild tax is worth it.
4. Dark mode is black-on-black (or the flip does nothing)
Symptom. The variation gadget does nothing. Or it works and the thread list is dark text on a dark background. Or only the header went dark.
Usual causes, in order.
| What you see | Likely cause |
|---|---|
| Flip does nothing | Variations not enabled on the active style |
| Flip works, first paint always light | OS / prefers-color-scheme not applied, or a second style forced |
| Dark is unreadable | Style type still Light on the dark variation, or hex in extra.less |
| Only the header went dark | You edited Header properties, not the Color palette |
| Email is a dark brick | HTML email uses the public style’s dark default |
| Staff say it looks fine | They never left the ACP |
Hard-coded hex is the one this cookbook owns. Official colour machinery: Color palette chips, then Basic colors roles, referenced as @xf-paletteNeutral3 and @xf-textColor. Official Less helpers xf-intensify and xf-diminish are variation-aware — they darken a light variation and lighten a dark one. A rule like background: #1a1a1a in extra.less is not variation-aware. It is the same paint on both halves. On the dark half it is a hole.
First moves.
- Confirm variations are enabled on the style Appearance default actually points at. The switcher article is the how-to.
- Palette: style type Light on the light half, Dark on the dark half.
- Open the child’s
extra.less. Search for#. Every hit on a shared surface is a suspect. Replace with@xf-…tokens or wrap inxf-intensify/xf-diminish. - HTML widgets and page-node HTML: search for
style=". Inline hex will not flip. - Node icons: 2.3 is SVG sprites. A leftover
content: "\f019"webfont trick from 2.2 will not put the icon in the sprite, and a white fill on a white unread state is a variation bug. The nodes article has the extra.less pattern; check both halves. - Email: Appearance options → default style for HTML email → a light style. Send one message.
What not to do. Do not install a third-party “dark mode switcher” that loads a second style via JavaScript. That is a 2.2 answer. Do not create “Board Dark” as a sibling style. That is two merge queues.
2.3.8 keeps the variation preference on logout (community / notebook). If a member reports the flip resetting, check the version before you write a cookie hack.
5. The slider is blank, jumps, or never paints
Symptom. XenPorta (or another magazine homepage) shows an empty hero, a flash of unstyled slides, or a layout jump after load. PageSpeed blames LCP / CLS. Members say “the homepage is broken” even though /forums/ is fine.
Usual cause. A slider that waits on JavaScript, fighting a lazy-load add-on or a theme that lazy-loads images the slider expected to be in the first paint. Community: XenPorta 2 sliders and lazy-load are a known pairing that goes wrong. The speed article already listed “a portal slider that waits on JS” as an LCP cause and “a lazy-load add-on fighting a slider” as a CLS cause.
This is not always the new style. Swapping a parent often enables the parent’s own lazy-load or a different image markup, and the slider you never retuned starts missing.
First moves.
- Confirm Index page route (Setup → Options → Basic board information). If the root is a page node or a XenPorta route, you are debugging that page, not “the theme.”
- Disable lazy-load on the slider’s images only. Do not disable lazy-load for the whole board because one hero is precious.
- Give the hero a reserved height in CSS (child
extra.less) so the thread list does not jump when the slide arrives. - Do not autoplay a live stream or a heavy video in the first screen. The streaming article already said no auto-embed on
/. - If XenPorta is unmaintained relative to your 2.3 parent, treat the slider as optional. Stock Featured content + an HTML widget on the forum-list portal is the replacement that does not need a CMS.
What not to do. Do not install a second portal to fix the first. Do not fork PAGE_CONTAINER to hard-code three banners. That fork is §2 next upgrade.
6. Guests still see the old CSS
Symptom. You are logged in and the new style is perfect. A private window shows the old header, or a mix: new HTML, old colours. Members on phones (often guests or rarely logged-in) file “you rolled it back.”
Usual cause. Guest page cache or LiteSpeed Cache for XF2 is serving a cached HTML document that still points at an old css.php URL, or the HTML is new and the CSS URL is cached. Community: guest LSCache serving old CSS is a classic after a style flip.
Official guest page cache: $config['pageCache']['enabled'] plus a dedicated $config['cache']['context']['page'] provider. Without the context, official page cache does not run — but LSCache is a different product and does not read that array.
First moves.
- Purge guest HTML and CSS. One without the other is how you get the mix.
- LiteSpeed Cache: use the add-on’s purge, not only “clear LSCache” in a panel that never saw
css.php. - If you also have Cloudflare (or similar) caching HTML, purge that too. Do not enable Auto Minify as part of the panic; 2.3 already minifies and defers JS.
- Confirm you are not looking at a member who still has an old style ID stored because user style selection was on. Turn the chooser off, or ask them to pick the new default.
- Cookie path / Board URL: if everyone looks like a guest, you have the mistakes article’s cookie bug, and guest cache is now caching “logged-out” for people who never logged in. Fix the cookie before you purge again.
What not to do. Do not disable all caching forever because a style flip was cached. Purge, then leave cache on. Do not rebuild caches in Tools as a superstition for this symptom — that rebuild is PHP data caches, not LSCache’s HTML.
7. Related breakages you will hit in the same week
These are not the six headlines, but they arrive in the same queue.
Logo missing or huge
Style properties: Header/logo row and the logo asset on the style. A parent swap can reset the logo to the vendor demo. Re-upload on the child. Check both variations — a light-only PNG vanishes on dark. SVG or two assets, not a white wordmark on a white header.
Fonts look like a different product
Typography sizes and families are style properties. @font-face in the child’s extra.less is community practice. Self-host the files. Do not add a Google Fonts CDN to “fix” a parent that shipped a different stack — site policy and performance both say no. If the parent expected a font file you did not copy, add the file or point the property at a stack you actually host.
Icons are empty bubbles
2.3 SVG sprites + Icon Usage Analyzer. A child that still emits 2.2 webfont markup shows the default bubble, a missing glyph, or both stacked. Run the analyzer after the parent swap. Community Font Awesome Manager (Kirby) was a 2.1/2.2 answer; start with stock on 2.3.
jQuery errors in the console
2.3 removed jQuery as a core dependency. A style or add-on that still calls $('selector') will fail after a 2.3 parent lands. That is an add-on/parent version problem, not extra.less. Disable the add-on or get a 2.3 build.
“Fresh install” wizard after you uploaded a style ZIP
You did not upload a style. You replaced the web root. Recreate internal_data/install-lock.php if it is missing, restore data/ and internal_data/ from backup, and never let an FTP client replace those directories. The backup article is the rest.
Permission or widget positions “broke”
They probably did not. A new parent moves widget position chrome or assumes different templates. Appearance → Widgets — confirm each instance still has a position that exists on the page you actually serve. If you changed Index page route or Forums default page in the same window, forum-list positions vanish from the first screen. That is the portal trap, not a broken ZIP.
Prefixes and listing cards look unstyled
Server listing prefixes and stream directory chrome often live in child extra.less against last year’s palette. After a parent swap, retune the prefix classes. Do not install a card-grid add-on to replace a colour.
A 30-minute triage order
When the board is public and ugly, do not start at a random heading. Walk this sequence.
- Which style is default? If it is not the child you think, stop. Fix the option.
- Guest private window. If guest ≠ logged-in, go to §6 first.
- Outdated templates. Yellow first. Merge.
- Child
extra.less. Is the rule on the style you serve? Search#. - Variations. Enable, types Light/Dark, hex out of extra.less.
- Widgets / XenPorta / slider. Disable lazy-load on the hero only; reserve height.
- Framework rebuild. If the sheet is half-missing, treat it as §3, not as “CSS is hard.”
- One add-on. Disable the last thing you installed with the parent. If the bug vanishes, that add-on is the ticket.
One variable at a time. If you purge cache, merge templates, and rewrite extra.less in the same minute, you will not know which fix worked.
Worked example: “we installed a 2.3 parent on Friday”
A mid-size board. Child of Default, a year of extra.less, XenPorta on /, LiteSpeed Cache for guests, variations enabled last month.
Friday: import UI.X 2 as a new parent, re-parent the child, hit rebuild, leave for dinner.
Saturday tickets:
- Guests see Default’s header.
- Logged-in members see UI.X with black-on-black quotes.
- Homepage slider is an empty box.
- ACP: outdated
PAGE_CONTAINERyellow; rebuild log mentions open files.
Monday that should have been Saturday:
- Raise file limit, finish the rebuild on CLI or after the host change. Purge LSCache HTML+CSS.
- Merge
PAGE_CONTAINER. Do not paste the 2024 hero back. Put the hero in a widget. - Move every extra.less rule that still lives on Default into the child. Delete the Default copy so it cannot drift.
- Replace
#222quote backgrounds with@xf-tokens. Check the dark variation. - Turn off lazy-load on XenPorta’s hero images. Give the hero a min-height.
- Guest / Registered / staff on both variations. Send one email. Confirm the email style is still light Default.
That is a morning. It is not a reason to commission a custom style the same day.
extra.less inheritance, drawn as a picture
Official inheritance is about properties. Community extra.less follows the same override rule and that is the part people miss.
- Parent
extra.lesshas a rule. Child has no customizedextra.less. The child inherits the parent’s file. Your rule appears. Good. - Parent
extra.lesshas a rule. Child has a customizedextra.lessthat does not include that rule. The child overrides. The parent’s rule is gone. This is the “I put it in Default and I serve Board” ticket. - Child
extra.lessincludes the parent file with<xf:include>and then adds more. Explicit, boring, correct. - A TMS appends to
extra.lesson every style the modification applies to. If you later customize the child’sextra.less, confirm the TMS still matches. A find string that no longer exists is a silent no-op.
When you re-parent a child onto a new vendor style, open the child’s extra.less first, before you blame the new parent. Half the “UI.X broke our prefix colours” tickets are a child file that still talks to last year’s class names.
Debug order that saves an hour:
- ACP: which style is Default style?
- Templates: does that style have a customized
extra.less? (Customized templates are marked in the list.) - Browser inspector: is your selector in the compiled CSS at all? If no, you are not serving that file, or cache has an old
css.php. If yes but it loses, you have a specificity fight with the parent — that is CSS, not “XenForo ignored me.” - Guest window after a purge. Only then start rewriting selectors.
Who owns which ticket
Style problems get bounced between “the theme guy,” hosting, and the add-on author. Assign them before the thread turns into a blame circle.
| Symptom | First owner | Not first |
|---|---|---|
| extra.less missing | Whoever last edited styles | The vendor |
| Yellow outdated template | You (merge) | The vendor, until you have merged and it still fails |
| Too many open files | Host / you (limit or CLI) | ThemeHouse as a “bug” |
| Hex vs dark variation | You (tokens) | 2.3 “broke dark mode” |
| Empty XenPorta slider | You (lazy-load + index route) | Core XenForo |
| Guests see old CSS | You (purge LSCache / page cache) | The new parent |
$ is not a function |
Add-on author (2.3 build) | The style, unless the style’s own JS is the caller |
| Fresh-install wizard | You (files replaced) | The style ZIP |
If you paid for a parent and the demo shows a control you do not have after a clean child, then it is a vendor ticket. Attach: XF version, parent version, child yes/no, guest screenshot, and the outdated-template list. “It looks wrong” is not a ticket.
What this is not
It is not a CSS primer. Selectors and LESS mixins can wait for a later tutorial. It is not permission to run designer mode on production. It is not a hosting upgrade guide, even when the file limit is the host. It is not how to pick UI.X versus a $30 DohTheme — that is the next article.
If you have not taken a backup this week, take one before you merge yellow templates. Merge is the right fix. Merge is also a thing you might want to undo.
Takeaways
extra.lesson the parent does not style a child that has its own copy. Edit the style you serve.- Outdated templates are the old page. Merge; do not paste last year’s
PAGE_CONTAINER. - UI.X-class rebuilds can hit too many open files. Raise the limit or rebuild off HTTP.
- Hex in extra.less is how dark variation dies. Tokens and
xf-intensify/xf-diminish. - XenPorta sliders plus lazy-load is an empty hero, not a “bad theme.”
- Guest LSCache / page cache will serve old CSS until you purge HTML and the sheet.
Fix the one symptom in front of you. Then go back to the checklist and tick the boxes you skipped.

