- Add WP Media Library integration for product and variation images - Support images array (URLs) conversion to attachment IDs - Add images array to API responses (Admin & Customer SPA) - Implement drag-and-drop sortable images in Admin product form - Add image gallery thumbnails in Customer SPA product page - Initialize WooCommerce session for guest cart operations - Fix product variations and attributes display in Customer SPA - Add variation image field in Admin SPA Changes: - includes/Api/ProductsController.php: Handle images array, add to responses - includes/Frontend/ShopController.php: Add images array for customer SPA - includes/Frontend/CartController.php: Initialize WC session for guests - admin-spa/src/lib/wp-media.ts: Add openWPMediaGallery function - admin-spa/src/routes/Products/partials/tabs/GeneralTab.tsx: WP Media + sortable images - admin-spa/src/routes/Products/partials/tabs/VariationsTab.tsx: Add variation image field - customer-spa/src/pages/Product/index.tsx: Add gallery thumbnails display
272 lines
6.1 KiB
Markdown
272 lines
6.1 KiB
Markdown
# Inline Spacing Fix - The Real Root Cause
|
|
|
|
## The Problem
|
|
|
|
Images were not filling their containers, leaving whitespace at the bottom. This was NOT a height issue, but an **inline element spacing issue**.
|
|
|
|
### Root Cause Analysis
|
|
|
|
1. **Images are inline by default** - They respect text baseline, creating extra vertical space
|
|
2. **SVG icons create inline gaps** - SVGs also default to inline display
|
|
3. **Line-height affects layout** - Parent containers with text create baseline alignment issues
|
|
|
|
### Visual Evidence
|
|
|
|
```
|
|
┌─────────────────────┐
|
|
│ │
|
|
│ IMAGE │
|
|
│ │
|
|
│ │
|
|
└─────────────────────┘
|
|
↑ Whitespace gap here (caused by inline baseline)
|
|
```
|
|
|
|
---
|
|
|
|
## The Solution
|
|
|
|
### Three Key Fixes
|
|
|
|
#### 1. Make Images Block-Level
|
|
```tsx
|
|
// Before (inline by default)
|
|
<img className="w-full h-full object-cover" />
|
|
|
|
// After (block display)
|
|
<img className="block w-full h-full object-cover" />
|
|
```
|
|
|
|
#### 2. Remove Inline Whitespace from Container
|
|
```tsx
|
|
// Add fontSize: 0 to parent
|
|
<div style={{ fontSize: 0 }}>
|
|
<img className="block w-full h-full object-cover" />
|
|
</div>
|
|
```
|
|
|
|
#### 3. Reset Font Size for Text Content
|
|
```tsx
|
|
// Reset fontSize for text elements inside
|
|
<div style={{ fontSize: '1rem' }}>
|
|
No Image
|
|
</div>
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation
|
|
|
|
### ProductCard Component
|
|
|
|
**All 4 layouts fixed:**
|
|
|
|
```tsx
|
|
// Classic, Modern, Boutique, Launch
|
|
<div className="relative w-full h-64 overflow-hidden bg-gray-100"
|
|
style={{ fontSize: 0 }}>
|
|
{product.image ? (
|
|
<img
|
|
src={product.image}
|
|
alt={product.name}
|
|
className="block w-full h-full object-cover object-center"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full flex items-center justify-center text-gray-400"
|
|
style={{ fontSize: '1rem' }}>
|
|
No Image
|
|
</div>
|
|
)}
|
|
</div>
|
|
```
|
|
|
|
**Key changes:**
|
|
- ✅ Added `style={{ fontSize: 0 }}` to container
|
|
- ✅ Added `block` class to `<img>`
|
|
- ✅ Reset `fontSize: '1rem'` for "No Image" text
|
|
- ✅ Added `flex items-center justify-center` to button with Heart icon
|
|
|
|
---
|
|
|
|
### Product Page
|
|
|
|
**Same fix applied:**
|
|
|
|
```tsx
|
|
<div className="relative w-full h-96 rounded-lg overflow-hidden bg-gray-100"
|
|
style={{ fontSize: 0 }}>
|
|
{product.image ? (
|
|
<img
|
|
src={product.image}
|
|
alt={product.name}
|
|
className="block w-full h-full object-cover object-center"
|
|
/>
|
|
) : (
|
|
<div className="w-full h-full flex items-center justify-center text-gray-400"
|
|
style={{ fontSize: '1rem' }}>
|
|
No image
|
|
</div>
|
|
)}
|
|
</div>
|
|
```
|
|
|
|
---
|
|
|
|
## Why This Works
|
|
|
|
### The Technical Explanation
|
|
|
|
#### Inline Elements and Baseline
|
|
- By default, `<img>` has `display: inline`
|
|
- Inline elements align to the text baseline
|
|
- This creates a small gap below the image (descender space)
|
|
|
|
#### Font Size Zero Trick
|
|
- Setting `fontSize: 0` on parent removes whitespace between inline elements
|
|
- This is a proven technique for removing gaps in inline layouts
|
|
- Text content needs `fontSize: '1rem'` reset to be readable
|
|
|
|
#### Block Display
|
|
- `display: block` removes baseline alignment
|
|
- Block elements fill their container naturally
|
|
- No extra spacing or gaps
|
|
|
|
---
|
|
|
|
## Files Modified
|
|
|
|
### 1. ProductCard.tsx
|
|
**Location:** `customer-spa/src/components/ProductCard.tsx`
|
|
|
|
**Changes:**
|
|
- Classic layout (line ~43)
|
|
- Modern layout (line ~116)
|
|
- Boutique layout (line ~183)
|
|
- Launch layout (line ~247)
|
|
|
|
**Applied to all:**
|
|
- Container: `style={{ fontSize: 0 }}`
|
|
- Image: `className="block ..."`
|
|
- Fallback text: `style={{ fontSize: '1rem' }}`
|
|
|
|
---
|
|
|
|
### 2. Product/index.tsx
|
|
**Location:** `customer-spa/src/pages/Product/index.tsx`
|
|
|
|
**Changes:**
|
|
- Product image container (line ~121)
|
|
- Same pattern as ProductCard
|
|
|
|
---
|
|
|
|
## Testing Checklist
|
|
|
|
### Visual Test
|
|
1. ✅ Go to `/shop`
|
|
2. ✅ Check product images - should fill containers completely
|
|
3. ✅ No whitespace at bottom of images
|
|
4. ✅ Hover effects should work smoothly
|
|
|
|
### Product Page Test
|
|
1. ✅ Click any product
|
|
2. ✅ Product image should fill container
|
|
3. ✅ No whitespace at bottom
|
|
4. ✅ Image should be 384px tall (h-96)
|
|
|
|
### Browser Test
|
|
- ✅ Chrome
|
|
- ✅ Firefox
|
|
- ✅ Safari
|
|
- ✅ Edge
|
|
|
|
---
|
|
|
|
## Best Practices Applied
|
|
|
|
### Global CSS Recommendation
|
|
For future projects, add to global CSS:
|
|
|
|
```css
|
|
img {
|
|
display: block;
|
|
max-width: 100%;
|
|
}
|
|
|
|
svg {
|
|
display: block;
|
|
}
|
|
```
|
|
|
|
This prevents inline spacing issues across the entire application.
|
|
|
|
### Why We Used Inline Styles
|
|
- Tailwind doesn't have a `font-size: 0` utility
|
|
- Inline styles are acceptable for one-off fixes
|
|
- Could be extracted to custom Tailwind class if needed
|
|
|
|
---
|
|
|
|
## Comparison: Before vs After
|
|
|
|
### Before
|
|
```tsx
|
|
<div className="relative w-full h-64">
|
|
<img className="w-full h-full object-cover" />
|
|
</div>
|
|
```
|
|
**Result:** Whitespace at bottom due to inline baseline
|
|
|
|
### After
|
|
```tsx
|
|
<div className="relative w-full h-64" style={{ fontSize: 0 }}>
|
|
<img className="block w-full h-full object-cover" />
|
|
</div>
|
|
```
|
|
**Result:** Perfect fill, no whitespace
|
|
|
|
---
|
|
|
|
## Key Learnings
|
|
|
|
### 1. Images Are Inline By Default
|
|
Always remember that `<img>` elements are inline, not block.
|
|
|
|
### 2. Baseline Alignment Creates Gaps
|
|
Inline elements respect text baseline, creating unexpected spacing.
|
|
|
|
### 3. Font Size Zero Trick
|
|
Setting `fontSize: 0` on parent is a proven technique for removing inline gaps.
|
|
|
|
### 4. Display Block Is Essential
|
|
For images in containers, always use `display: block`.
|
|
|
|
### 5. SVGs Have Same Issue
|
|
SVG icons also need `display: block` to prevent spacing issues.
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
**Problem:** Whitespace at bottom of images due to inline element spacing
|
|
|
|
**Root Cause:** Images default to `display: inline`, creating baseline alignment gaps
|
|
|
|
**Solution:**
|
|
1. Container: `style={{ fontSize: 0 }}`
|
|
2. Image: `className="block ..."`
|
|
3. Text: `style={{ fontSize: '1rem' }}`
|
|
|
|
**Result:** Perfect image fill with no whitespace! ✅
|
|
|
|
---
|
|
|
|
## Credits
|
|
|
|
Thanks to the second opinion for identifying the root cause:
|
|
- Inline SVG spacing
|
|
- Image baseline alignment
|
|
- Font-size zero technique
|
|
|
|
This is a classic CSS gotcha that many developers encounter!
|