A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang=fr>
  4. <!-- Has to be within the first 1024 bytes, hence before the <title>
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset=utf-8>
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name=viewport content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Flexbox Grid Finesse (archive) — David Larlet</title>
  13. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  14. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons/apple-touch-icon.png">
  15. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons/favicon-32x32.png">
  16. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons/favicon-16x16.png">
  17. <link rel="manifest" href="/manifest.json">
  18. <link rel="mask-icon" href="/static/david/icons/safari-pinned-tab.svg" color="#5bbad5">
  19. <link rel="shortcut icon" href="/static/david/icons/favicon.ico">
  20. <meta name="apple-mobile-web-app-title" content="David Larlet">
  21. <meta name="application-name" content="David Larlet">
  22. <meta name="msapplication-TileColor" content="#da532c">
  23. <meta name="msapplication-config" content="/static/david/icons/browserconfig.xml">
  24. <meta name="theme-color" content="#f0f0ea">
  25. <!-- That good ol' feed, subscribe :p. -->
  26. <link rel=alternate type="application/atom+xml" title=Feed href="/david/log/">
  27. <meta name="robots" content="noindex, nofollow">
  28. <meta content="origin-when-cross-origin" name="referrer">
  29. <!-- Canonical URL for SEO purposes -->
  30. <link rel="canonical" href="http://www.heydonworks.com/article/flexbox-grid-finesse">
  31. <style>
  32. /* http://meyerweb.com/eric/tools/css/reset/ */
  33. html, body, div, span,
  34. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  35. a, abbr, address, big, cite, code,
  36. del, dfn, em, img, ins,
  37. small, strike, strong, tt, var,
  38. dl, dt, dd, ol, ul, li,
  39. fieldset, form, label, legend,
  40. table, caption, tbody, tfoot, thead, tr, th, td,
  41. article, aside, canvas, details, embed,
  42. figure, figcaption, footer, header, hgroup,
  43. menu, nav, output, ruby, section, summary,
  44. time, mark, audio, video {
  45. margin: 0;
  46. padding: 0;
  47. border: 0;
  48. font-size: 100%;
  49. font: inherit;
  50. vertical-align: baseline;
  51. }
  52. /* HTML5 display-role reset for older browsers */
  53. article, aside, details, figcaption, figure,
  54. footer, header, hgroup, menu, nav, section { display: block; }
  55. body { line-height: 1; }
  56. blockquote, q { quotes: none; }
  57. blockquote:before, blockquote:after,
  58. q:before, q:after {
  59. content: '';
  60. content: none;
  61. }
  62. table {
  63. border-collapse: collapse;
  64. border-spacing: 0;
  65. }
  66. /* http://practicaltypography.com/equity.html */
  67. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  68. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  69. @font-face {
  70. font-family: 'EquityTextB';
  71. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  72. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  73. font-weight: 300;
  74. font-style: normal;
  75. font-display: swap;
  76. }
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: italic;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  89. font-weight: 700;
  90. font-style: normal;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'ConcourseT3';
  95. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  96. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  97. font-weight: 300;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  102. body {
  103. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  104. font-family: "EquityTextB", Palatino, serif;
  105. background-color: #f0f0ea;
  106. color: #07486c;
  107. font-kerning: normal;
  108. -moz-osx-font-smoothing: grayscale;
  109. -webkit-font-smoothing: subpixel-antialiased;
  110. text-rendering: optimizeLegibility;
  111. font-variant-ligatures: common-ligatures contextual;
  112. font-feature-settings: "kern", "liga", "clig", "calt";
  113. }
  114. pre, code, kbd, samp, var, tt {
  115. font-family: 'TriplicateT4c', monospace;
  116. }
  117. em {
  118. font-style: italic;
  119. color: #323a45;
  120. }
  121. strong {
  122. font-weight: bold;
  123. color: black;
  124. }
  125. nav {
  126. background-color: #323a45;
  127. color: #f0f0ea;
  128. display: flex;
  129. justify-content: space-around;
  130. padding: 1rem .5rem;
  131. }
  132. nav:last-child {
  133. border-bottom: 1vh solid #2d7474;
  134. }
  135. nav a {
  136. color: #f0f0ea;
  137. }
  138. nav abbr {
  139. border-bottom: 1px dotted white;
  140. }
  141. h1 {
  142. border-top: 1vh solid #2d7474;
  143. border-bottom: .2vh dotted #2d7474;
  144. background-color: #e3e1e1;
  145. color: #323a45;
  146. text-align: center;
  147. padding: 5rem 0 4rem 0;
  148. width: 100%;
  149. font-family: 'ConcourseT3';
  150. display: flex;
  151. flex-direction: column;
  152. }
  153. h1.single {
  154. padding-bottom: 10rem;
  155. }
  156. h1 span {
  157. position: absolute;
  158. top: 1vh;
  159. left: 20%;
  160. line-height: 0;
  161. }
  162. h1 span a {
  163. line-height: 1.7;
  164. padding: 1rem 1.2rem .6rem 1.2rem;
  165. border-radius: 0 0 6% 6%;
  166. background: #2d7474;
  167. font-size: 1.3rem;
  168. color: white;
  169. text-decoration: none;
  170. }
  171. h2 {
  172. margin: 4rem 0 1rem;
  173. border-top: .2vh solid #2d7474;
  174. padding-top: 1vh;
  175. }
  176. h3 {
  177. text-align: center;
  178. margin: 3rem 0 .75em;
  179. }
  180. hr {
  181. height: .4rem;
  182. width: .4rem;
  183. border-radius: .4rem;
  184. background: #07486c;
  185. margin: 2.5rem auto;
  186. }
  187. time {
  188. display: bloc;
  189. margin-left: 0 !important;
  190. }
  191. ul, ol {
  192. margin: 2rem;
  193. }
  194. ul {
  195. list-style-type: square;
  196. }
  197. a {
  198. text-decoration-skip-ink: auto;
  199. text-decoration-thickness: 0.05em;
  200. text-underline-offset: 0.09em;
  201. }
  202. article {
  203. max-width: 50rem;
  204. display: flex;
  205. flex-direction: column;
  206. margin: 2rem auto;
  207. }
  208. article.single {
  209. border-top: .2vh dotted #2d7474;
  210. margin: -6rem auto 1rem auto;
  211. background: #f0f0ea;
  212. padding: 2rem;
  213. }
  214. article p:last-child {
  215. margin-bottom: 1rem;
  216. }
  217. p {
  218. padding: 0 .5rem;
  219. margin-left: 3rem;
  220. }
  221. p + p,
  222. figure + p {
  223. margin-top: 2rem;
  224. }
  225. blockquote {
  226. background-color: #e3e1e1;
  227. border-left: .5vw solid #2d7474;
  228. display: flex;
  229. flex-direction: column;
  230. align-items: center;
  231. padding: 1rem;
  232. margin: 1.5rem;
  233. }
  234. blockquote cite {
  235. font-style: italic;
  236. }
  237. blockquote p {
  238. margin-left: 0;
  239. }
  240. figure {
  241. border-top: .2vh solid #2d7474;
  242. background-color: #e3e1e1;
  243. text-align: center;
  244. padding: 1.5rem 0;
  245. margin: 1rem 0 0;
  246. font-size: 1.5rem;
  247. width: 100%;
  248. }
  249. figure img {
  250. max-width: 250px;
  251. max-height: 250px;
  252. border: .5vw solid #323a45;
  253. padding: 1px;
  254. }
  255. figcaption {
  256. padding: 1rem;
  257. line-height: 1.4;
  258. }
  259. aside {
  260. display: flex;
  261. flex-direction: column;
  262. background-color: #e3e1e1;
  263. padding: 1rem 0;
  264. border-bottom: .2vh solid #07486c;
  265. }
  266. aside p {
  267. max-width: 50rem;
  268. margin: 0 auto;
  269. }
  270. /* https://fvsch.com/code/css-locks/ */
  271. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  272. font-size: 1rem;
  273. line-height: calc( 1.5em + 0.2 * 1rem );
  274. }
  275. h1 {
  276. font-size: 1.9rem;
  277. line-height: calc( 1.2em + 0.2 * 1rem );
  278. }
  279. h2 {
  280. font-size: 1.6rem;
  281. line-height: calc( 1.3em + 0.2 * 1rem );
  282. }
  283. h3 {
  284. font-size: 1.35rem;
  285. line-height: calc( 1.4em + 0.2 * 1rem );
  286. }
  287. @media (min-width: 20em) {
  288. /* The (100vw - 20rem) / (50 - 20) part
  289. resolves to 0-1rem, depending on the
  290. viewport width (between 20em and 50em). */
  291. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  292. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  293. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  294. margin-left: 0;
  295. }
  296. h1 {
  297. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  298. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  299. }
  300. h2 {
  301. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  302. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  303. }
  304. h3 {
  305. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. }
  309. @media (min-width: 50em) {
  310. /* The right part of the addition *must* be a
  311. rem value. In this example we *could* change
  312. the whole declaration to font-size:2.5rem,
  313. but if our baseline value was not expressed
  314. in rem we would have to use calc. */
  315. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  316. font-size: calc( 1rem + .6 * 1rem );
  317. line-height: 1.5em;
  318. }
  319. p, li, pre, details {
  320. margin-left: 3rem;
  321. }
  322. h1 {
  323. font-size: calc( 1.9rem + 1.5 * 1rem );
  324. line-height: 1.2em;
  325. }
  326. h2 {
  327. font-size: calc( 1.5rem + 1.5 * 1rem );
  328. line-height: 1.3em;
  329. }
  330. h3 {
  331. font-size: calc( 1.35rem + 1.5 * 1rem );
  332. line-height: 1.4em;
  333. }
  334. figure img {
  335. max-width: 500px;
  336. max-height: 500px;
  337. }
  338. }
  339. figure.unsquared {
  340. margin-bottom: 1.5rem;
  341. }
  342. figure.unsquared img {
  343. height: inherit;
  344. }
  345. @media print {
  346. body { font-size: 100%; }
  347. a:after { content: " (" attr(href) ")"; }
  348. a, a:link, a:visited, a:after {
  349. text-decoration: underline;
  350. text-shadow: none !important;
  351. background-image: none !important;
  352. background: white;
  353. color: black;
  354. }
  355. abbr[title] { border-bottom: 0; }
  356. abbr[title]:after { content: " (" attr(title) ")"; }
  357. img { page-break-inside: avoid; }
  358. @page { margin: 2cm .5cm; }
  359. h1, h2, h3 { page-break-after: avoid; }
  360. p3 { orphans: 3; widows: 3; }
  361. img {
  362. max-width: 250px !important;
  363. max-height: 250px !important;
  364. }
  365. nav, aside { display: none; }
  366. }
  367. ul.with_columns {
  368. column-count: 1;
  369. }
  370. @media (min-width: 20em) {
  371. ul.with_columns {
  372. column-count: 2;
  373. }
  374. }
  375. @media (min-width: 50em) {
  376. ul.with_columns {
  377. column-count: 3;
  378. }
  379. }
  380. ul.with_two_columns {
  381. column-count: 1;
  382. }
  383. @media (min-width: 20em) {
  384. ul.with_two_columns {
  385. column-count: 1;
  386. }
  387. }
  388. @media (min-width: 50em) {
  389. ul.with_two_columns {
  390. column-count: 2;
  391. }
  392. }
  393. .gallery {
  394. display: flex;
  395. flex-wrap: wrap;
  396. justify-content: space-around;
  397. }
  398. .gallery figure img {
  399. margin-left: 1rem;
  400. margin-right: 1rem;
  401. }
  402. .gallery figure figcaption {
  403. font-family: 'ConcourseT3'
  404. }
  405. footer {
  406. font-family: 'ConcourseT3';
  407. display: flex;
  408. flex-direction: column;
  409. border-top: 3px solid white;
  410. padding: 4rem 0;
  411. background-color: #07486c;
  412. color: white;
  413. }
  414. footer > * {
  415. max-width: 50rem;
  416. margin: 0 auto;
  417. }
  418. footer a {
  419. color: #f1c40f;
  420. }
  421. footer .avatar {
  422. width: 200px;
  423. height: 200px;
  424. border-radius: 50%;
  425. float: left;
  426. -webkit-shape-outside: circle();
  427. shape-outside: circle();
  428. margin-right: 2rem;
  429. padding: 2px 5px 5px 2px;
  430. background: white;
  431. border-left: 1px solid #f1c40f;
  432. border-top: 1px solid #f1c40f;
  433. border-right: 5px solid #f1c40f;
  434. border-bottom: 5px solid #f1c40f;
  435. }
  436. </style>
  437. <h1>
  438. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  439. Flexbox Grid Finesse (archive)
  440. <time>Pour la pérennité des contenus liés. Non-indexé, retrait sur simple email.</time>
  441. </h1>
  442. <section>
  443. <article>
  444. <h3><a href="http://www.heydonworks.com/article/flexbox-grid-finesse">Source originale du contenu</a></h3>
  445. <div>
  446. <p class="intro"><em>(This post was originally published on Medium, put has a permanent home here.)</em></p>
  447. <p>Flexbox—not to be confused with <a href="https://en.wikipedia.org/wiki/Sex_Box">Sex Box</a>, the British TV show wherein Mariella Frostrup interviews people who’ve just had sex in a box—is the CSS layout toolkit <em>de rigueur</em>. Of all the celebrated features of Flexbox, it is the light work it makes of producing wrappable grids, tolerant of dynamic content, that I think’s integral. </p>
  448. <p>In this article, I’ll cover a few techniques to exploit Flexbox’s internal algorithms and design finessed grids intended for changing quantities and dimensions of content.</p>
  449. <h2 id="basic-wrapping">Basic wrapping</h2>
  450. <pre class="prettyprint"><code class=" hljs css"><span class="hljs-class">.parent</span> <span class="hljs-rules">{&#13;
  451. <span class="hljs-rule"><span class="hljs-attribute">display</span>:<span class="hljs-value"> flex</span></span>;&#13;
  452. <span class="hljs-rule"><span class="hljs-attribute">flex-flow</span>:<span class="hljs-value"> row wrap</span></span>;&#13;
  453. <span class="hljs-rule">}</span></span>&#13;
  454. &#13;
  455. <span class="hljs-class">.child</span> <span class="hljs-rules">{&#13;
  456. <span class="hljs-rule"><span class="hljs-attribute">flex</span>:<span class="hljs-value"> <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">25</span>%</span></span>;&#13;
  457. <span class="hljs-rule">}</span></span></code></pre>
  458. <p>I’ve made the <code>.parent</code> a flex container and used the <code>flex-flow</code> shorthand to set the <code>flex-direction</code> to <code>row</code> (i.e. following the horizontal axis) and enabled wrapping. Wrapping operates according to the <code>flex-basis</code> set on children; in this case <code>25%</code>. </p>
  459. <p>100 divided by 25 is 4, meaning what we have here is a 4 column grid. Simple stuff, I know. With wrapping on, a new row is begun every time you exceed 4 additional children. The last row is always complete, either because the total is exactly divisible by 4, or because the left over children are “grown” to share a row’s width. The “1” in <code>flex: 1 0 25%</code> essentially means the ability for children to grow is set to <em>on</em>.</p>
  460. <p>The upshot is that you can employ a grid which “tidies” itself, distributing children automatically. This is powerful stuff. I can be assured that no matter the number of children currently included, my layout will be acceptable.</p>
  461. <h2 id="element-queries">Element queries</h2>
  462. <p>I’m not the first (I think <a href="https://twitter.com/zomigi">Zoe Gillenwater</a> pointed it out) to notice that Flexbox can be made to employ something akin to “element queries”; changes in an element’s layout based on that element’s own dimensions. By incorporating a <code>min-width</code> into the last example, I can trigger elements to grow at this “breakpoint”. </p>
  463. <pre class="prettyprint"><code class=" hljs css"><span class="hljs-class">.parent</span> <span class="hljs-rules">{&#13;
  464. <span class="hljs-rule"><span class="hljs-attribute">display</span>:<span class="hljs-value"> flex</span></span>;&#13;
  465. <span class="hljs-rule"><span class="hljs-attribute">flex-flow</span>:<span class="hljs-value"> row wrap</span></span>;&#13;
  466. <span class="hljs-rule">}</span></span>&#13;
  467. &#13;
  468. <span class="hljs-class">.child</span> <span class="hljs-rules">{&#13;
  469. <span class="hljs-rule"><span class="hljs-attribute">flex</span>:<span class="hljs-value"> <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">25</span>%</span></span>;&#13;
  470. <span class="hljs-rule"><span class="hljs-attribute">min-width</span>:<span class="hljs-value"> <span class="hljs-number">5</span>em</span></span>;&#13;
  471. <span class="hljs-rule">}</span></span></code></pre>
  472. <p>I have made my grid entirely responsive with just one additional declaration. The number of columns is predicated on the simple axiom that no one column (element) can be fewer than <code>5em</code> in width. Flexbox’s <code>grow</code> takes care of expanding children that hit this minimum width, making sure they never get any narrower than this setting. Wrapping takes care of everything else.</p>
  473. <h2 id="dealing-with-remainders-of-1">Dealing with remainders of 1</h2>
  474. <p>If I have a 4 column grid with 8 children present then I add a child element, that element will constitute the whole of the bottom row. Ideally, I’d like to move things around so that this is not the case. By harnessing the ability of my elements to grow and incorporating nome <code>nth-child</code> magic, I can essentially borrow elements from the penultimate row to distribute the elements towards the end of the grid more reasonably. I can also do this without negatively affecting other quantities of elements producing more than a single remainder or no remainder at all.</p>
  475. <p>In the following example, I’ve adapted the first example in this article.</p>
  476. <pre class="prettyprint"><code class=" hljs css"><span class="hljs-class">.parent</span> <span class="hljs-rules">{&#13;
  477. <span class="hljs-rule"><span class="hljs-attribute">display</span>:<span class="hljs-value"> flex</span></span>;&#13;
  478. <span class="hljs-rule"><span class="hljs-attribute">flex-flow</span>:<span class="hljs-value"> row wrap</span></span>;&#13;
  479. <span class="hljs-rule">}</span></span>&#13;
  480. &#13;
  481. <span class="hljs-class">.child</span> <span class="hljs-rules">{&#13;
  482. <span class="hljs-rule"><span class="hljs-attribute">flex</span>:<span class="hljs-value"> <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">25</span>%</span></span>;&#13;
  483. <span class="hljs-rule">}</span></span>&#13;
  484. &#13;
  485. <span class="hljs-class">.child</span><span class="hljs-pseudo">:nth-last-child(2)</span><span class="hljs-pseudo">:nth-child(4n)</span> <span class="hljs-rules">{&#13;
  486. <span class="hljs-rule"><span class="hljs-attribute">min-width</span>:<span class="hljs-value"> <span class="hljs-number">33</span>%</span></span>;&#13;
  487. <span class="hljs-rule">}</span></span></code></pre>
  488. <p>This selector expression in the last block targets any element that falls in the fourth and final column (<code>4n</code>) which is simultaneously the penultimate element ”“ that is, the element before the long, single remainder. By bumping this element’s width to <code>33%</code>, it’s forced down into the final line, leaving the penultimate line with just three elements. </p>
  489. <p>The result is the elimination of the single element and a dynamic grid that resolves into a line of 4, then 3, then 2 children when there is a single remainder. No matter how many child elements are present, the grid never ends with a single element row.</p>
  490. <p>Try adding and removing items in <a href="http://codepen.io/heydon/pen/zvNxZN">this codePen demo</a> and experimenting with different numbers of columns. The basic formula for the selector is <code>.child:nth-last-child(2):nth-child([number of columns]n)</code>. The width you set has to be somewhere between the base width and the base width for the grid if it had one less column. So, if there are five columns, the width set in this override should be between 20% and 25%.</p>
  491. <h2 id="controlled-chaos">Controlled chaos</h2>
  492. <p>In the last example, I singled out a child element based on its index using the algebraic <code>:nth-child</code> and <code>nth-last-child</code>. Because of my Flexbox configuration’s insistence of filling the available space according to its element growth and wrapping features, I could do this safe in the knowledge that I would not produce an incomplete, gap-ridden grid.</p>
  493. <p>Based on this principle, I can arbitrarily change the widths of any grid children I like. I can get quite expressive with this and build in some algorithmic asymmetry.</p>
  494. <pre class="prettyprint"><code class=" hljs css"><span class="hljs-class">.child</span><span class="hljs-pseudo">:nth-child(3n)</span> <span class="hljs-rules">{&#13;
  495. <span class="hljs-rule"><span class="hljs-attribute">width</span>:<span class="hljs-value"> <span class="hljs-number">33.333</span>%</span></span>;&#13;
  496. <span class="hljs-rule">}</span></span>&#13;
  497. &#13;
  498. <span class="hljs-class">.child</span><span class="hljs-pseudo">:nth-child(5n)</span> <span class="hljs-rules">{&#13;
  499. <span class="hljs-rule"><span class="hljs-attribute">width</span>:<span class="hljs-value"> <span class="hljs-number">50</span>%</span></span>;&#13;
  500. <span class="hljs-rule">}</span></span>&#13;
  501. &#13;
  502. <span class="hljs-class">.child</span><span class="hljs-pseudo">:nth-child(7n)</span> <span class="hljs-rules">{&#13;
  503. <span class="hljs-rule"><span class="hljs-attribute">width</span>:<span class="hljs-value"> <span class="hljs-number">66.666</span>%</span></span>;&#13;
  504. <span class="hljs-rule">}</span></span></code></pre>
  505. <p>By using prime numbers (3, 5 and 7) to augment the child elements’ width at intervals, any perceived regularity in the layout can be easily diminished. However, the layout never <em>breaks</em> as such thanks to our go-to wrapping and growth settings. Be sure to try out the <a href="http://codepen.io/heydon/pen/GpbQdP">codePen demo</a> for this one and experiment with different, superimposed <code>nth-child</code> intervals.</p>
  506. <h2 id="gutter-tactics">Gutter tactics</h2>
  507. <p><em>(This is an edit to the original article after <a href="https://medium.com/@StuCoxMedia/how-would-you-suggest-adding-a-gutter-with-this-pattern-6e176fb6b4e9#.2ts42s545">Stu Cox</a> started a discussion about how one might deal with gutters.)</em></p>
  508. <p>Gutters are, put simply, the gaps between grid children to space them. I’m not absolutely certain what the “flexy” way to add gutters to any of my described grids would be, but I am aware of one technique which would create gutters that do not break when wrapping produces remainders.</p>
  509. <pre class="prettyprint"><code class=" hljs css"><span class="hljs-class">.parent</span> <span class="hljs-rules">{&#13;
  510. <span class="hljs-rule"><span class="hljs-attribute">display</span>:<span class="hljs-value"> flex</span></span>;&#13;
  511. <span class="hljs-rule"><span class="hljs-attribute">flex-flow</span>:<span class="hljs-value"> row wrap</span></span>;&#13;
  512. <span class="hljs-rule"><span class="hljs-attribute">margin-left</span>:<span class="hljs-value"> -<span class="hljs-number">0.5</span>rem</span></span>;&#13;
  513. <span class="hljs-rule"><span class="hljs-attribute">margin-right</span>:<span class="hljs-value"> -<span class="hljs-number">0.5</span>rem</span></span>;&#13;
  514. <span class="hljs-rule">}</span></span>&#13;
  515. &#13;
  516. <span class="hljs-class">.child</span> <span class="hljs-rules">{&#13;
  517. <span class="hljs-rule"><span class="hljs-attribute">flex</span>:<span class="hljs-value"> <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">25</span>%</span></span>;&#13;
  518. <span class="hljs-rule"><span class="hljs-attribute">box-sizing</span>:<span class="hljs-value"> border-box</span></span>;&#13;
  519. <span class="hljs-rule"><span class="hljs-attribute">padding</span>:<span class="hljs-value"> <span class="hljs-number">0</span> <span class="hljs-number">0.5</span>rem <span class="hljs-number">1</span>rem</span></span>;&#13;
  520. <span class="hljs-rule">}</span></span></code></pre>
  521. <p>It is important that I treat each item equally, rather than trying to anticipate things with nth children, because any of my items can potentially grow or wrap. Hence the <code>padding: 0.5rem 1rem</code> on all <code>.child</code> elements. This produces a <code>1rem</code> gutter around each child, no matter how they wrap or grow.</p>
  522. <p>All that’s left is to compensate for the redundant 0.5rem space for left-most and right-most children, facilitated by the left and right negative margins on the parent (Stu arrived at this notion). Depending on the vertical rhythm of your page, you may want to remove the redundant bottom margin of the last child row too, with margin-bottom: -1rem on the parent too. There is <a href="http://codepen.io/heydon/pen/EVqwOW">a codePen to play with</a>.</p>
  523. <h2 id="conclusion">Conclusion</h2>
  524. <p>I hope that this short article has given you something to think about regarding the way Flexbox handles and tolerates dynamic content, allowing you to tersely code robust yet expressive layouts. With Flexbox, for the first time, we’re afforded something akin to true grid <em>systems</em>; grids which govern themselves, freeing us to focus on content creation and aesthetics.</p>
  525. </div>
  526. </article>
  527. </section>
  528. <nav id="jumpto">
  529. <p>
  530. <a href="/david/blog/">Accueil du blog</a> |
  531. <a href="http://www.heydonworks.com/article/flexbox-grid-finesse">Source originale</a> |
  532. <a href="/david/stream/2019/">Accueil du flux</a>
  533. </p>
  534. </nav>
  535. <footer>
  536. <div>
  537. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  538. <p>
  539. Bonjour/Hi!
  540. Je suis <a href="/david/" title="Profil public">David&nbsp;Larlet</a>, je vis actuellement à Montréal et j’alimente cet espace depuis 15 ans. <br>
  541. Si tu as apprécié cette lecture, n’hésite pas à poursuivre ton exploration. Par exemple via les <a href="/david/blog/" title="Expériences bienveillantes">réflexions bimestrielles</a>, la <a href="/david/stream/2019/" title="Pensées (dés)articulées">veille hebdomadaire</a> ou en t’abonnant au <a href="/david/log/" title="S’abonner aux publications via RSS">flux RSS</a> (<a href="/david/blog/2019/flux-rss/" title="Tiens c’est quoi un flux RSS ?">so 2005</a>).
  542. </p>
  543. <p>
  544. Je m’intéresse à la place que je peux avoir dans ce monde. En tant qu’humain, en tant que membre d’une famille et en tant qu’associé d’une coopérative. De temps en temps, je fais aussi des <a href="https://github.com/davidbgk" title="Principalement sur Github mais aussi ailleurs">trucs techniques</a>. Et encore plus rarement, <a href="/david/talks/" title="En ce moment je laisse plutôt la place aux autres">j’en parle</a>.
  545. </p>
  546. <p>
  547. Voici quelques articles choisis :
  548. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  549. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  550. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  551. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  552. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  553. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  554. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  555. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  556. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  557. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  558. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  559. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  560. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  561. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  562. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  563. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  564. </p>
  565. <p>
  566. On peut <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">échanger par courriel</a>. Si éventuellement tu souhaites que l’on travaille ensemble, tu devrais commencer par consulter le <a href="http://larlet.com">profil dédié à mon activité professionnelle</a> et/ou contacter directement <a href="http://scopyleft.fr/">scopyleft</a>, la <abbr title="Société coopérative et participative">SCOP</abbr> dont je fais partie depuis six ans. Je recommande au préalable de lire <a href="/david/blog/2018/cout-site/" title="Attention ce qui va suivre peut vous choquer">combien coûte un site</a> et pourquoi je suis plutôt favorable à une <a href="/david/pro/devis/" title="Discutons-en !">non-demande de devis</a>.
  567. </p>
  568. <p>
  569. Je ne traque pas ta navigation mais mon
  570. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  571. conserve des logs d’accès.
  572. </p>
  573. </div>
  574. </footer>
  575. <script type="text/javascript">
  576. ;(_ => {
  577. const jumper = document.getElementById('jumper')
  578. jumper.addEventListener('click', e => {
  579. e.preventDefault()
  580. const anchor = e.target.getAttribute('href')
  581. const targetEl = document.getElementById(anchor.substring(1))
  582. targetEl.scrollIntoView({behavior: 'smooth'})
  583. })
  584. })()
  585. </script>