Administrator comparing a forum layout on a phone, a tablet, and a widescreen monitor

A forum that “works on mobile” is not a second style. XenForo already collapses to a single column, grows hit targets, and tucks secondary chrome into menus — that sentence is in the official PWA chapter. Discourse already splits a lot of its CSS by @media. Your job is to stop fighting those systems: use the style properties that already know about narrow viewports, test the composer and the quote control with a thumb, and be careful with “make it full width” components that look great on a 24-inch panel and bunched on a phone you never opened.

This is not the CSS / Less primer. That article is selectors, @xf- tokens, and extra.less. This one assumes you can write a rule. It is also not the typography file-hosting walkthrough, and it is not a second dark mode style. A “mobile-only dark style” is two chooser entries and a second bug. Responsive is width. Variations are palette.

Official XenForo sources: style properties (including layout / header / page width groups), Setup → PWA setup (responsive is listed as a PWA feature, not as a separate product), the public board as a guest. Discourse sources: notebook / Meta practice on @media splitting, the discourse-full-width-component, and the known-flaky quoting popup on mobile. If a breakpoint number is not on those pages, this article will not invent a magic 768px as “the XenForo breakpoint.” Inspect your compiled sheet.

What “responsive” means on a forum

Members do not say “responsive.” They say:

  • The post button is under my thumb.
  • The quote popup vanished.
  • The sidebar ate the thread on my tablet.
  • The line of text is 40 centimetres long on my ultrawide and I cannot read it.
  • I cannot hit Reply without opening Report.

Translate those into work:

Complaint Actual job
“The theme is not mobile” You added a fixed width, a hover-only control, or a second style
“Buttons are tiny” Touch targets. 44 CSS pixels is the usual accessibility floor, not a XenForo setting name
“The menu is a mess” Mobile nav / off-canvas. Stop adding tabs
“Desktop looks empty / bunched left” Max-width versus full-width. Discourse has a named component for this
“Composer is unusable” Fixed headers + 100vh + on-screen keyboard. Test on a real phone

Performance is part of this page because a 3 MB first screen is not “responsive” just because the columns stack. Images and webfonts have their own articles. Here: do not load desktop-only chrome on a phone if you can avoid it, and do not ship a hover gallery as the only way to reach Edit.

XenForo: properties, then a little Less

Start in Appearance → Styles → [child] → Style properties. Groups that usually own width and header behaviour (labels vary by style; open them, do not assume a vendor’s names):

  • Page / content width — the measure of the main column. A readable thread is not “as wide as the monitor.” Somewhere in the 1100–1400 px content range is where most Default-descended styles already live. Raising this to 2000 px because you bought an ultrawide is how post lines become unreadably long. If you need more room for a portal hero, that is a page-only sheet, not a global measure change.
  • Header and navigation / Header/logo row — sticky header, logo space, nav density. A tall sticky header plus a sticky staff bar plus a sticky thread title is how a phone has 120 pixels of thread left.
  • Node / forum list — row padding, icon column. The nodes article already warned: a 96-pixel crest in a 40-pixel gutter overflows the title on mobile.
  • Responsive / breakpoint switches if your style exposes them. Default XenForo has public CSS that collapses sidebars and moves nav into an off-canvas menu. Vendor frameworks add more toggles. Use a toggle before you write @media.

Then, and only then, extra.less.

XenForo’s public markup already has hooks. Inspect a phone-width window (DevTools device mode is a start; a real phone is the exam). You will see classes and off-canvas markup (.offCanvasMenu on stock). Do not clone PAGE_CONTAINER to “build a mobile header.” You will own that merge forever.

A safe pattern when a property does not exist:

@media (max-width: 650px) {
	.p-staffBar {
		// example only — inspect your compiled breakpoint first
		font-size: @xf-fontSizeSmall;
	}
}

