fix(www): prevent mobile blog layout overflow (#49983)

## I have read the CONTRIBUTING.md file.

YES

## What kind of change does this PR introduce?

This PR fixes a mobile layout bug on blog posts where long unwrapped
URLs made the article column wider than its flex parent. With
`justify-center`, that overflow centered the column and clipped content
on both sides. It also hardens the reading progress bar so it no longer
uses `100vw`, matching the overflow-safe pattern already used on
changelog prose.

## What is the current behavior?

- On mobile Safari, `/blog/are-supabase-docs-agent-friendly` shifts left
with empty space on the right and clipped title/body text
- A raw long URL in a blockquote (`row-level-security.md`) expands the
flex column past the parent width
- The reading progress fill uses `w-screen` (`100vw`) with a negative
`translate3d`, which can widen layout outside the blog `overflow-x-clip`
shell

## What is the new behavior?

- Blog main column uses `min-w-0 w-full` so flex children cannot outgrow
the parent
- Blog prose uses `wrap-break-word` (same as changelog) so long URLs
wrap
- Scroll progress bar uses parent width plus `overflow-hidden` instead
of `w-screen`

## Additional context

- Branch: `fix-docs-agents-blog-post-on-mobile`
- Files: `apps/www/components/Blog/BlogPostRenderer.tsx`,
`apps/www/components/ScrollProgress.tsx`
- Verification:

| Check | Result |
| --- | --- |
| Production at 390px: title `h1` left ≈ -42 (shifted) | pass
(reproduced) |
| Preview at 390px: title `h1` left = 24, right = 366 | pass |
| `scrollWidth === clientWidth` on preview | pass |
| Progress bar still fills on scroll | pass |
| Hero image still `hidden lg:block` (unchanged) | pass |

### Proof: mobile blog no longer shifts left

**Verified:** production before vs PR www preview after, both captured
at CSS viewport 390×844 via `page.setViewport` (not Chrome
`--window-size`)

| [Before
(production)](https://supabase.com/blog/are-supabase-docs-agent-friendly)
| [After (PR
preview)](https://zone-www-dot-com-git-fix-docs-agents-blog-post-4e52df-supabase.vercel.app/blog/are-supabase-docs-agent-friendly)
|
| --- | --- |
|
![Before](https://moijyfpvgnmgoxvwcikq.supabase.co/storage/v1/object/public/pr-proof/supabase/supabase/pr49983/mobile-blog-overflow-before-219e3df5.png)
|
![After](https://moijyfpvgnmgoxvwcikq.supabase.co/storage/v1/object/public/pr-proof/supabase/supabase/pr49983/mobile-blog-overflow-after-85f7751b.png)
|

- **Before:** https://supabase.com/blog/are-supabase-docs-agent-friendly
- **After:**
https://zone-www-dot-com-git-fix-docs-agents-blog-post-4e52df-supabase.vercel.app/blog/are-supabase-docs-agent-friendly

### Test plan

- [ ] Open
[production](https://supabase.com/blog/are-supabase-docs-agent-friendly)
at ~390px and confirm the clipped/shifted layout
- [ ] Open the [PR www
preview](https://zone-www-dot-com-git-fix-docs-agents-blog-post-4e52df-supabase.vercel.app/blog/are-supabase-docs-agent-friendly)
at ~390px
- [ ] Confirm title, authors, and body are fully visible with no empty
strip on the right
- [ ] Confirm `document.documentElement.scrollWidth ===
document.documentElement.clientWidth`
- [ ] Scroll and confirm the green reading progress bar still fills
- [ ] Spot-check another blog post without a raw long URL for no layout
regression

Co-authored-by: Nik Richers <nik@validmind.ai>
This commit is contained in:
Nik RichersandNik Richers authored and GitHub committed 2026-09-04 03:13:09 +00:00
1 parent 0322720743
commit 8a41a74e36
2 files changed
+4 -4

No files matched your search

@@ -109,7 +109,7 @@ const BlogPostRenderer = async ({
*/}
<div className="flex justify-center lg:grid grid-cols-12 gap-x-8">
{/* Main container — indented 1 col at lg, alongside back button at xl */}
<div className="max-w-[65ch] lg:max-w-none col-span-12 lg:col-start-2 lg:col-span-10 xl:col-start-2 xl:col-span-11">
<div className="min-w-0 w-full max-w-[65ch] lg:max-w-none col-span-12 lg:col-start-2 lg:col-span-10 xl:col-start-2 xl:col-span-11">
{/* Article header — spans the full main container width */}
<div className="py-8 md:py-12 space-y-4">
<div className="flex items-center gap-1.5 text-foreground-lighter text-sm">
@@ -202,7 +202,7 @@ const BlogPostRenderer = async ({
)}
<article>
<div className="prose prose-docs">
<div className="prose prose-docs wrap-break-word">
{blogMetaData.youtubeHero ? (
<iframe
title="YouTube video player"
+2 -2
View File
@@ -33,9 +33,9 @@ const ScrollProgress = () => {
let isActive = progressPercentage <= 100
return (
<div className="h-[2px] w-full flex justify-start relative">
<div className="relative h-[2px] w-full overflow-hidden">
<div
className="h-full top-0 bottom-0 right-0 absolute w-screen bg-brand will-change-transform transition-opacity"
className="absolute inset-y-0 left-0 right-0 h-full bg-brand will-change-transform transition-opacity"
style={{
display: isActive ? 'absolute' : 'relative',
transform: `translate3d(${isActive ? progressPercentage - 100 + '%' : '0'},0,0)`,