picasso-skill 1.0.0 → 1.2.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.
@@ -1,5 +1,23 @@
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
+ ---
20
+
3
21
  ## 1. Breakpoints
4
22
 
5
23
  Use content-driven breakpoints, not device-driven. These are sensible defaults:
@@ -18,6 +36,8 @@ Use content-driven breakpoints, not device-driven. These are sensible defaults:
18
36
  @media (min-width: 1536px) { }
19
37
  ```
20
38
 
39
+ When a layout breaks before reaching a named breakpoint, add a custom one. The content dictates the breakpoint, not the other way around. Avoid more than five or six breakpoints total.
40
+
21
41
  ## 2. Mobile-First Approach
22
42
 
23
43
  Start with the mobile layout (single column, stacked). Add complexity at wider breakpoints. This ensures the core experience works everywhere before enhancements.
@@ -52,20 +72,113 @@ h1 {
52
72
  }
53
73
  ```
54
74
 
55
- ## 4. Container Queries
75
+ For spacing systems, combine `clamp()` with CSS custom properties so every spacing token scales together:
76
+
77
+ ```css
78
+ :root {
79
+ --space-s: clamp(0.5rem, 1.5vw, 0.75rem);
80
+ --space-m: clamp(1rem, 3vw, 1.5rem);
81
+ --space-l: clamp(1.5rem, 5vw, 3rem);
82
+ }
83
+ ```
56
84
 
57
- For component-level responsiveness (when the component's width, not the viewport, should determine layout):
85
+ ## 4. Dynamic Viewport Units
86
+
87
+ The classic `vh` unit does not account for browser chrome (address bar, toolbar) on mobile devices. This causes content to be hidden behind the UI. Use the newer viewport units instead:
88
+
89
+ | Unit | Meaning | Use when |
90
+ |------|---------|----------|
91
+ | `svh` | Small viewport height (browser chrome fully visible) | You want the smallest guaranteed visible area |
92
+ | `lvh` | Large viewport height (browser chrome hidden) | You want the largest possible area |
93
+ | `dvh` | Dynamic viewport height (updates live as chrome shows/hides) | You want the hero or section to always fill exactly the visible area |
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
+ }
110
+
111
+ /* Fallback for older browsers */
112
+ .hero {
113
+ min-height: 100vh;
114
+ min-height: 100dvh;
115
+ }
116
+ ```
117
+
118
+ Always declare a `vh` fallback before the `dvh` value. Browser support is strong (2023+), but the fallback costs nothing.
119
+
120
+ ## 5. Container Queries
121
+
122
+ For component-level responsiveness (when the component's width, not the viewport, should determine layout). This is essential for reusable components that live in different layout contexts (main content area, sidebar, modal, dashboard grid).
123
+
124
+ ### Card that adapts to its container
58
125
 
59
126
  ```css
60
127
  .card-container {
61
128
  container-type: inline-size;
129
+ container-name: card;
62
130
  }
63
- @container (min-width: 400px) {
64
- .card { display: grid; grid-template-columns: 1fr 2fr; }
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
+ }
160
+ ```
161
+
162
+ ### Sidebar-aware layout
163
+
164
+ ```css
165
+ .main-content { container-type: inline-size; }
166
+
167
+ @container (min-width: 600px) {
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
+ }
65
176
  }
66
177
  ```
67
178
 
68
- ## 5. Touch Targets
179
+ This means when the sidebar is open and the main area shrinks, the grid automatically drops columns without any viewport media query.
180
+
181
+ ## 6. Touch Targets
69
182
 
70
183
  Minimum touch target: 44x44px (WCAG) or 48x48px (Material). Apply to all interactive elements on mobile. If the visual element is smaller, use padding or `::before` pseudo-element to extend the hit area.
71
184
 
@@ -82,20 +195,22 @@ Minimum touch target: 44x44px (WCAG) or 48x48px (Material). Apply to all interac
82
195
  }
83
196
  ```
84
197
 
85
- ## 6. Responsive Typography
198
+ Also ensure at least 8px of space between adjacent touch targets to prevent mis-taps.
199
+
200
+ ## 7. Responsive Typography
86
201
 