Two honesty rules:

  1. Use the breakpoint XenForo already used, not a number you like. Inspect the core rule that hides the desktop nav. Match that width so your hide and theirs happen together.
  2. Tokens, not hex. Same as the primer. A mobile-only #fff still breaks the dark variation.

If @xf-fontSizeSmall is not on your style, use a unit or skip the tweak. Do not invent tokens.

Mobile nav is a menu, not a second sitemap

On a narrow viewport XenForo moves secondary items into menus. Official PWA feature list: single column, larger hit targets, secondary chrome in menus. Your job is to stop adding tabs.

Practical rules:

  • The public nav should fit the things a first-week member needs: forums, what’s new, one custom item you can defend. Landing and onboarding links can live in the footer or a notice.
  • Staff links belong in the staff bar, not in the public nav. Guests should not get a tap target for a room they cannot see. CSS display: none is not permissions.
  • Mega-menus and hover flyouts are desktop toys. If a section is only reachable on :hover, it does not exist on a phone. Provide a tap path.
  • Off-canvas should close on navigate and on the first backdrop tap. If a vendor style traps focus badly, that is a vendor bug — test before you buy, and test after every parent update.

PWA is adjacent, not the same job. Setup → PWA setup wants HTTPS, a ≤12-character short title, and 192 / 512 icons. That makes the site installable and enables push. It does not fix a 72-pixel sticky header. Do the layout work first.

The composer on a phone

Most “our forum is unusable on mobile” tickets are the reply box, not the forum list.

Test this on a real device, both variations, as a throwaway Registered user:

  1. Open a long thread. Tap Reply.
  2. Does the composer sit under a sticky header? Can you see what you type once the keyboard is up?
  3. Attach an image. Does the client-side resize path still work, or does the keyboard + file picker leave you in a broken overlay?
  4. Preview, then post. Find Edit on your own post. Find Quote on someone else’s.
  5. Open a conversation (mail pipe is a different article; the UI is this one). Same composer questions.

Fixes that stay in CSS / properties:

  • Reduce stacked sticky bars on small viewports. One sticky is a gift. Three is a bug.
  • Do not set height: 100vh on overlays without testing the keyboard. Mobile vh includes area the keyboard then covers.
  • Grow the tap target on .message-attribution controls if you customized them down to 12 px text with 4 px padding. Restore padding. Do not only enlarge the glyph.

Fixes that are not CSS:

  • A member on a 2018 Android with three add-on JS composers. Disable the extra editors on staging and retest stock.
  • A vendor “mobile message layout” that hides user info you still need for moderation. Check staff flow, not just the pretty guest screenshot.

Discourse: @media is how the product thinks

Discourse theme CSS is already organized around viewport. Notebook / community practice: split custom CSS by @media. Desktop rules in a desktop query, mobile rules in a mobile query. A 400-line unscoped theme sheet that assumes a 1440 px window will punch a phone in the face.

Operational split (use Discourse’s own breakpoints when you can see them in core; do not invent a third set):

/* Mobile-first additions */
.custom-hero { padding: 12px; }

@media (min-width: 768px) {
	.custom-hero { padding: 24px 32px; }
}

Theme components are how Discourse shares that CSS. Install fewer of them. Each component is a CSS + JS bundle someone else upgrades on their schedule.

discourse-full-width-component

This is the named component in the notebook. It lets the topic list and topic view use more of a wide desktop. That is a real job: Discourse’s default measure can look bunched left on a 27-inch monitor, with a large empty gutter that feels like unused product.

Use it when:

  • Your members actually sit at wide screens (an internal IT community, a sim-racing league with triple monitors).
  • You have looked at a topic, not just the latest list. Full width on a 200-character post is a long lonely line.
  • You still have a max-width on prose if the component lets the column grow past comfortable reading. A full-bleed frame with a readable measure is the goal. A 220-character line is not “modern.” It is tiring.

Do not use it when:

  • Most of the community is on phones. They will never see the win and they will see any CSS the component leaks downward.
  • You have not tested the topic map, the timeline, and the composer at that width.

