@convertex/skill 1.0.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/cli.mjs +103 -0
- package/package.json +29 -0
- package/skills/convertex/SKILL.md +330 -0
- package/skills/convertex/client-first/css/rules.md +102 -0
- package/skills/convertex/client-first/naming/conventions.md +92 -0
- package/skills/convertex/client-first/structure/page-skeleton.md +154 -0
- package/skills/convertex/client-first/utilities/buttons.md +170 -0
- package/skills/convertex/client-first/utilities/layout.md +89 -0
- package/skills/convertex/client-first/utilities/spacing.md +81 -0
- package/skills/convertex/client-first/utilities/typography.md +86 -0
- package/skills/convertex/css/best-practices.md +190 -0
- package/skills/convertex/elements/background-video.md +62 -0
- package/skills/convertex/elements/dropdown.md +49 -0
- package/skills/convertex/elements/forms.md +170 -0
- package/skills/convertex/elements/images.md +90 -0
- package/skills/convertex/elements/lightbox.md +61 -0
- package/skills/convertex/elements/links-buttons.md +96 -0
- package/skills/convertex/elements/navbar.md +100 -0
- package/skills/convertex/elements/slider.md +81 -0
- package/skills/convertex/elements/tabs.md +63 -0
- package/skills/convertex/patterns/ghost-blocks.md +94 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# CSS Property Reference for Webflow
|
|
2
|
+
|
|
3
|
+
Detailed writing guide for CSS properties. For rules and selectors, see [SKILL.md](../SKILL.md).
|
|
4
|
+
|
|
5
|
+
## Spacing
|
|
6
|
+
|
|
7
|
+
```css
|
|
8
|
+
/* All forms work */
|
|
9
|
+
padding: 2rem;
|
|
10
|
+
padding: 1rem 2rem;
|
|
11
|
+
padding-top: 1rem;
|
|
12
|
+
margin: 0 auto;
|
|
13
|
+
gap: 1.5rem;
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Borders
|
|
17
|
+
|
|
18
|
+
```css
|
|
19
|
+
/* Per-side shorthand — preferred */
|
|
20
|
+
border-top: 1px solid #e5e7eb;
|
|
21
|
+
border-bottom: 2px solid #000;
|
|
22
|
+
|
|
23
|
+
/* All sides — use 3 separate properties */
|
|
24
|
+
border-width: 1px;
|
|
25
|
+
border-style: solid;
|
|
26
|
+
border-color: #e5e7eb;
|
|
27
|
+
|
|
28
|
+
/* Border radius */
|
|
29
|
+
border-radius: 0.5rem;
|
|
30
|
+
border-top-left-radius: 1rem;
|
|
31
|
+
border-top-right-radius: 1rem;
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Backgrounds & Gradients
|
|
35
|
+
|
|
36
|
+
```css
|
|
37
|
+
/* Color */
|
|
38
|
+
background-color: #1a1a2e;
|
|
39
|
+
|
|
40
|
+
/* Linear gradient */
|
|
41
|
+
background-image: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
42
|
+
|
|
43
|
+
/* Radial gradient */
|
|
44
|
+
background-image: radial-gradient(circle at center, #667eea 0%, transparent 70%);
|
|
45
|
+
|
|
46
|
+
/* Image */
|
|
47
|
+
background-image: url('hero-bg.jpg');
|
|
48
|
+
background-size: cover;
|
|
49
|
+
background-position: center;
|
|
50
|
+
background-repeat: no-repeat;
|
|
51
|
+
|
|
52
|
+
/* Shorthand */
|
|
53
|
+
background: linear-gradient(to bottom, rgba(0,0,0,0.6), transparent);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Transitions
|
|
57
|
+
|
|
58
|
+
```css
|
|
59
|
+
/* Shorthand — preferred */
|
|
60
|
+
transition: color 0.3s ease, transform 0.2s ease-in-out;
|
|
61
|
+
transition: all 0.3s ease;
|
|
62
|
+
|
|
63
|
+
/* Longhand */
|
|
64
|
+
transition-property: opacity, transform;
|
|
65
|
+
transition-duration: 300ms, 200ms;
|
|
66
|
+
transition-timing-function: ease, ease-in-out;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Flexbox
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: space-between;
|
|
76
|
+
gap: 1.5rem;
|
|
77
|
+
flex-wrap: wrap;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Grid
|
|
81
|
+
|
|
82
|
+
```css
|
|
83
|
+
/* Standard grid */
|
|
84
|
+
display: grid;
|
|
85
|
+
grid-template-columns: repeat(3, 1fr);
|
|
86
|
+
gap: 2rem;
|
|
87
|
+
|
|
88
|
+
/* Grid placement */
|
|
89
|
+
grid-area: 1 / 1 / 3 / 4;
|
|
90
|
+
grid-column: span 2;
|
|
91
|
+
grid-row: 1 / 3;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Typography
|
|
95
|
+
|
|
96
|
+
```css
|
|
97
|
+
font-family: 'Inter', sans-serif;
|
|
98
|
+
font-size: 1rem;
|
|
99
|
+
font-weight: 600;
|
|
100
|
+
line-height: 1.5;
|
|
101
|
+
letter-spacing: -0.02em;
|
|
102
|
+
text-transform: uppercase;
|
|
103
|
+
text-decoration: none;
|
|
104
|
+
color: #1a1a2e;
|
|
105
|
+
text-shadow: 0 2px 4px rgba(0,0,0,0.3);
|
|
106
|
+
-webkit-text-stroke-width: 1px;
|
|
107
|
+
-webkit-text-stroke-color: #000;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Filters & Effects
|
|
111
|
+
|
|
112
|
+
```css
|
|
113
|
+
opacity: 0.9;
|
|
114
|
+
mix-blend-mode: overlay;
|
|
115
|
+
filter: blur(4px) brightness(0.8);
|
|
116
|
+
backdrop-filter: blur(10px) saturate(1.5);
|
|
117
|
+
transform: translateY(-4px) scale(1.02);
|
|
118
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Sizing & Layout
|
|
122
|
+
|
|
123
|
+
```css
|
|
124
|
+
/* Dimensions */
|
|
125
|
+
width: 100%;
|
|
126
|
+
max-width: 80rem;
|
|
127
|
+
min-height: 100vh;
|
|
128
|
+
|
|
129
|
+
/* Object fit — for images and videos */
|
|
130
|
+
object-fit: cover;
|
|
131
|
+
object-fit: contain;
|
|
132
|
+
aspect-ratio: 16 / 9;
|
|
133
|
+
|
|
134
|
+
/* Positioning */
|
|
135
|
+
position: relative;
|
|
136
|
+
position: absolute;
|
|
137
|
+
position: sticky;
|
|
138
|
+
top: 0;
|
|
139
|
+
z-index: 10;
|
|
140
|
+
inset: 0;
|
|
141
|
+
|
|
142
|
+
/* Overflow */
|
|
143
|
+
overflow: hidden;
|
|
144
|
+
overflow: auto;
|
|
145
|
+
overflow-x: hidden;
|
|
146
|
+
overflow-y: auto;
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Cursor
|
|
150
|
+
|
|
151
|
+
```css
|
|
152
|
+
cursor: pointer;
|
|
153
|
+
cursor: default;
|
|
154
|
+
cursor: not-allowed;
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Animations & Keyframes
|
|
158
|
+
|
|
159
|
+
**Keyframes must go in a ghost block embed, not in the standalone CSS.**
|
|
160
|
+
|
|
161
|
+
```html
|
|
162
|
+
<div class="w-embed"><style>
|
|
163
|
+
@keyframes fadeInUp {
|
|
164
|
+
from { opacity: 0; transform: translateY(20px); }
|
|
165
|
+
to { opacity: 1; transform: translateY(0); }
|
|
166
|
+
}
|
|
167
|
+
.hero_heading { animation: fadeInUp 0.6s ease forwards; }
|
|
168
|
+
</style></div>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Prefer CSS `transition` over `animation` wherever possible — transitions are natively supported without ghost blocks.
|
|
172
|
+
|
|
173
|
+
## Responsive Pattern
|
|
174
|
+
|
|
175
|
+
Desktop-first base styles, override downward. Only include properties that change:
|
|
176
|
+
|
|
177
|
+
```css
|
|
178
|
+
.hero_heading {
|
|
179
|
+
font-size: 4rem;
|
|
180
|
+
line-height: 1.1;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@media (max-width: 991px) {
|
|
184
|
+
.hero_heading { font-size: 3rem; }
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@media (max-width: 479px) {
|
|
188
|
+
.hero_heading { font-size: 2rem; }
|
|
189
|
+
}
|
|
190
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Background Video
|
|
2
|
+
|
|
3
|
+
## Required Structure
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<div class="w-background-video hero-video"
|
|
7
|
+
data-autoplay="true"
|
|
8
|
+
data-loop="true"
|
|
9
|
+
data-wf-ignore="true"
|
|
10
|
+
data-video-urls="video.webm,video.mp4"
|
|
11
|
+
data-poster-url="poster.jpg">
|
|
12
|
+
<div class="hero-content">
|
|
13
|
+
<h1>Hero Title</h1>
|
|
14
|
+
<p>Subtitle text</p>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Data Attributes
|
|
20
|
+
|
|
21
|
+
| Attribute | Description |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `data-video-urls` | Comma-separated video URLs (`.webm` preferred first) |
|
|
24
|
+
| `data-poster-url` | Fallback poster image URL |
|
|
25
|
+
| `data-autoplay` | `"true"` / `"false"` |
|
|
26
|
+
| `data-loop` | `"true"` / `"false"` |
|
|
27
|
+
| `data-wf-ignore` | `"true"` / `"false"` |
|
|
28
|
+
|
|
29
|
+
## Children
|
|
30
|
+
|
|
31
|
+
All non-video children are rendered on top of the video (overlay content, headings, buttons, etc.). `<video>` and `<noscript>` tags inside the wrapper are ignored — only the `data-*` attributes matter.
|
|
32
|
+
|
|
33
|
+
## Play/Pause Button (Optional)
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<div class="w-backgroundvideo-backgroundvideoplaypausebutton">
|
|
37
|
+
<img src="pause-icon.svg" alt="Pause video" />
|
|
38
|
+
<img src="play-icon.svg" alt="Play video" />
|
|
39
|
+
</div>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The button images are identified by their `alt` text: `"Pause video"` and `"Play video"`.
|
|
43
|
+
|
|
44
|
+
## Full Example with Play/Pause
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<div class="w-background-video hero-video"
|
|
48
|
+
data-autoplay="true"
|
|
49
|
+
data-loop="true"
|
|
50
|
+
data-wf-ignore="true"
|
|
51
|
+
data-video-urls="hero.webm,hero.mp4"
|
|
52
|
+
data-poster-url="hero-poster.jpg">
|
|
53
|
+
<div class="w-backgroundvideo-backgroundvideoplaypausebutton">
|
|
54
|
+
<img src="pause.svg" alt="Pause video" />
|
|
55
|
+
<img src="play.svg" alt="Play video" />
|
|
56
|
+
</div>
|
|
57
|
+
<div class="hero-overlay">
|
|
58
|
+
<h1 class="hero_heading">Welcome</h1>
|
|
59
|
+
<p class="hero_subtitle">Watch the video</p>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Dropdown
|
|
2
|
+
|
|
3
|
+
## Required Structure
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<div class="w-dropdown" data-hover="true" data-delay="0">
|
|
7
|
+
<div class="w-dropdown-toggle">
|
|
8
|
+
<div class="w-icon-dropdown-toggle"></div>
|
|
9
|
+
<div>Menu</div>
|
|
10
|
+
</div>
|
|
11
|
+
<nav class="w-dropdown-list">
|
|
12
|
+
<a href="/option1" class="w-dropdown-link">Option 1</a>
|
|
13
|
+
<a href="/option2" class="w-dropdown-link">Option 2</a>
|
|
14
|
+
</nav>
|
|
15
|
+
</div>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Data Attributes
|
|
19
|
+
|
|
20
|
+
| Attribute | Default | Description |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `data-hover` | `"false"` | Open on hover (`"true"` = enabled) |
|
|
23
|
+
| `data-delay` | `"0"` | Close delay on hover-out (ms) |
|
|
24
|
+
|
|
25
|
+
## Required Elements
|
|
26
|
+
|
|
27
|
+
### Wrapper — `div.w-dropdown`
|
|
28
|
+
Root element for the dropdown.
|
|
29
|
+
|
|
30
|
+
### Toggle — `div.w-dropdown-toggle`
|
|
31
|
+
The clickable trigger that opens the dropdown. Can contain:
|
|
32
|
+
- **Toggle icon** (`div.w-icon-dropdown-toggle`) — renders a default arrow/chevron
|
|
33
|
+
- Text content or other elements
|
|
34
|
+
|
|
35
|
+
### List — `nav.w-dropdown-list`
|
|
36
|
+
The dropdown panel that appears when opened.
|
|
37
|
+
|
|
38
|
+
### Links — `a.w-dropdown-link`
|
|
39
|
+
Links inside the dropdown list.
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<a href="/option" class="w-dropdown-link dropdown-item">Option Label</a>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Notes
|
|
46
|
+
|
|
47
|
+
- Non-link children inside the list are also supported (divs, images, etc.)
|
|
48
|
+
- Dropdowns work both standalone and inside navbars (see `elements/navbar.md`)
|
|
49
|
+
- The toggle icon (`w-icon-dropdown-toggle`) renders Webflow's default chevron
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Forms
|
|
2
|
+
|
|
3
|
+
## Required Structure
|
|
4
|
+
|
|
5
|
+
A Webflow form needs a 3-part wrapper: the form wrapper (`div.w-form`), the form itself (`<form>`), and success/error states.
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<div class="w-form">
|
|
9
|
+
<form name="Contact Form" method="get">
|
|
10
|
+
<!-- form fields go here -->
|
|
11
|
+
<input type="submit" value="Send" class="submit-button" />
|
|
12
|
+
</form>
|
|
13
|
+
<div class="w-form-done"><div>Thank you!</div></div>
|
|
14
|
+
<div class="w-form-fail"><div>Oops, something went wrong.</div></div>
|
|
15
|
+
</div>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Always include the full wrapper** with `w-form-done` and `w-form-fail` for proper success/error states and wrapper styling control.
|
|
19
|
+
|
|
20
|
+
## Input Types
|
|
21
|
+
|
|
22
|
+
All text-like inputs use `<input>` with the appropriate `type`:
|
|
23
|
+
|
|
24
|
+
| HTML `type` | Notes |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `text` (or omitted) | Default text input |
|
|
27
|
+
| `email` | Email validation |
|
|
28
|
+
| `password` | Password field |
|
|
29
|
+
| `tel` | Phone number |
|
|
30
|
+
| `number` | Numeric input |
|
|
31
|
+
| `url` | URL input |
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<input type="email" name="email" placeholder="you@example.com" required class="text-field" />
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Key attributes: `name` (required), `placeholder`, `maxlength`, `id`, `required`.
|
|
38
|
+
|
|
39
|
+
## Checkbox
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<label class="w-checkbox checkbox-field">
|
|
43
|
+
<input type="checkbox" name="agree" class="w-checkbox-input" />
|
|
44
|
+
<span class="w-form-label">I agree to the terms</span>
|
|
45
|
+
</label>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Radio Button
|
|
49
|
+
|
|
50
|
+
```html
|
|
51
|
+
<label class="w-radio radio-field">
|
|
52
|
+
<input type="radio" name="choice" value="A" class="w-radio-input" />
|
|
53
|
+
<span class="w-form-label">Option A</span>
|
|
54
|
+
</label>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Boolean attributes
|
|
58
|
+
|
|
59
|
+
`required`, `checked`, `disabled`, `autofocus` are detected by presence, not value. Write `<input required>`, not `required="true"`.
|
|
60
|
+
|
|
61
|
+
## Select Dropdown
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<select name="country" class="select-field">
|
|
65
|
+
<option value="">Select one...</option>
|
|
66
|
+
<option value="fr">France</option>
|
|
67
|
+
<option value="us">United States</option>
|
|
68
|
+
</select>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Textarea
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<textarea name="message" placeholder="Your message" class="text-area"></textarea>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Submit Button
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<input type="submit" value="Send" class="submit-button" />
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or:
|
|
84
|
+
|
|
85
|
+
```html
|
|
86
|
+
<button type="submit" class="submit-button">Send</button>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Important:** A `<button>` without `type="submit"` becomes a regular button, NOT a form submit. Only `type="submit"` triggers form submission behavior.
|
|
90
|
+
|
|
91
|
+
## Complete Example
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<div class="w-form">
|
|
95
|
+
<form name="Contact" method="get">
|
|
96
|
+
<label for="name" class="field-label">Name</label>
|
|
97
|
+
<input type="text" name="name" id="name" placeholder="John Doe" required class="text-field" />
|
|
98
|
+
|
|
99
|
+
<label for="email" class="field-label">Email</label>
|
|
100
|
+
<input type="email" name="email" id="email" placeholder="john@example.com" required class="text-field" />
|
|
101
|
+
|
|
102
|
+
<label for="phone" class="field-label">Phone</label>
|
|
103
|
+
<input type="tel" name="phone" id="phone" placeholder="+33 6..." class="text-field" />
|
|
104
|
+
|
|
105
|
+
<label for="subject" class="field-label">Subject</label>
|
|
106
|
+
<select name="subject" id="subject" class="select-field">
|
|
107
|
+
<option value="">Choose...</option>
|
|
108
|
+
<option value="general">General Inquiry</option>
|
|
109
|
+
<option value="support">Support</option>
|
|
110
|
+
</select>
|
|
111
|
+
|
|
112
|
+
<label for="message" class="field-label">Message</label>
|
|
113
|
+
<textarea name="message" id="message" placeholder="Your message..." required class="text-area"></textarea>
|
|
114
|
+
|
|
115
|
+
<label class="w-checkbox checkbox-field">
|
|
116
|
+
<input type="checkbox" name="newsletter" class="w-checkbox-input" />
|
|
117
|
+
<span class="w-form-label">Subscribe to newsletter</span>
|
|
118
|
+
</label>
|
|
119
|
+
|
|
120
|
+
<input type="submit" value="Send Message" class="submit-button" />
|
|
121
|
+
</form>
|
|
122
|
+
<div class="w-form-done"><div>Thank you! Your message has been sent.</div></div>
|
|
123
|
+
<div class="w-form-fail"><div>Oops! Something went wrong.</div></div>
|
|
124
|
+
</div>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Styling Tips
|
|
128
|
+
|
|
129
|
+
```css
|
|
130
|
+
.text-field {
|
|
131
|
+
padding-top: 0.75rem;
|
|
132
|
+
padding-bottom: 0.75rem;
|
|
133
|
+
padding-left: 1rem;
|
|
134
|
+
padding-right: 1rem;
|
|
135
|
+
border-width: 1px;
|
|
136
|
+
border-style: solid;
|
|
137
|
+
border-color: #d1d5db;
|
|
138
|
+
border-radius: 0.5rem;
|
|
139
|
+
font-size: 1rem;
|
|
140
|
+
width: 100%;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.text-field:focus {
|
|
144
|
+
border-color: #2563eb;
|
|
145
|
+
outline: none;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.field-label {
|
|
149
|
+
font-weight: 500;
|
|
150
|
+
margin-bottom: 0.5rem;
|
|
151
|
+
display: block;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.submit-button {
|
|
155
|
+
background-color: #2563eb;
|
|
156
|
+
color: #fff;
|
|
157
|
+
padding-top: 0.75rem;
|
|
158
|
+
padding-bottom: 0.75rem;
|
|
159
|
+
padding-left: 2rem;
|
|
160
|
+
padding-right: 2rem;
|
|
161
|
+
border-radius: 0.5rem;
|
|
162
|
+
font-weight: 600;
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
width: 100%;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.submit-button:hover {
|
|
168
|
+
background-color: #1d4ed8;
|
|
169
|
+
}
|
|
170
|
+
```
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Images
|
|
2
|
+
|
|
3
|
+
## Standard Image
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<img src="photo.jpg" alt="Description" class="hero-image" loading="lazy" />
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Attributes
|
|
10
|
+
|
|
11
|
+
| Attribute | Default | Notes |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `src` | — | Image source URL (required) |
|
|
14
|
+
| `alt` | `""` | Alt text — required for accessibility |
|
|
15
|
+
| `loading` | `"lazy"` | Use `"eager"` for above-the-fold images |
|
|
16
|
+
| `width` / `height` | `"auto"` | Optional dimensions |
|
|
17
|
+
|
|
18
|
+
## Responsive Images
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<img
|
|
22
|
+
src="photo-800.jpg"
|
|
23
|
+
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
|
|
24
|
+
sizes="(max-width: 479px) 100vw, (max-width: 767px) 80vw, 50vw"
|
|
25
|
+
alt="Responsive photo"
|
|
26
|
+
class="responsive-image"
|
|
27
|
+
/>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Both `srcset` and `sizes` are preserved.
|
|
31
|
+
|
|
32
|
+
## SVG Handling
|
|
33
|
+
|
|
34
|
+
### SVG as Image (decorative)
|
|
35
|
+
```html
|
|
36
|
+
<img src="icon.svg" alt="Icon" class="icon" />
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Inline SVG (needs CSS control or animation)
|
|
40
|
+
|
|
41
|
+
**Must be wrapped in `<div class="w-embed">`:**
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<div class="w-embed">
|
|
45
|
+
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
46
|
+
<path d="M12 2L2 22h20L12 2z" stroke="currentColor" stroke-width="2"/>
|
|
47
|
+
</svg>
|
|
48
|
+
</div>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
A raw `<svg>` without the `w-embed` wrapper will render incorrectly in Webflow.
|
|
52
|
+
|
|
53
|
+
## Object Fit & Aspect Ratio
|
|
54
|
+
|
|
55
|
+
For images that must fill a container without distortion:
|
|
56
|
+
|
|
57
|
+
```css
|
|
58
|
+
.hero_image {
|
|
59
|
+
width: 100%;
|
|
60
|
+
height: 100%;
|
|
61
|
+
object-fit: cover;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.hero_image-wrapper {
|
|
65
|
+
aspect-ratio: 16 / 9;
|
|
66
|
+
overflow: hidden;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`object-fit: cover`, `object-fit: contain`, and `aspect-ratio` are all supported.
|
|
71
|
+
|
|
72
|
+
## Background Images
|
|
73
|
+
|
|
74
|
+
Applied via CSS, not HTML attributes:
|
|
75
|
+
|
|
76
|
+
```css
|
|
77
|
+
.hero-section {
|
|
78
|
+
background-image: url('hero-bg.jpg');
|
|
79
|
+
background-size: cover;
|
|
80
|
+
background-position: center;
|
|
81
|
+
background-repeat: no-repeat;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Accessibility
|
|
86
|
+
|
|
87
|
+
- Every `<img>` must have an `alt` attribute
|
|
88
|
+
- Decorative images: use `alt=""`
|
|
89
|
+
- Informative images: describe the content, not the file (`alt="Team meeting in conference room"`, not `alt="photo.jpg"`)
|
|
90
|
+
- SVG icons without text: add `aria-label` on the parent element
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Lightbox
|
|
2
|
+
|
|
3
|
+
## Required Structure
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<div class="w-lightbox">
|
|
7
|
+
<img src="thumbnail.jpg" alt="Image description" class="lightbox-image" />
|
|
8
|
+
<script type="application/json" class="w-json">{
|
|
9
|
+
"items": [
|
|
10
|
+
{ "type": "image", "url": "full-size.jpg", "caption": "Image caption" }
|
|
11
|
+
],
|
|
12
|
+
"group": "gallery-1"
|
|
13
|
+
}</script>
|
|
14
|
+
</div>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## How It Works
|
|
18
|
+
|
|
19
|
+
The `w-lightbox` class creates a clickable lightbox element. The `<script class="w-json">` block defines the media items and gallery grouping.
|
|
20
|
+
|
|
21
|
+
### JSON Format
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"items": [
|
|
26
|
+
{ "type": "image", "url": "full-size.jpg", "caption": "Optional caption" },
|
|
27
|
+
{ "type": "video", "url": "https://youtube.com/...", "caption": "" }
|
|
28
|
+
],
|
|
29
|
+
"group": "gallery-name"
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- `items`: Array of media objects. Each has `type` ("image" or "video"), `url`, and optional `caption`.
|
|
34
|
+
- `group`: Use the same group name on multiple lightboxes to enable gallery navigation between them.
|
|
35
|
+
|
|
36
|
+
### Children
|
|
37
|
+
|
|
38
|
+
Non-script children (typically an `<img>` for the thumbnail) display as the clickable trigger.
|
|
39
|
+
|
|
40
|
+
## Gallery Example
|
|
41
|
+
|
|
42
|
+
Multiple lightboxes with the same `group` form a navigable gallery:
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<div class="gallery-grid">
|
|
46
|
+
<div class="w-lightbox gallery-item">
|
|
47
|
+
<img src="thumb-1.jpg" alt="Photo 1" class="gallery-image" />
|
|
48
|
+
<script type="application/json" class="w-json">{
|
|
49
|
+
"items": [{ "type": "image", "url": "full-1.jpg", "caption": "Photo 1" }],
|
|
50
|
+
"group": "portfolio"
|
|
51
|
+
}</script>
|
|
52
|
+
</div>
|
|
53
|
+
<div class="w-lightbox gallery-item">
|
|
54
|
+
<img src="thumb-2.jpg" alt="Photo 2" class="gallery-image" />
|
|
55
|
+
<script type="application/json" class="w-json">{
|
|
56
|
+
"items": [{ "type": "image", "url": "full-2.jpg", "caption": "Photo 2" }],
|
|
57
|
+
"group": "portfolio"
|
|
58
|
+
}</script>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
```
|