87
202
  Do not just shrink everything on mobile. Adjust the type scale:
88
203
  - Mobile: use a smaller ratio (1.2) with a 15-16px base
89
204
  - Desktop: use a larger ratio (1.25-1.333) with a 16-18px base
90
205
  - Headings should scale more aggressively than body text
91
206
 
92
- ## 7. Navigation Patterns
207
+ ## 8. Navigation Patterns
93
208
 
94
209
  - **Mobile (< 768px)**: Hamburger menu, bottom tab bar, or slide-out drawer
95
210
  - **Tablet (768-1024px)**: Collapsed sidebar or icon-only navigation
96
211
  - **Desktop (> 1024px)**: Full sidebar, top navigation bar, or mega-menu
97
212
 
98
- ## 8. Images
213
+ ## 9. Images
99
214
 
100
215
  Use `srcset` and `sizes` for responsive images. Use `loading="lazy"` for below-the-fold images. Set `aspect-ratio` to prevent layout shift:
101
216
 
@@ -108,11 +223,230 @@ img {
108
223
  }
109
224
  ```
110
225
 
111
- ## 9. Common Mistakes
226
+ ## 10. Responsive Tables
227
+
228
+ Tables are one of the hardest elements to make responsive. Two proven patterns:
229
+
230
+ ### Pattern A: Horizontal scroll wrapper
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
262
+
263
+ Reformats each row into a standalone card. Best for user-facing lists (orders, contacts, transactions) where each row is an independent record.
264
+
265
+ ```css
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
+ ```
309
+
310
+ ## 11. Print Styles
311
+
312
+ Always include basic print styles for pages with substantive content (articles, invoices, dashboards, reports):
313
+
314
+ ```css
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
+ ```
351
+
352
+ ## 12. Progressive Enhancement
353
+
354
+ Use `@supports` to deliver modern layouts to capable browsers while keeping a usable fallback:
355
+
356
+ ```css
357
+ /* Fallback: flexbox grid */
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
+ }
388
+
389
+ /* Has selector for advanced targeting */
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
+ ```
402
+
403
+ ## 13. Landscape and Orientation
404
+
405
+ Handle orientation changes explicitly, especially for mobile devices where landscape mode drastically changes available height:
406
+
407
+ ```css
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
+ ```
425
+
426
+ Key considerations:
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.
430
+
431
+ ## 14. Common Mistakes
112
432
 
113
- - Hiding too much content on mobile (users expect the same information, just reorganized)
114
- - Using `vw` units for text without a `clamp()` minimum (becomes unreadable on small screens)
115
- - Horizontal scrolling on mobile (almost never acceptable)
116
- - Fixed-position elements that cover too much of the mobile viewport
117
- - Not testing at actual device widths (375px for iPhone SE, 390px for modern iPhones, 360px for Android)
118
- - Tables that overflow on mobile (use horizontal scroll wrapper or reformat as stacked cards)
433
+ - **Hiding content on mobile**: Users expect the same information, just reorganized. Use progressive disclosure (expand/collapse) instead of `display: none`.
434
+ - **Unguarded `vw` text**: Using `vw` units for text without a `clamp()` minimum makes text unreadable on small screens and comically large on ultrawide.
435
+ - **Horizontal overflow**: Almost never acceptable on mobile. Test at 320px wide to catch it. Common culprits: tables, pre/code blocks, fixed-width images, long URLs.
436
+ - **Fixed elements hogging the viewport**: A fixed header + fixed bottom bar + cookie banner can consume over half the screen on a short phone.
437
+ - **Not testing real device widths**: 375px (iPhone SE), 390px (modern iPhone), 360px (common Android), 320px (stress test).
438
+ - **Ignoring the notch and safe areas**: On devices with notches or rounded corners, use `env(safe-area-inset-*)` for edge-to-edge layouts:
439
+ ```css
440
+ .bottom-bar {
441
+ padding-bottom: env(safe-area-inset-bottom, 0px);
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.