After install: latest, a long topic, a short topic, user card, composer, both light and dark if you ship them. Theme components break on upgrade more often than core. Pin a known-good version if your host lets you.

Quoting is flaky on mobile

Notebook fact, stated plainly: the quoting popup is flaky on mobile. Members select text, expect the Quote / Reply balloon, and get nothing — or get it once, then never again until refresh.

What you should do:

  • Document a fallback in the welcome / first-month habits: the Quote button on the post, or reply and paste. Do not pretend the balloon is guaranteed.
  • Do not install a second quoting component to “fix” core. You now have two balloons.
  • Test before you blame a theme. Stock theme, no components, Android Chrome and iOS Safari. If stock fails, it is the known issue. If only your theme fails, your CSS (overflow, user-select, a transform on a parent) is a suspect.
  • Moderators quoting from the queue should use the desktop or the post menu, not a selection balloon, when they are on a phone on the bus.

This is not a XenForo ticket. XenForo’s quote is a post-menu action plus selected-text quote on desktop. Still test it. Do not assume it.

Touch targets, thumbs, and the 44-pixel floor

Neither official XenForo nor the Discourse notebook publishes “our buttons are 44×44.” WCAG / platform HIG energy is still the right floor: about 44×44 CSS pixels for anything a thumb must hit. Spacing between targets matters as much as size. Two 44 px buttons that share a 2 px gap are one fat-finger error.

Audit on a real phone:

Control Common failure Fix
Post / Reply / Create topic Pretty, padded-down vendor button Restore property padding
Quote / Like / Edit / Report Icon-only row packed in the attribution More padding; consider hiding Report behind a menu on mobile (core often already does)
Nav hamburger Hit area is the 16 px glyph Pad the button, not just the icon
Checkbox / reaction Tiny native box Do not shrink form controls in extra.less
Off-canvas close A 12 px × in the corner Bigger target + backdrop tap
Pagination Page numbers as 10 px links Use the core pager; stop restyling it to “minimal”

Hover-only is the other half of touch. Tooltips that contain the only copy of a permission error, :hover dropdowns with no :focus-within equivalent, drag handles with no button alternative — those are desktop assumptions. If staff must drag to reorder, give them a desktop. Do not tell a moderator their only sort tool is a hover handle.

Wide desktops without a second product

Ultrawide members will ask you to “use the whole screen.” Resist the urge to remove max-width globally.

Readable prose has a measure. Classic typography (and every newspaper) keeps line length in a range the eye can scan. A forum post is prose. A server list table is not. A media grid is not.

So:

  • Thread bodies and articles stay on a readable measure. XenForo’s default content width is already in that business. Discourse’s default is too. Full-width components should still protect the post column.
  • Indexes, galleries, dashboards can go wider. A portal hero, a media strip, a two-column widget row — those jobs want horizontal space. Scope the exception: a page-only <xf:css> on XenForo, a theme component or a category-specific class on Discourse.
  • Sidebars. XenForo can move the sidebar below content on small viewports (core behaviour). On a tablet in portrait, “below” can still be a long widget stack the member never asked for. Hide or shorten guest widgets on small widths rather than shipping the entire What’s online stack under every thread.

A child-style exception for a page node:

// only if you scoped it to that page's wrapper
.template-page_view .p-body-inner {
	max-width: 1200px;
}

Class names vary. Inspect. Do not copy a guessed template- class from a blog comment.

Performance is a viewport problem

A phone on LTE is the honest test. The CWV article owns guest cache, WebP, and icon sprites. This page only names the layout mistakes that show up as mobile performance:

  • A desktop hero slider on the index that loads four 2000 px JPEGs before the thread list. Use one image, sized, or no slider.
  • A custom webfont you did not subset (typography).
  • A theme component that injects a third-party script for a mobile menu you already had.
  • preload of desktop-only images.
  • Sticky everything, which costs main-thread work on scroll (INP), not just space.

