picasso-skill 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/picasso.md +26 -542
- package/commands/godmode.md +3 -13
- package/commands/roast.md +3 -14
- package/commands/score.md +3 -18
- package/commands/steal.md +3 -31
- package/package.json +1 -1
- package/references/accessibility-wcag.md +3 -0
- package/references/code-typography.md +36 -166
- package/references/color-and-contrast.md +78 -345
- package/references/generative-art.md +49 -561
- package/references/modern-css-performance.md +46 -258
- package/references/motion-and-animation.md +225 -88
- package/references/navigation-patterns.md +29 -186
- package/references/performance-optimization.md +42 -678
- package/references/react-patterns.md +56 -216
- package/references/responsive-design.md +77 -379
- package/references/sensory-design.md +62 -263
- package/references/ux-writing.md +64 -354
- package/references/animation-performance.md +0 -244
- package/references/interaction-design.md +0 -162
|
@@ -1,78 +1,33 @@
|
|
|
1
1
|
# Responsive Design Reference
|
|
2
2
|
|
|
3
|
-
## Table of Contents
|
|
4
|
-
1. Breakpoints
|
|
5
|
-
2. Mobile-First Approach
|
|
6
|
-
3. Fluid Design
|
|
7
|
-
4. Dynamic Viewport Units
|
|
8
|
-
5. Container Queries
|
|
9
|
-
6. Touch Targets
|
|
10
|
-
7. Responsive Typography
|
|
11
|
-
8. Navigation Patterns
|
|
12
|
-
9. Images
|
|
13
|
-
10. Responsive Tables
|
|
14
|
-
11. Print Styles
|
|
15
|
-
12. Progressive Enhancement
|
|
16
|
-
13. Landscape and Orientation
|
|
17
|
-
14. Common Mistakes
|
|
18
|
-
|
|
19
3
|
---
|
|
20
4
|
|
|
21
5
|
## 1. Breakpoints
|
|
22
6
|
|
|
23
|
-
Use content-driven breakpoints, not device-driven.
|
|
7
|
+
Use content-driven breakpoints, not device-driven. Sensible defaults:
|
|
24
8
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
/* Large desktops */
|
|
34
|
-
@media (min-width: 1280px) { }
|
|
35
|
-
/* Ultrawide */
|
|
36
|
-
@media (min-width: 1536px) { }
|
|
37
|
-
```
|
|
9
|
+
| Breakpoint | Width | Target |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| (none) | Base | Mobile first, no media query |
|
|
12
|
+
| sm | 640px | Large phones / small tablets |
|
|
13
|
+
| md | 768px | Tablets |
|
|
14
|
+
| lg | 1024px | Laptops / desktops |
|
|
15
|
+
| xl | 1280px | Large desktops |
|
|
16
|
+
| 2xl | 1536px | Ultrawide |
|
|
38
17
|
|
|
39
|
-
When a layout breaks before reaching a named breakpoint, add a custom one. The content dictates the breakpoint
|
|
18
|
+
When a layout breaks before reaching a named breakpoint, add a custom one. The content dictates the breakpoint. Avoid more than 5-6 total.
|
|
40
19
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Start with the mobile layout (single column, stacked). Add complexity at wider breakpoints. This ensures the core experience works everywhere before enhancements.
|
|
20
|
+
---
|
|
44
21
|
|
|
45
|
-
|
|
46
|
-
/* Base: single column */
|
|
47
|
-
.grid { display: grid; gap: 1rem; }
|
|
22
|
+
## 2. Mobile-First Approach
|
|
48
23
|
|
|
49
|
-
|
|
50
|
-
@media (min-width: 768px) {
|
|
51
|
-
.grid { grid-template-columns: repeat(2, 1fr); }
|
|
52
|
-
}
|
|
24
|
+
Start with single-column, stacked layout. Add complexity at wider breakpoints. Base styles = mobile. `@media (min-width)` = enhancements.
|
|
53
25
|
|
|
54
|
-
|
|
55
|
-
@media (min-width: 1024px) {
|
|
56
|
-
.grid { grid-template-columns: repeat(3, 1fr); }
|
|
57
|
-
}
|
|
58
|
-
```
|
|
26
|
+
---
|
|
59
27
|
|
|
60
28
|
## 3. Fluid Design
|
|
61
29
|
|
|
62
|
-
Use `clamp()` for font sizes, padding, and gaps that scale smoothly:
|
|
63
|
-
|
|
64
|
-
```css
|
|
65
|
-
.container {
|
|
66
|
-
padding: clamp(1rem, 4vw, 3rem);
|
|
67
|
-
max-width: 1200px;
|
|
68
|
-
margin: 0 auto;
|
|
69
|
-
}
|
|
70
|
-
h1 {
|
|
71
|
-
font-size: clamp(1.75rem, 4vw + 0.5rem, 3.5rem);
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
For spacing systems, combine `clamp()` with CSS custom properties so every spacing token scales together:
|
|
30
|
+
Use `clamp()` for font sizes, padding, and gaps that scale smoothly. Combine with CSS custom properties so all spacing tokens scale together:
|
|
76
31
|
|
|
77
32
|
```css
|
|
78
33
|
:root {
|
|
@@ -80,373 +35,116 @@ For spacing systems, combine `clamp()` with CSS custom properties so every spaci
|
|
|
80
35
|
--space-m: clamp(1rem, 3vw, 1.5rem);
|
|
81
36
|
--space-l: clamp(1.5rem, 5vw, 3rem);
|
|
82
37
|
}
|
|
38
|
+
h1 { font-size: clamp(1.75rem, 4vw + 0.5rem, 3.5rem); }
|
|
83
39
|
```
|
|
84
40
|
|
|
85
|
-
|
|
41
|
+
---
|
|
86
42
|
|
|
87
|
-
|
|
43
|
+
## 4. Dynamic Viewport Units
|
|
88
44
|
|
|
89
45
|
| Unit | Meaning | Use when |
|
|
90
46
|
|------|---------|----------|
|
|
91
|
-
| `svh` | Small viewport height (browser chrome
|
|
92
|
-
| `lvh` | Large viewport height (
|
|
93
|
-
| `dvh` | Dynamic viewport height (updates live
|
|
94
|
-
| `dvw` | Dynamic viewport width | Rare, but useful for side-panel layouts on mobile browsers with edge UI |
|
|
95
|
-
|
|
96
|
-
```css
|
|
97
|
-
/* Full-screen hero that actually fills the screen on mobile */
|
|
98
|
-
.hero {
|
|
99
|
-
min-height: 100dvh;
|
|
100
|
-
display: grid;
|
|
101
|
-
place-items: center;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/* Sticky footer layout that respects mobile browser chrome */
|
|
105
|
-
.app-shell {
|
|
106
|
-
display: grid;
|
|
107
|
-
grid-template-rows: auto 1fr auto;
|
|
108
|
-
min-height: 100dvh;
|
|
109
|
-
}
|
|
47
|
+
| `svh` | Small viewport height (browser chrome visible) | Smallest guaranteed visible area |
|
|
48
|
+
| `lvh` | Large viewport height (chrome hidden) | Largest possible area |
|
|
49
|
+
| `dvh` | Dynamic viewport height (updates live) | Hero/section should always fill visible area |
|
|
110
50
|
|
|
111
|
-
|
|
112
|
-
.hero {
|
|
113
|
-
min-height: 100vh;
|
|
114
|
-
min-height: 100dvh;
|
|
115
|
-
}
|
|
116
|
-
```
|
|
51
|
+
Always declare a `vh` fallback before the `dvh` value. Use `100dvh` for full-screen heroes and sticky footer layouts.
|
|
117
52
|
|
|
118
|
-
|
|
53
|
+
---
|
|
119
54
|
|
|
120
55
|
## 5. Container Queries
|
|
121
56
|
|
|
122
|
-
For component-level responsiveness (when the component's width, not the viewport,
|
|
123
|
-
|
|
124
|
-
### Card that adapts to its container
|
|
57
|
+
For component-level responsiveness (when the component's width, not the viewport, determines layout). Essential for reusable components in different layout contexts.
|
|
125
58
|
|
|
126
59
|
```css
|
|
127
|
-
.card-container {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/* Compact: image on top, content below */
|
|
133
|
-
.card {
|
|
134
|
-
display: grid;
|
|
135
|
-
gap: 0.75rem;
|
|
136
|
-
}
|
|
137
|
-
.card img {
|
|
138
|
-
width: 100%;
|
|
139
|
-
aspect-ratio: 16 / 9;
|
|
140
|
-
object-fit: cover;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/* Wide enough: image beside content */
|
|
144
|
-
@container card (min-width: 400px) {
|
|
145
|
-
.card {
|
|
146
|
-
grid-template-columns: 200px 1fr;
|
|
147
|
-
}
|
|
148
|
-
.card img {
|
|
149
|
-
aspect-ratio: 1;
|
|
150
|
-
height: 100%;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/* Very wide: add metadata column */
|
|
155
|
-
@container card (min-width: 700px) {
|
|
156
|
-
.card {
|
|
157
|
-
grid-template-columns: 240px 1fr 180px;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
60
|
+
.card-container { container-type: inline-size; container-name: card; }
|
|
61
|
+
@container card (min-width: 400px) { .card { grid-template-columns: 200px 1fr; } }
|
|
62
|
+
@container card (min-width: 700px) { .card { grid-template-columns: 240px 1fr 180px; } }
|
|
160
63
|
```
|
|
161
64
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
```css
|
|
165
|
-
.main-content { container-type: inline-size; }
|
|
65
|
+
When the sidebar is open and the main area shrinks, container query grids automatically drop columns without viewport media queries.
|
|
166
66
|
|
|
167
|
-
|
|
168
|
-
.dashboard-grid {
|
|
169
|
-
grid-template-columns: repeat(2, 1fr);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
@container (min-width: 900px) {
|
|
173
|
-
.dashboard-grid {
|
|
174
|
-
grid-template-columns: repeat(3, 1fr);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
This means when the sidebar is open and the main area shrinks, the grid automatically drops columns without any viewport media query.
|
|
67
|
+
---
|
|
180
68
|
|
|
181
69
|
## 6. Touch Targets
|
|
182
70
|
|
|
183
|
-
Minimum
|
|
71
|
+
- Minimum: 44x44px (WCAG) or 48x48px (Material)
|
|
72
|
+
- If visual element is smaller, extend hit area with padding or `::before { inset: -12px; }`
|
|
73
|
+
- Ensure at least 8px space between adjacent touch targets
|
|
184
74
|
|
|
185
|
-
|
|
186
|
-
.icon-button {
|
|
187
|
-
position: relative;
|
|
188
|
-
width: 24px;
|
|
189
|
-
height: 24px;
|
|
190
|
-
}
|
|
191
|
-
.icon-button::before {
|
|
192
|
-
content: '';
|
|
193
|
-
position: absolute;
|
|
194
|
-
inset: -12px; /* extends tap area to 48x48 */
|
|
195
|
-
}
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Also ensure at least 8px of space between adjacent touch targets to prevent mis-taps.
|
|
75
|
+
---
|
|
199
76
|
|
|
200
77
|
## 7. Responsive Typography
|
|
201
78
|
|
|
202
|
-
|
|
203
|
-
-
|
|
204
|
-
- Desktop: use a larger ratio (1.25-1.333) with a 16-18px base
|
|
79
|
+
- Mobile: smaller ratio (1.2) with 15-16px base
|
|
80
|
+
- Desktop: larger ratio (1.25-1.333) with 16-18px base
|
|
205
81
|
- Headings should scale more aggressively than body text
|
|
206
82
|
|
|
83
|
+
---
|
|
84
|
+
|
|
207
85
|
## 8. Navigation Patterns
|
|
208
86
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
87
|
+
| Viewport | Pattern |
|
|
88
|
+
|---|---|
|
|
89
|
+
| Mobile (< 768px) | Hamburger, bottom tab bar, or slide-out drawer |
|
|
90
|
+
| Tablet (768-1024px) | Collapsed sidebar or icon-only nav |
|
|
91
|
+
| Desktop (> 1024px) | Full sidebar, top nav bar, or mega-menu |
|
|
92
|
+
|
|
93
|
+
---
|
|
212
94
|
|
|
213
95
|
## 9. Images
|
|
214
96
|
|
|
215
|
-
Use `srcset` and `sizes` for responsive images. Use `loading="lazy"` for below-the-fold
|
|
97
|
+
Use `srcset` and `sizes` for responsive images. Use `loading="lazy"` for below-the-fold. Set `aspect-ratio` to prevent layout shift. Use `<picture>` with AVIF/WebP sources.
|
|
216
98
|
|
|
217
|
-
|
|
218
|
-
img {
|
|
219
|
-
width: 100%;
|
|
220
|
-
height: auto;
|
|
221
|
-
aspect-ratio: 16 / 9;
|
|
222
|
-
object-fit: cover;
|
|
223
|
-
}
|
|
224
|
-
```
|
|
99
|
+
---
|
|
225
100
|
|
|
226
101
|
## 10. Responsive Tables
|
|
227
102
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
Keeps the table structure intact. Best for data-dense tables where column relationships matter (financial data, comparison grids).
|
|
233
|
-
|
|
234
|
-
```css
|
|
235
|
-
.table-wrapper {
|
|
236
|
-
overflow-x: auto;
|
|
237
|
-
-webkit-overflow-scrolling: touch;
|
|
238
|
-
border: 1px solid var(--border);
|
|
239
|
-
border-radius: 0.5rem;
|
|
240
|
-
}
|
|
241
|
-
.table-wrapper table {
|
|
242
|
-
min-width: 600px; /* prevents columns from crushing */
|
|
243
|
-
width: 100%;
|
|
244
|
-
border-collapse: collapse;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/* Visual hint that the table scrolls */
|
|
248
|
-
.table-wrapper {
|
|
249
|
-
background:
|
|
250
|
-
linear-gradient(to right, white 30%, transparent),
|
|
251
|
-
linear-gradient(to left, white 30%, transparent),
|
|
252
|
-
linear-gradient(to right, rgba(0,0,0,0.1), transparent 15px),
|
|
253
|
-
linear-gradient(to left, rgba(0,0,0,0.1), transparent 15px);
|
|
254
|
-
background-position: left, right, left, right;
|
|
255
|
-
background-size: 40px 100%, 40px 100%, 15px 100%, 15px 100%;
|
|
256
|
-
background-repeat: no-repeat;
|
|
257
|
-
background-attachment: local, local, scroll, scroll;
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
### Pattern B: Stacked cards on mobile
|
|
103
|
+
| Pattern | When to Use |
|
|
104
|
+
|---|---|
|
|
105
|
+
| Horizontal scroll wrapper | Data-dense tables where column relationships matter (financial, comparison) |
|
|
106
|
+
| Stacked cards on mobile | User-facing lists where each row is an independent record (orders, contacts) |
|
|
262
107
|
|
|
263
|
-
|
|
108
|
+
For scroll wrapper: add `overflow-x: auto` with scroll shadow hints. For stacked cards: use `data-label` attributes on `<td>` elements and `td::before { content: attr(data-label); }` on mobile.
|
|
264
109
|
|
|
265
|
-
|
|
266
|
-
@media (max-width: 767px) {
|
|
267
|
-
table, thead, tbody, th, td, tr {
|
|
268
|
-
display: block;
|
|
269
|
-
}
|
|
270
|
-
thead {
|
|
271
|
-
position: absolute;
|
|
272
|
-
width: 1px;
|
|
273
|
-
height: 1px;
|
|
274
|
-
overflow: hidden;
|
|
275
|
-
clip: rect(0, 0, 0, 0);
|
|
276
|
-
}
|
|
277
|
-
tr {
|
|
278
|
-
margin-bottom: 1rem;
|
|
279
|
-
border: 1px solid var(--border);
|
|
280
|
-
border-radius: 0.5rem;
|
|
281
|
-
padding: 0.75rem;
|
|
282
|
-
}
|
|
283
|
-
td {
|
|
284
|
-
display: flex;
|
|
285
|
-
justify-content: space-between;
|
|
286
|
-
padding: 0.4rem 0;
|
|
287
|
-
border-bottom: 1px solid var(--border-light);
|
|
288
|
-
}
|
|
289
|
-
td:last-child {
|
|
290
|
-
border-bottom: none;
|
|
291
|
-
}
|
|
292
|
-
/* Use data attributes for labels */
|
|
293
|
-
td::before {
|
|
294
|
-
content: attr(data-label);
|
|
295
|
-
font-weight: 600;
|
|
296
|
-
margin-right: 1rem;
|
|
297
|
-
flex-shrink: 0;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
The HTML needs `data-label` attributes on each `<td>`:
|
|
303
|
-
|
|
304
|
-
```html
|
|
305
|
-
<td data-label="Name">Alice Johnson</td>
|
|
306
|
-
<td data-label="Status">Active</td>
|
|
307
|
-
<td data-label="Amount">$1,240.00</td>
|
|
308
|
-
```
|
|
110
|
+
---
|
|
309
111
|
|
|
310
112
|
## 11. Print Styles
|
|
311
113
|
|
|
312
|
-
|
|
114
|
+
For pages with substantive content (articles, invoices, dashboards):
|
|
115
|
+
- Hide nav, sidebar, toolbar, footer with `display: none !important`
|
|
116
|
+
- Reset to white background, black text, 12pt
|
|
117
|
+
- Use `break-after: avoid` on headings, `break-inside: avoid` on tables/cards
|
|
118
|
+
- Show link URLs: `a[href^="http"]::after { content: " (" attr(href) ")"; }`
|
|
313
119
|
|
|
314
|
-
|
|
315
|
-
@media print {
|
|
316
|
-
/* Remove non-essential UI */
|
|
317
|
-
nav, .sidebar, .toolbar, footer, .no-print {
|
|
318
|
-
display: none !important;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/* Reset backgrounds and colors for ink saving */
|
|
322
|
-
body {
|
|
323
|
-
background: white !important;
|
|
324
|
-
color: black !important;
|
|
325
|
-
font-size: 12pt;
|
|
326
|
-
line-height: 1.5;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/* Prevent elements from breaking across pages */
|
|
330
|
-
h1, h2, h3 {
|
|
331
|
-
break-after: avoid;
|
|
332
|
-
}
|
|
333
|
-
table, figure, .card {
|
|
334
|
-
break-inside: avoid;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/* Show link URLs inline */
|
|
338
|
-
a[href^="http"]::after {
|
|
339
|
-
content: " (" attr(href) ")";
|
|
340
|
-
font-size: 0.85em;
|
|
341
|
-
color: #555;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/* Constrain width for readability */
|
|
345
|
-
.container {
|
|
346
|
-
max-width: 100% !important;
|
|
347
|
-
padding: 0 !important;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
```
|
|
120
|
+
---
|
|
351
121
|
|
|
352
122
|
## 12. Progressive Enhancement
|
|
353
123
|
|
|
354
|
-
Use `@supports`
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
.grid {
|
|
359
|
-
display: flex;
|
|
360
|
-
flex-wrap: wrap;
|
|
361
|
-
gap: 1rem;
|
|
362
|
-
}
|
|
363
|
-
.grid > * {
|
|
364
|
-
flex: 1 1 300px;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/* Enhancement: subgrid for aligned cards */
|
|
368
|
-
@supports (grid-template-rows: subgrid) {
|
|
369
|
-
.grid {
|
|
370
|
-
display: grid;
|
|
371
|
-
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
372
|
-
}
|
|
373
|
-
.grid > .card {
|
|
374
|
-
display: grid;
|
|
375
|
-
grid-template-rows: subgrid;
|
|
376
|
-
grid-row: span 3;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
Other useful `@supports` checks:
|
|
382
|
-
|
|
383
|
-
```css
|
|
384
|
-
/* Container queries */
|
|
385
|
-
@supports (container-type: inline-size) {
|
|
386
|
-
.widget-wrapper { container-type: inline-size; }
|
|
387
|
-
}
|
|
124
|
+
Use `@supports` for modern layouts with graceful fallbacks:
|
|
125
|
+
- Flexbox fallback, then `@supports (grid-template-rows: subgrid)` for aligned cards
|
|
126
|
+
- `@supports (container-type: inline-size)` for container queries
|
|
127
|
+
- `@supports (backdrop-filter: blur(10px))` for frosted glass
|
|
388
128
|
|
|
389
|
-
|
|
390
|
-
@supports selector(:has(*)) {
|
|
391
|
-
.form-group:has(:invalid) { border-color: red; }
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/* Backdrop filter for frosted glass */
|
|
395
|
-
@supports (backdrop-filter: blur(10px)) {
|
|
396
|
-
.overlay {
|
|
397
|
-
backdrop-filter: blur(10px);
|
|
398
|
-
background: rgba(255, 255, 255, 0.6);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
```
|
|
129
|
+
---
|
|
402
130
|
|
|
403
131
|
## 13. Landscape and Orientation
|
|
404
132
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
/* Landscape phones: reduce vertical spacing, switch to row layout */
|
|
409
|
-
@media (orientation: landscape) and (max-height: 500px) {
|
|
410
|
-
.hero {
|
|
411
|
-
min-height: auto;
|
|
412
|
-
padding: 2rem 1rem;
|
|
413
|
-
}
|
|
414
|
-
.onboarding-steps {
|
|
415
|
-
flex-direction: row;
|
|
416
|
-
overflow-x: auto;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/* Tablet landscape: often wide enough for desktop layout */
|
|
421
|
-
@media (orientation: landscape) and (min-width: 768px) {
|
|
422
|
-
.sidebar { display: block; }
|
|
423
|
-
}
|
|
424
|
-
```
|
|
133
|
+
- Landscape phones have very little vertical space (under 400px). No full-height heroes or tall modals.
|
|
134
|
+
- Use `@media (orientation: landscape) and (max-height: 500px)` for landscape phone overrides
|
|
135
|
+
- Virtual keyboards consume even more vertical space in landscape
|
|
425
136
|
|
|
426
|
-
|
|
427
|
-
- Landscape phones have very little vertical space (typically under 400px). Do not use full-height heroes or tall modals.
|
|
428
|
-
- Virtual keyboards consume even more vertical space in landscape. Keep form inputs above the fold or use a scroll strategy.
|
|
429
|
-
- Test with `(max-height: Xpx)` in addition to orientation queries for finer control.
|
|
137
|
+
---
|
|
430
138
|
|
|
431
139
|
## 14. Common Mistakes
|
|
432
140
|
|
|
433
|
-
- **Hiding content on mobile**:
|
|
434
|
-
- **Unguarded `vw` text**:
|
|
435
|
-
- **Horizontal overflow**:
|
|
436
|
-
- **Fixed elements hogging
|
|
437
|
-
- **Not testing real
|
|
438
|
-
- **Ignoring
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
```
|
|
444
|
-
- **Breakpoint-only thinking**: If you find yourself writing more than three media queries for a single component, switch to container queries or fluid sizing.
|
|
445
|
-
- **Forgetting hover states are absent on touch**: Use `@media (hover: hover)` to scope hover effects so they do not get stuck on touch devices.
|
|
446
|
-
```css
|
|
447
|
-
@media (hover: hover) {
|
|
448
|
-
.card:hover { transform: translateY(-2px); }
|
|
449
|
-
}
|
|
450
|
-
```
|
|
451
|
-
- **Z-index wars on mobile**: Stacking contexts behave differently when fixed/sticky elements overlap modals and drawers. Establish a z-index scale in custom properties.
|
|
452
|
-
- **Viewport-height layouts with virtual keyboards**: On mobile, the virtual keyboard does not shrink the viewport in all browsers. Elements pinned to `100vh` can end up hidden. Use `100dvh` or listen for `visualViewport` resize events.
|
|
141
|
+
- **Hiding content on mobile**: Use progressive disclosure (expand/collapse) instead of `display: none`
|
|
142
|
+
- **Unguarded `vw` text**: Always use `clamp()` with a minimum
|
|
143
|
+
- **Horizontal overflow**: Test at 320px. Common culprits: tables, pre/code, fixed-width images, long URLs
|
|
144
|
+
- **Fixed elements hogging viewport**: Header + bottom bar + cookie banner can take half the screen
|
|
145
|
+
- **Not testing real widths**: 375px (iPhone SE), 390px (modern iPhone), 360px (Android), 320px (stress test)
|
|
146
|
+
- **Ignoring safe areas**: Use `env(safe-area-inset-*)` for edge-to-edge layouts
|
|
147
|
+
- **Breakpoint-only thinking**: If 3+ media queries for one component, switch to container queries or fluid sizing
|
|
148
|
+
- **Hover states on touch**: Use `@media (hover: hover)` to scope hover effects
|
|
149
|
+
- **Z-index wars**: Establish a z-index scale in custom properties
|
|
150
|
+
- **Viewport-height with virtual keyboards**: Use `100dvh` or `visualViewport` resize events
|