Mobile
Why your WooCommerce checkout breaks on mobile
Most of your traffic is on a phone and most of your revenue is not. Some of that gap is real buying behaviour, and some of it is five specific, measurable defects that almost never show up when you look at your checkout on a laptop. Here is how to find each one.
What this article covers
- A button can be "present" and still untappable. Zero width in a flex row, or under the keyboard, or trapped by a transformed ancestor.
- Test at short viewport heights, not just narrow widths. Height catches the below the fold failures that width never will.
- A full page screenshot hides exactly the bugs you are hunting, because it changes how sticky elements render.
- Autocomplete and inputmode attributes are the cheapest mobile win in checkout, and most themes omit them.
The size of the gap
Mobile is around 70% of ecommerce traffic, and converts at roughly half the rate of desktop: reported figures cluster around 2% on mobile against 3.4% on desktop. Cart abandonment shows the same split, with mobile in the low 80s against desktop around 70%.
Not all of that is your fault. Desktop buyers are disproportionately high intent people who saw the product on a phone earlier and came back to a laptop to buy. But a meaningful slice of it is defects, and defects are fixable in an afternoon.
There is a second cost that is easy to miss. Baymard's usability testing found that shoppers who hit layout quirks sometimes concluded the site had been hacked, which makes every defect below a trust defect as well as a usability one. That side of it is in why shoppers do not trust your store with their card.
The reason these survive so long: they are silent. None of them throw a JavaScript error, none appear in your logs, and none are visible in a desktop browser window dragged narrow. They show up only as slightly fewer orders, which reads as normal variance.
1. The button that is present, visible, and untappable
The single most expensive mobile checkout defect, and the hardest to see.
Your Place Order or Continue button sits in a flex row alongside something else: a back link, a price, a security badge. On a wide screen there is room. At 360 or 390 pixels there is not, and one of two things happens. Either the button wraps somewhere unexpected, or, if it has no explicit minimum width and its sibling has longer content than the designer tested with, it collapses to zero or near zero width.
A zero width button is still in the DOM. It still reports as visible. It still passes a check that asks "does the Place Order button exist". A shopper cannot tap it.
Why your testing missed it. Most people check a checkout with a short test name and one cheap item in the cart. Real orders have longer names, longer addresses, longer product titles and more line items. Overflow and collapse are content dependent, so a throwaway test cart is the one input guaranteed not to reproduce them.
How to check it
Do not ask whether the button exists. Assert four things, in this order:
- It exists in the DOM.
- Its rendered box is at least 44 by 44 pixels. The average adult fingertip covers 44 to 57 pixels of screen, and 48 by 48 is a safer target.
- Its box is fully inside the viewport, not off the right edge.
- A hit test at its centre point actually returns that button, and not an overlay sitting on top of it.
Point four catches a separate class of bug: a cookie banner, a chat widget or a sticky summary bar covering the button. The button is fine. Something is on top of it.
2. The sticky bar that is trapped, or under the keyboard
Mobile checkouts usually put the primary action in a sticky footer. Two CSS realities break this constantly.
The transformed ancestor trap
This one is genuinely obscure and catches experienced developers. If any ancestor of a position: fixed element has a transform, filter, perspective, backdrop-filter or will-change on it, that ancestor becomes the containing block. Your fixed footer is no longer fixed to the viewport. It is fixed inside a div somewhere up the page, and it scrolls away with it.
/* Somewhere in a theme, added for a hover effect or an animation: */
.checkout-panel { transform: translateZ(0); }
/* Three hundred lines later, in the mobile stylesheet: */
.place-order-bar { position: fixed; bottom: 0; }
/* ^ no longer fixed to the viewport. Nothing warns you. */A single translateZ(0), often added for GPU acceleration, is enough to do this.
The keyboard
A software keyboard covers 40 to 50% of a phone screen. If your sticky bar is positioned against the layout viewport rather than the visual viewport, opening the keyboard to type a postcode can put your Place Order button underneath it. The shopper sees the keyboard, dismisses it, the bar reappears, and they never realise anything was wrong. But every tap they made in that region went somewhere else.
Test this the only way that works: focus a field near the bottom of the form on a real device, with the keyboard actually open, and check the button is still reachable.
3. Horizontal overflow from one element
The page scrolls sideways. Everything looks slightly wrong and nothing looks obviously broken. It is almost always one element, and it is usually one of five:
- The order summary table. A product name that will not wrap, or a table with a minimum width.
- A long email address or coupon code in a container without
overflow-wrap: break-word. - A hardcoded pixel width in a theme's checkout CSS.
- A negative margin intended for a wide layout.
- An embedded payment iframe with its own minimum width.
Do not trust a simple overflow check. Comparing document.body.scrollWidth against the window width misses plenty of real cases, because a child can overflow its own container without extending the body. Find the offender by measuring every element's right edge against the viewport width and listing the ones that exceed it.
// Paste in the console on your checkout, at 390px wide.
// Lists every element sticking out past the right edge.
[...document.querySelectorAll('*')]
.map(el => ({ el, r: el.getBoundingClientRect() }))
.filter(x => x.r.right > window.innerWidth + 1 && x.r.width > 0)
.forEach(x => console.log(Math.round(x.r.right), x.el));4. The total the shopper cannot find
On desktop, the order summary sits in a sidebar and is always visible. On mobile it collapses to a "Show order summary" bar, usually at the top, and the total moves out of sight.
This matters more than it sounds. Unexpected cost is the top abandonment reason by a wide margin, at 40% in Baymard's data, and a further 12% abandon because they could not see or calculate the total cost up front. A collapsed summary does not create a surprise, but it does remove the reassurance that prevents one. Cost is the largest abandonment reason there is, and the rest of the ranked list is in how to reduce cart abandonment in WooCommerce.
Two fixes, both cheap:
- Always show the total on the collapsed bar, even when the item list is hidden. The shopper should never have to expand anything to see what they will pay.
- Put the total on the button. "Pay $84.50" outperforms "Place Order" for the same reason: it answers the question at the moment it is asked.
5. The wrong keyboard, and the missing autofill
The cheapest mobile checkout win available, and most WooCommerce themes leave it on the floor.
When a shopper taps the postcode field and gets a full QWERTY keyboard instead of a number pad, you have added several seconds and a few typos to every order. When the browser cannot autofill their address because the fields lack autocomplete attributes, you have added thirty.
<!-- What the fields should carry -->
<input name="billing_email"
type="email"
autocomplete="email"
inputmode="email">
<input name="billing_postcode"
autocomplete="postal-code"
inputmode="numeric"> <!-- numeric only where postcodes are -->
<input name="billing_phone"
type="tel"
autocomplete="tel">
<input name="billing_address_1"
autocomplete="address-line1">Use inputmode="numeric" only in countries with all digit postcodes. In the UK, Canada and the Netherlands it will block letters shoppers need.
Two more, while you are in there:
- Font size 16px or larger on inputs. iOS Safari zooms the page when you focus an input smaller than 16px, and the layout jumps. This is the cause of most "my checkout jumps around on iPhone" reports.
- Address autocomplete collapses five fields into one interaction, and is the single largest reduction in mobile typing you can make.
How to test properly
Three rules that matter more than any specific tool.
Test short heights, not just narrow widths
Everybody resizes to 390 pixels wide. Almost nobody tests a short viewport, and height is what catches below the fold failures: the CTA that sits just past the first screen, the trust badge nobody scrolls to, the error message that appears off screen. A layout can pass at 1920 by 950 and at 390 by 740, and fail at 1366 by 700. We have shipped that exact bug, and only the short viewport found it.
Never diagnose from a full page screenshot
A full page screenshot is taken by expanding the viewport to the document height, which changes how position: fixed and position: sticky elements render. Sticky bars appear in the wrong place, or appear correct when they are broken. For anything involving a sticky element or the fold, take a viewport screenshot at a known scroll position instead.
Reach the states that are hidden
Most of a checkout is not on screen when it loads. On a multi-step flow the payment step is behind two Continue clicks. The mobile order summary is behind a toggle. The coupon field is behind a link. Inactive panes are typically display: none, which means they compute as zero by zero and any measurement you take of them is meaningless.
So a check that says "the Place Order button is 200 pixels wide" while that step is hidden has not measured anything. Walk the flow to each state, then measure. If you cannot reach a state, you have not tested it, regardless of what your script reported.
The 10 minute audit
On a real phone, with a realistic cart: three items, a long product name, a long address.
- Load checkout. Does the page scroll sideways at all? Swipe left to check.
- Can you see the order total without tapping anything?
- Tap the email field. Does an email keyboard appear? Does autofill offer your address?
- Tap the postcode field. Number pad, or QWERTY?
- Does the page zoom or jump when a field is focused?
- With the keyboard open, is the primary button still reachable?
- Walk to the final step. Is the Place Order button full width and at least 44 pixels tall?
- Trigger a validation error. Does the message appear next to the field, on screen?
- Rotate to landscape. Does anything overlap?
- Complete a real order with a real card, then refund it.
Step ten is not optional. Everything above it can pass while the order still fails.
See a checkout built for the phone first
Every OptiCheckout template is rendered from the real plugin and tested at phone widths and short viewport heights. Open one on your own phone and run the audit above against it.
Read next
Checkout designHow to build a multi-step WooCommerce checkout
What Baymard actually concludes about multi-step versus one page, why most case studies are confounded, and the five mistakes that make it convert worse.
12 min read Checkout fieldsHow to remove or edit WooCommerce checkout fields
The working snippet, the four fields that are safe to remove, the four that will break your shipping and tax, and why the same code does nothing on blocks.
11 min read ConversionHow to reduce cart abandonment in WooCommerce
The ranked reasons people abandon, what each one is worth, and the two highest value fixes, neither of which needs a plugin.
13 min read