Cloudflare “speed” toggles that rewrite JavaScript are a security / ops and a Discourse-specific landmine (disable JS minify / JS modifications or Discourse breaks). They are not a mobile optimization.

A 45-minute pass on an existing board

  1. Phone, guest, forum list. Can you reach What’s new and a forum in three taps?
  2. Phone, throwaway Registered, open a thread, Reply, type a sentence with the keyboard up, attach a small image, post.
  3. Quote via the post menu. Try selected-text quote. Note if it fails; do not “fix” it with a plugin on the same day.
  4. Tablet portrait. Is the sidebar under the thread? Is that acceptable? Hide one widget if not.
  5. Desktop at 1440 px and at 2560 px. Is the measure readable? If Discourse looks bunched, then evaluate discourse-full-width-component. If XenForo looks bunched, raise the page width a notch, not to infinity.
  6. Both XenForo variations. Dark + small + sticky header is where contrast dies.
  7. Staff account: moderation menu, Edit, move, merge. If staff tools require hover, give staff a desktop SOP.
  8. Optional: PageSpeed on a guest phone profile. If LCP is a hero image, that is the image article, not a breakpoint.

Three sessions: guest, member, staff. Two widths: ~390 px and your actual desktop. One real device. DevTools is a lie detector you should still confirm on glass.

What usually looks like a responsive bug

Symptom Likely cause First move
Horizontal scroll on a thread A table, image, or pre without overflow max-width: 100% on images; wrap pre; don’t paste 20-column tables
Double headers Vendor mobile header + core header Disable one
Composer under keyboard 100vh overlay + sticky header Test on device; reduce stickies
Quote balloon missing (Discourse) Known flake, or your overflow/transform Stock theme test; teach post-menu quote
“Full width” bunched left You expected the component to change latest only Read what the component actually wraps
Nav empty on phone You hid .p-nav globally to “clean desktop” Scope the hide to a min-width query
Dark mode unreadable on phone Hex in mobile @media Tokens; see the primer

What this is not

It is not a second XenForo style named “Mobile.” Official responsive layout is already the product. A second style is a second outdated-template queue.

It is not PWA setup. HTTPS, icons, short title, push — notifications.

It is not permission to fork PAGE_CONTAINER for a custom hamburger. Child extra.less + properties +, on Discourse, a small theme component.

It is not a Core Web Vitals deep dive. Link and leave: speed.

Checklist

  • No second “mobile style.” One style, properties + @media.
  • Page / content max-width is readable on a 27-inch monitor (prose measure protected).
  • Sticky chrome: one bar on small viewports.
  • Public nav is a short list; the rest is off-canvas or footer.
  • Touch targets ~44 px and spaced; no hover-only critical actions.
  • Composer tested on a real phone with the keyboard up.
  • Discourse custom CSS split by @media.
  • discourse-full-width-component only after a wide-desktop look at topics, not just latest.
  • Quoting: post-menu path documented; balloon treated as best-effort on mobile.
  • Images max-width: 100%; no desktop-only hero on the phone first screen.
  • Guest + member + staff, ~390 px + desktop, both XenForo variations.

Takeaways

  • XenForo is already responsive. You break it with fixed widths, hover-only UI, stacked stickies, and a second style. Properties first, a small @media in the child extra.less second.
  • Discourse wants CSS split by @media. The full-width component fixes a real bunched-left desktop. It is not a substitute for a readable measure, and it will not repair the quoting popup.
  • The quoting popup is flaky on mobile (notebook). Teach the post-menu quote. Do not install a second balloon.
  • Touch is padding and spacing, not a new icon font. Test the composer on glass.
  • Wide and narrow are different jobs. Let indexes go wide. Keep posts readable. Measure both.

Open the board on your phone before you buy a “mobile theme.” If you can post a reply with one thumb, you are most of the way there.