├── .gitattributes ├── README.md ├── index.html └── main.css /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSS Variables Grid 2 | 3 | Bootstrap-inspired grid system based on CSS custom properties and flexbox. 4 | 5 | 6 | An experiment made for the purposes of an article: 7 | [Responsive Designs and CSS Custom Properties: Building a Flexible Grid System](https://css-tricks.com/) (link to be updated once the article is published) 8 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CSS Variables Grid 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 |

Grid system

15 |

Auto-layout columns

16 |

Equal-width

17 |
18 |
19 |
20 |
21 | 1 of 2 22 |
23 |
24 | 2 of 2 25 |
26 |
27 |
28 |
29 | 1 of 3 30 |
31 |
32 | 2 of 3 33 |
34 |
35 | 3 of 3 36 |
37 |
38 |
39 |
40 | 41 |
42 |
43 |
44 |
Column
45 |
Column
46 |
47 |
Column
48 |
Column
49 |
50 |
51 |
52 | 53 |

Setting one column width

54 |
55 |
56 |
57 |
58 | 1 of 3 59 |
60 |
61 | 2 of 3 (wider) 62 |
63 |
64 | 3 of 3 65 |
66 |
67 |
68 |
69 | 1 of 3 70 |
71 |
72 | 2 of 3 (wider) 73 |
74 |
75 | 3 of 3 76 |
77 |
78 |
79 |
80 | 81 |

Variable width content

82 |
83 |
84 |
85 |
86 | 1 of 3 87 |
88 |
89 | Variable width content 90 |
91 |
92 | 3 of 3 93 |
94 |
95 |
96 |
97 | 1 of 3 98 |
99 |
100 | Variable width content 101 |
102 |
103 | 3 of 3 104 |
105 |
106 |
107 |
108 | 109 |

Responsive

110 |

All breakpoints

111 |
112 |
113 |
114 |
col
115 |
col
116 |
col
117 |
col
118 |
119 |
120 |
col-8
121 |
col-4
122 |
123 |
124 |
125 | 126 |

Stacked to horizontal

127 |
128 |
129 |
130 |
col-sm-8
131 |
col-sm-4
132 |
133 |
134 |
col-sm
135 |
col-sm
136 |
col-sm
137 |
138 |
139 |
140 | 141 |

Mix and match

142 |
143 |
144 | 145 |
146 |
.col-12 .col-md-8
147 |
.col-6 .col-md-4
148 |
149 | 150 | 151 |
152 |
.col-6 .col-md-4
153 |
.col-6 .col-md-4
154 |
.col-6 .col-md-4
155 |
156 | 157 | 158 |
159 |
.col-6
160 |
.col-6
161 |
162 |
163 |
164 | 165 |

Gutters

166 |
167 |
168 |
169 |
Custom column padding
170 |
Custom column padding
171 |
172 |
173 |
174 | 175 |

Alignment

176 |

Vertical alignment

177 |
178 |
179 |
180 |
181 | One of three columns 182 |
183 |
184 | One of three columns 185 |
186 |
187 | One of three columns 188 |
189 |
190 |
191 |
192 | One of three columns 193 |
194 |
195 | One of three columns 196 |
197 |
198 | One of three columns 199 |
200 |
201 |
202 |
203 | One of three columns 204 |
205 |
206 | One of three columns 207 |
208 |
209 | One of three columns 210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 | One of three columns 219 |
220 |
221 | One of three columns 222 |
223 |
224 | One of three columns 225 |
226 |
227 |
228 |
229 | 230 |

Horizontal alignment

231 |
232 |
233 |
234 |
235 | One of two columns 236 |
237 |
238 | One of two columns 239 |
240 |
241 |
242 |
243 | One of two columns 244 |
245 |
246 | One of two columns 247 |
248 |
249 |
250 |
251 | One of two columns 252 |
253 |
254 | One of two columns 255 |
256 |
257 |
258 |
259 | One of two columns 260 |
261 |
262 | One of two columns 263 |
264 |
265 |
266 |
267 | One of two columns 268 |
269 |
270 | One of two columns 271 |
272 |
273 |
274 |
275 | 276 |

No gutters

277 |
278 |
279 |
280 |
Custom column padding
281 |
Custom column padding
282 |
283 |
284 |
285 | 286 |

Column wrapping

287 |
288 |
289 |
290 |
.col-9
291 |
.col-4
Since 9 + 4 = 13 > 12, this 4-column-wide div gets wrapped onto a new line as one contiguous unit.
292 |
.col-6
Subsequent columns continue along the new line.
293 |
294 |
295 |
296 | 297 |

Column breaks

298 |
299 |
300 |
301 |
.col-6 .col-sm-3
302 |
.col-6 .col-sm-3
303 | 304 | 305 |
306 | 307 |
.col-6 .col-sm-3
308 |
.col-6 .col-sm-3
309 |
310 |
311 |
312 | 313 |

Reordering

314 |

Order

315 |
316 |
317 |
318 |
319 | First, but unordered 320 |
321 |
322 | Second, but last 323 |
324 |
325 | Third, but first 326 |
327 |
328 |
329 |
330 | 331 |

Offsetting columns

332 |
333 |
334 |
335 |
.col-md-4
336 |
.col-md-4 .offset-md-4
337 |
338 |
339 |
.col-md-3 .offset-md-3
340 |
.col-md-3 .offset-md-3
341 |
342 |
343 |
.col-md-6 .offset-md-3
344 |
345 |
346 |
347 |
348 |
349 |
350 |
.col-sm-5 .col-md-6
351 |
.col-sm-5 .offset-sm-2 .col-md-6 .offset-md-0
352 |
353 |
354 |
.col-sm-6 .col-md-5 .col-lg-6
355 |
.col-sm-6 .col-md-5 .offset-md-2 .col-lg-6 .offset-lg-0
356 |
357 |
358 |
359 | 360 |

Margin utilities

361 |
362 |
363 |
364 |
.col-md-4
365 |
.col-md-4 .ml-auto
366 |
367 |
368 |
.col-md-3 .ml-md-auto
369 |
.col-md-3 .ml-md-auto
370 |
371 |
372 |
.col-auto .mr-auto
373 |
.col-auto
374 |
375 |
376 |
377 | 378 |

Nesting

379 |
380 |
381 |
382 |
383 | Level 1: .col-sm-9 384 |
385 |
386 | Level 2: .col-8 .col-sm-6 387 |
388 |
389 | Level 2: .col-4 .col-sm-6 390 |
391 |
392 |
393 |
394 |
395 |
396 | 397 |
398 |
399 | 400 | -------------------------------------------------------------------------------- /main.css: -------------------------------------------------------------------------------- 1 | /* variables */ 2 | :root { 3 | --container-max-width: 1140px; 4 | --grid-columns: 12; 5 | --grid-gutter-width: 30px; 6 | } 7 | 8 | /* grid classes */ 9 | .container { 10 | width: 100%; 11 | max-width: var(--container-max-width); 12 | padding-right: calc(var(--grid-gutter-width) / 2); 13 | padding-left: calc(var(--grid-gutter-width) / 2); 14 | margin-right: auto; 15 | margin-left: auto; 16 | } 17 | .row { 18 | display: flex; 19 | flex-wrap: wrap; 20 | margin-right: calc(var(--grid-gutter-width) / -2); 21 | margin-left: calc(var(--grid-gutter-width) / -2); 22 | justify-content: var(--justify-content); 23 | align-items: var(--align-items); 24 | } 25 | [class^="col"] { 26 | padding-left: var(--grid-gutter-width); 27 | padding-right: var(--grid-gutter-width); 28 | width: 100%; /* or --col: var(--grid-columns); --> make items full-width when no default value for col (smallest breakpoint is set) */ 29 | 30 | --fixed-col-flex-grow: calc( var(--column-width) - var(--column-width)); 31 | --fixed-col-flex-basis: calc( var(--column-width) / var(--grid-columns) * 100% ); 32 | flex-basis: var(--fixed-col-flex-basis, 0); 33 | flex-grow: var(--fixed-col-flex-grow, 1); 34 | 35 | --column-width: var(--col); /* we need this value to diffrentiate basic xs width from the active width */ 36 | --column-offset: var(--offset); 37 | 38 | align-self: var(--align-self); 39 | order: var(--column-order); 40 | margin-left: calc( var(--column-offset) / var(--grid-columns) * 100% ); 41 | } 42 | .col-auto { 43 | width: auto; 44 | flex: 0 0 auto; 45 | } 46 | .col-sm,.col-md,.col-lg,.col-xl { 47 | flex-basis: auto; 48 | } 49 | .ml-auto { 50 | margin-left: auto; 51 | } 52 | .mr-auto { 53 | margin-right: auto; 54 | } 55 | 56 | /* responsive grid */ 57 | @media (min-width: 576px) { 58 | [class^="col"] { 59 | --col-sm: var(--col); /* fallback for --col-sm */ 60 | --column-width: var(--col-sm); /* if --col-sm is set inline it takes this value, if not it takes a fallback specified above */ 61 | 62 | --offset-sm: var(--offset); 63 | --column-offset: var(--offset-sm); 64 | } 65 | .col-sm { 66 | flex-basis: var(--fixed-col-flex-basis, 0); 67 | flex-grow: var(--fixed-col-flex-grow, 1); 68 | } 69 | .col-sm-auto { 70 | width: auto; 71 | flex: 0 0 auto; 72 | } 73 | .ml-sm-auto { 74 | margin-left: auto; 75 | } 76 | .mr-sm-auto { 77 | margin-right: auto; 78 | } 79 | } 80 | @media (min-width: 768px) { 81 | [class^="col"] { 82 | --col-md: var(--col-sm); 83 | --column-width: var(--col-md); 84 | 85 | --offset-md: var(--offset-sm); 86 | --column-offset: var(--offset-md); 87 | } 88 | .col-md { 89 | flex-basis: var(--fixed-col-flex-basis, 0); 90 | flex-grow: var(--fixed-col-flex-grow, 1); 91 | } 92 | .col-md-auto { 93 | width: auto; 94 | flex: 0 0 auto; 95 | } 96 | .ml-md-auto { 97 | margin-left: auto; 98 | } 99 | .mr-md-auto { 100 | margin-right: auto; 101 | } 102 | } 103 | @media (min-width: 992px) { 104 | [class^="col"] { 105 | --col-lg: var(--col-md); 106 | --column-width: var(--col-lg); 107 | 108 | --offset-lg: var(--offset-md); 109 | --column-offset: var(--offset-lg); 110 | } 111 | .col-lg { 112 | flex-basis: var(--fixed-col-flex-basis, 0); 113 | flex-grow: var(--fixed-col-flex-grow, 1); 114 | } 115 | .col-lg-auto { 116 | width: auto; 117 | flex: 0 0 auto; 118 | } 119 | .ml-lg-auto { 120 | margin-left: auto; 121 | } 122 | .mr-lg-auto { 123 | margin-right: auto; 124 | } 125 | } 126 | @media (min-width: 1200px) { 127 | [class^="col"] { 128 | --col-xl: var(--col-lg); 129 | --column-width: var(--col-xl); 130 | 131 | --offset-xl: var(--offset-lg); 132 | --column-offset: var(--offset-xl); 133 | } 134 | .col-xl { 135 | flex-basis: var(--fixed-col-flex-basis, 0); 136 | flex-grow: var(--fixed-col-flex-grow, 1); 137 | } 138 | .col-xl-auto { 139 | width: auto; 140 | flex: 0 0 auto; 141 | } 142 | .ml-xl-auto { 143 | margin-left: auto; 144 | } 145 | .mr-xl-auto { 146 | margin-right: auto; 147 | } 148 | } 149 | 150 | /* helpers */ 151 | .w-100 { 152 | width: 100%; 153 | } 154 | 155 | /* demo styles */ 156 | body { 157 | margin: 0; 158 | font: normal 100% sans-serif; 159 | background-color: white; 160 | } 161 | *, ::after, ::before { 162 | box-sizing: border-box; 163 | } 164 | main { 165 | padding: 30px; 166 | } 167 | .example { 168 | padding: 30px 30px 15px; 169 | border: 2px seashell solid; 170 | margin-bottom: 30px; 171 | } 172 | .example [class^="col"] { 173 | padding-top: calc( var(--grid-gutter-width) / 2); 174 | padding-bottom: calc( var(--grid-gutter-width) / 2); 175 | background: bisque; 176 | border: 1px sandybrown solid; 177 | } 178 | .example .row { 179 | margin-bottom: 15px; 180 | } 181 | .example [class^="row align"] { 182 | min-height: 10rem; 183 | background: antiquewhite; 184 | } --------------------------------------------------------------------------------