style: mobile — hoist buy CTA above the title, split product-right
The right column was a single .product-right that wrapped the buy zone
(price + Add to Cart + preview + auction/offer) AND the related content
(comments link, price history, watch queue, related products) in one
node. Hoisting it to top of the mobile stack would put the related grid
above the title — too much chrome before the title even appears.
Split into two sibling sections, both still carrying .product-right
so existing button/cinema/centering rules apply unchanged:
- section.product-purchase — buy zone
- section.product-related — comments link, price history, watch
queue, related products
Mobile (≤800px) order:
0 product-purchase ← above the title
1 product-images (title + cover + thumbnails)
2 product-description
3 product-comments
4 product-related (no longer crowding the title)
Desktop (≥960px) grid-template-areas:
"images purchase"
"description related"
"comments related"
So purchase sits at the top of the right column (where the price has
always lived) and related spans the two rows below — the page hierarchy
stays identical to before on desktop, but mobile finally gets the CTA
to the top of fold.
Cinema-mode grid + watch-mode mobile/desktop rules updated to address
both new grid areas. CLAUDE.md Mobile Layout section rewritten.
Product/watch/cinema test slice (37 tests) still green.
This commit is contained in:
parent
81c051e3fc
commit
8b25285647
3 changed files with 82 additions and 49 deletions
29
CLAUDE.md
29
CLAUDE.md
|
|
@ -389,15 +389,28 @@ normal redirect flow on any error.
|
||||||
## Mobile Layout
|
## Mobile Layout
|
||||||
|
|
||||||
On mobile (`max-width: 800px`), our product page reorders to single column
|
On mobile (`max-width: 800px`), our product page reorders to single column
|
||||||
with the **buy CTA promoted up** so a tablet/phone buyer doesn't have to
|
with the **buy CTA promoted ABOVE the title** so a phone buyer sees price
|
||||||
scroll past the description and comment thread to find Add to Cart.
|
+ Add to Cart immediately, before scrolling. The old right-column section
|
||||||
Desktop two-column already keeps `product-right` visible as a side panel;
|
was split into two siblings (`.product-purchase` + `.product-related`,
|
||||||
this mobile rule mirrors that intent:
|
both also carry `.product-right` so legacy styling still applies). Order:
|
||||||
|
|
||||||
1. `product-images` (order 1) — sticky in watch mode
|
1. `product-purchase` (order 0) — price, Add to Cart, preview, auction/offer
|
||||||
2. `product-right` (order 2) — price, Add to Cart, Preview, related content
|
2. `product-images` (order 1) — title, cover image, thumbnails; sticky in watch mode
|
||||||
3. `product-description` (order 3)
|
3. `product-description` (order 2)
|
||||||
4. `product-comments` (order 4)
|
4. `product-comments` (order 3)
|
||||||
|
5. `product-related` (order 4) — comments link, price history, watch queue, related products
|
||||||
|
|
||||||
|
Desktop (`@media (min-width: 960px)`) uses `grid-template-areas`:
|
||||||
|
|
||||||
|
```
|
||||||
|
"images purchase"
|
||||||
|
"description related"
|
||||||
|
"comments related"
|
||||||
|
```
|
||||||
|
|
||||||
|
So `product-purchase` sits at the top of the right column next to the
|
||||||
|
image (where the price has always lived) and `product-related` spans the
|
||||||
|
rows below.
|
||||||
|
|
||||||
Cinema mode is a no-op on mobile (gated on `@media (min-width: 800px)`).
|
Cinema mode is a no-op on mobile (gated on `@media (min-width: 800px)`).
|
||||||
The normal watch-mode mobile stack already gives full-viewport-width media
|
The normal watch-mode mobile stack already gives full-viewport-width media
|
||||||
|
|
|
||||||
|
|
@ -2634,13 +2634,21 @@ textarea.markup-editor-textarea {
|
||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Section order on tablet + phone: images first, then product-right
|
/* Section order on tablet + phone: the buy zone (price + Add To
|
||||||
(price, Add to Cart, Preview, Up Next) so the buy CTA is at the
|
Cart + preview / auction / offer buttons) is hoisted ABOVE the
|
||||||
top — not buried below description + comments. Desktop two-column
|
title — that title lives inside .product-images, so order:0 on
|
||||||
keeps product-right as a side panel where the CTA is always
|
.product-purchase lifts the well above the entire image block.
|
||||||
visible alongside the image; mobile lifts it up so a buyer doesn't
|
Related content (comments link, price history, related products)
|
||||||
have to scroll past the entire description and comment thread to
|
falls to the bottom so it doesn't push the title off-screen. */
|
||||||
find the button. */
|
section.product-purchase {
|
||||||
|
order: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
section.product-purchase .well {
|
||||||
|
margin-top: var(--space-2, 8px);
|
||||||
|
margin-bottom: var(--space-3, 12px);
|
||||||
|
}
|
||||||
|
|
||||||
.product-images {
|
.product-images {
|
||||||
order: 1;
|
order: 1;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
@ -2655,25 +2663,17 @@ textarea.markup-editor-textarea {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
section.product-right {
|
|
||||||
order: 2;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.product-right .well {
|
|
||||||
/* Tighten the top margin on mobile — the well now sits directly
|
|
||||||
under the product image instead of below description + comments,
|
|
||||||
so it doesn't need the 30px gap that separated it from the
|
|
||||||
comment thread in the old order. */
|
|
||||||
margin-top: var(--space-3, 12px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-description {
|
.product-description {
|
||||||
order: 3;
|
order: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.product-comments {
|
.product-comments {
|
||||||
|
order: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.product-related {
|
||||||
order: 4;
|
order: 4;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Watch mode mobile: dissolve watch-left wrapper so sticky video sticks
|
/* Watch mode mobile: dissolve watch-left wrapper so sticky video sticks
|
||||||
|
|
@ -2691,15 +2691,15 @@ textarea.markup-editor-textarea {
|
||||||
|
|
||||||
.watch-mode .product-description,
|
.watch-mode .product-description,
|
||||||
.watch-mode .product-comments,
|
.watch-mode .product-comments,
|
||||||
.watch-mode section.product-right {
|
.watch-mode section.product-purchase,
|
||||||
|
.watch-mode section.product-related {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
background: var(--bg-primary, #ffffff);
|
background: var(--bg-primary, #ffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
.watch-mode section.product-right {
|
.watch-mode section.product-purchase { order: 0; }
|
||||||
order: 2;
|
.watch-mode section.product-related { order: 4; }
|
||||||
}
|
|
||||||
|
|
||||||
/* On mobile, show only 7 next items in related content */
|
/* On mobile, show only 7 next items in related content */
|
||||||
.related-content-row.related-content-overflow {
|
.related-content-row.related-content-overflow {
|
||||||
|
|
@ -2766,7 +2766,8 @@ textarea.markup-editor-textarea {
|
||||||
grid-template-columns: 2fr 1fr;
|
grid-template-columns: 2fr 1fr;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"images images"
|
"images images"
|
||||||
"content purchase";
|
"content purchase"
|
||||||
|
"content related";
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
|
|
@ -2788,7 +2789,8 @@ textarea.markup-editor-textarea {
|
||||||
}
|
}
|
||||||
|
|
||||||
section.two-column.cinema-mode.cinema-wide .product-images { grid-area: images; }
|
section.two-column.cinema-mode.cinema-wide .product-images { grid-area: images; }
|
||||||
section.two-column.cinema-mode.cinema-wide section.product-right { grid-area: purchase; align-self: start; }
|
section.two-column.cinema-mode.cinema-wide section.product-purchase { grid-area: purchase; align-self: start; }
|
||||||
|
section.two-column.cinema-mode.cinema-wide section.product-related { grid-area: related; align-self: start; }
|
||||||
|
|
||||||
section.two-column.cinema-mode.cinema-wide .watch-video-container {
|
section.two-column.cinema-mode.cinema-wide .watch-video-container {
|
||||||
max-height: 92vh;
|
max-height: 92vh;
|
||||||
|
|
@ -2887,9 +2889,9 @@ textarea.markup-editor-textarea {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
|
grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"images purchase"
|
"images purchase"
|
||||||
"description purchase"
|
"description related"
|
||||||
"comments purchase";
|
"comments related";
|
||||||
gap: 40px;
|
gap: 40px;
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
|
@ -2903,10 +2905,14 @@ textarea.markup-editor-textarea {
|
||||||
grid-area: images;
|
grid-area: images;
|
||||||
}
|
}
|
||||||
|
|
||||||
section.product-right {
|
section.product-purchase {
|
||||||
grid-area: purchase;
|
grid-area: purchase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
section.product-related {
|
||||||
|
grid-area: related;
|
||||||
|
}
|
||||||
|
|
||||||
.product-description {
|
.product-description {
|
||||||
grid-area: description;
|
grid-area: description;
|
||||||
}
|
}
|
||||||
|
|
@ -2915,10 +2921,13 @@ textarea.markup-editor-textarea {
|
||||||
grid-area: comments;
|
grid-area: comments;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Watch mode: two-column layout with left wrapper for sticky video */
|
/* Watch mode: two-column layout with left wrapper for sticky video.
|
||||||
|
Right column stacks purchase (top) and related (below). */
|
||||||
section.two-column.watch-mode {
|
section.two-column.watch-mode {
|
||||||
grid-template-columns: 2fr 1fr;
|
grid-template-columns: 2fr 1fr;
|
||||||
grid-template-areas: "left purchase";
|
grid-template-areas:
|
||||||
|
"left purchase"
|
||||||
|
"left related";
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2942,8 +2951,8 @@ textarea.markup-editor-textarea {
|
||||||
background: var(--bg-primary, #ffffff);
|
background: var(--bg-primary, #ffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
.watch-mode section.product-right {
|
.watch-mode section.product-purchase,
|
||||||
grid-area: purchase;
|
.watch-mode section.product-related {
|
||||||
align-self: start;
|
align-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -186,8 +186,13 @@
|
||||||
|
|
||||||
{% if request.shop.watch_mode_enabled %}</div>{% endif %}
|
{% if request.shop.watch_mode_enabled %}</div>{% endif %}
|
||||||
|
|
||||||
<section class="product-right">
|
{# The buy zone is its own section so we can hoist it above the
|
||||||
<br/>
|
title on mobile/tablet (fox: "moved close to top of fold maybe even
|
||||||
|
above the title"). On desktop it still occupies the top of the
|
||||||
|
right column via grid-template-areas. .product-right is kept as a
|
||||||
|
second class so the existing right-column styling (centering, button
|
||||||
|
widths, cinema-mode task bar, etc.) still applies to both halves. #}
|
||||||
|
<section class="product-purchase product-right">
|
||||||
<div class="well">
|
<div class="well">
|
||||||
<h1>${{ '{:,.2f}'.format(product.price) }}</h1>
|
<h1>${{ '{:,.2f}'.format(product.price) }}</h1>
|
||||||
|
|
||||||
|
|
@ -306,6 +311,12 @@
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{# Related-content + comments-link + price-history sit below the buy
|
||||||
|
zone on desktop (right column) and at the bottom of the stack on
|
||||||
|
mobile, so they don't push the title off-screen. #}
|
||||||
|
<section class="product-related product-right">
|
||||||
|
|
||||||
{% if shop.comments_enabled %}
|
{% if shop.comments_enabled %}
|
||||||
<a href="#comments" class="product-comments-link">Comments ({{ product.public_comment_count }})</a>
|
<a href="#comments" class="product-comments-link">Comments ({{ product.public_comment_count }})</a>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue