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 68KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  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>Designing with Progressive Enhancement (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://sixtwothree.org/posts/designing-with-progressive-enhancement">
  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. Designing with Progressive Enhancement (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://sixtwothree.org/posts/designing-with-progressive-enhancement">Source originale du contenu</a></h3>
  445. <p>The following is the text (and links!) from my presentation at the seventh annual <a href="http://csssummit.com/">CSS Summit</a>, delivered Tuesday morning, July 7th, 2015. <a href="https://speakerdeck.com/jgarber/designing-with-progressive-enhancement">Slides from this talk</a> are also available.</p>
  446. <p>I’d like to thank <a href="http://jcarbaugh.com/">Jeremy Carbaugh</a>, <a href="http://veronicaerb.com/">Veronica Erb</a>, <a href="http://www.aaron-gustafson.com/">Aaron Gustafson</a>, and <a href="http://tpitale.com/">Tony Pitale</a> for reviewing early versions of this presentation.</p>
  447. <hr/>
  448. <p>Good morning!</p>
  449. <p>First off, I’d like to thank <a href="http://christopherschmitt.com/">Christopher</a> and <a href="http://www.aristiles.com/">Ari</a> at <a href="http://environmentsforhumans.com/">Environments for Humans</a> for putting together this wonderful event and for inviting me to speak with you all today. It’s a pleasure to be here and I’m excited to share with you some lessons I’ve learned designing and building things on the Web for nearly twenty years.</p>
  450. <p>I’m here today to talk with you about a Web development methodology known as <a href="https://en.wikipedia.org/wiki/Progressive_enhancement">progressive enhancement</a>. Some of you may be familiar with the concept, others not. Don’t worry; there’s plenty here for everyone, independent of your familiarity with the technique.</p>
  451. <p>I’ve organized today’s presentation into three major sections:</p>
  452. <ol>
  453. <li>I’ll give a brief history of progressive enhancement: what the term means, the environment from which it grew, and how it compared to existing development strategies of the time.</li>
  454. <li>I’ll compare those circumstances to the Web as we know it. That is, how does a methodology like progressive enhancement fit into the state of the Web in 2015.</li>
  455. <li>I’ll walk through some examples of progressive enhancement as applied to the Web’s front-end layers: HTML, CSS, and JavaScript.</li>
  456. </ol>
  457. <p>There’s a lot to cover, so let’s dive in.</p>
  458. <h2>A Brief History of Progressive Enhancement</h2>
  459. <p>Before we can talk about progressive enhancement’s relevance in 2015, we must first look to the past. Two thousand and three, to be exact.</p>
  460. <h3>State of the Web: 2003 Edition</h3>
  461. <p>By 2003, the <a href="https://en.wikipedia.org/wiki/Browser_wars">first browser wars</a> were over and Microsoft’s Internet Explorer 6 stood atop a decimated landscape. In January of that year, Steve Jobs announced the release of <a href="https://en.wikipedia.org/wiki/Safari_(web_browser)">Apple’s Safari Web browser</a>, giving us the first version of the <a href="https://en.wikipedia.org/wiki/WebKit">Webkit rendering engine</a>. <a href="https://en.wikipedia.org/wiki/Netscape">Netscape</a> by this point had already open-sourced their browser’s code, spawning the <a href="https://en.wikipedia.org/wiki/Mozilla">Mozilla</a> project and its suite of applications. Mozilla’s Phoenix browser—which we now know as <a href="https://en.wikipedia.org/wiki/Firefox">Firefox</a>—was just beginning to capture savvy Web users' attention and Google, as characterized by then-CEO Eric Schmidt, was “<a href="http://blogs.wsj.com/digits/2009/07/09/sun-valley-schmidt-didnt-want-to-build-chrome-initially-he-says/">a small company</a>.”</p>
  462. <p>While alternatives to Internet Explorer were available, for all intents and purposes, we lived with a de facto browser monoculture.</p>
  463. <h3>The Participatory Web</h3>
  464. <p>The Web at this time was also on the cusp of its second boom cycle—later dubbed <a href="https://en.wikipedia.org/wiki/Web_2.0">Web 2.0</a>—which would blow the Web’s doors wide open, inviting everyone to participate online via easy-to-use blogging services and new social networks. Looking at raw numbers, in 2003, <a href="http://www.internetworldstats.com/emarketing.htm">upwards of 700 million people</a>—roughly 10% of the world’s population—were online. An additional hundred million would come online by the end of the following year.</p>
  465. <h3>Graceful Degradation</h3>
  466. <p>The prevailing development practice at the time—<a href="https://en.wikipedia.org/wiki/Fault_tolerance">graceful degradation</a>—focused on providing an optimal experience to the latest and greatest browsers with little focus on users saddled with older or less-capable browsers. In practical terms, this approach amounted to coding for an ideal set of circumstances—a particular browser or a certain amount of bandwidth—and hoping for the best in all other cases. Web developers made <em>a lot</em> of dangerous assumptions about how their websites were accessed.</p>
  467. <p>While it was common practice throughout the industry, graceful degradation had its critics.</p>
  468. <h3>South by Southwest 2003</h3>
  469. <p>Way back in March of 2003, at a then-tiny conference in Austin, Texas, <a href="http://hesketh.com/">Steve Champeon</a> delivered a presentation titled “<a href="http://hesketh.com/publications/inclusive_web_design_for_the_future/">Inclusive Web Design for the Future</a>.”</p>
  470. <p>In his presentation, Steve threw the gauntlet squarely at the feet of Web designers, declaring:</p>
  471. <blockquote>
  472. <p>Web design must mature and accept the developments of the past several years, abandon the exclusionary attitudes formed in the rough and tumble dotcom era, realize the coming future of a wide variety of devices and platforms, and separate semantic markup from presentation logic and behavior.</p>
  473. </blockquote>
  474. <p>I’ll repeat my favorite line from that because it’s so beautifully forward-thinking:</p>
  475. <blockquote>
  476. <p>The coming future of a wide variety of devices and platforms.</p>
  477. </blockquote>
  478. <p>This was 2003: four years before the release of the first iPhone and what we now consider the launch of the modern, mobile-accessible Web.</p>
  479. <p>He continues:</p>
  480. <blockquote>
  481. <p>The goal of Web design is not merely to dazzle, but to deliver information to the widest audience possible.</p>
  482. </blockquote>
  483. <p>Steve’s approach—progressive enhancement—flipped graceful degradation on its head by focusing on providing <em>everyone</em> with access to a website’s content and layering on technology—HTML, CSS, and JavaScript—in responsible ways that enhance the experience of lower layers in the stack.</p>
  484. <h3>Content-Focused Design</h3>
  485. <p>As <a href="http://www.aaron-gustafson.com/">Aaron Gustafson</a> would later write in “<a href="http://www.amazon.com/dp/098358950X/?tag=sixtwothree-20">Adaptive Web Design</a>,” progressive enhancement is about “crafting experiences that serve your audience by giving them access to content without technological restrictions.” This gets to the heart of progressive enhancement as originally conceived: universal access to a website’s content irrespective of a person’s physical abilities or technological capabilities.</p>
  486. <p>On that point: It’s important to keep in mind that we each experience and interact with the Web in different ways. Those differences may be subtle or pronounced, but they exist and we shouldn’t forget that.</p>
  487. <p>So these are the philosophical origins and underpinnings of progressive enhancement: a content-first, accessible, inclusive, layered approach to building websites.</p>
  488. <h2>Progressive Enhancement in 2015</h2>
  489. <p>Now that we’ve got the history lesson behind us, let’s take a look at how the Web’s changed in the intervening years. Twelve years ago, we wrestled with limited bandwidth, memory-constrained devices, and display, screen size, and resolution limitations.</p>
  490. <p>That… sounds awfully familiar…</p>
  491. <p><em>Today we wrestle with limited bandwidth, memory-constrained devices, and display, screen size, and resolution limitations.</em></p>
  492. <h3>Ch-ch-changes</h3>
  493. <p>But to say nothing has changed in twelve years would, of course, be disingenuous. <em>Everything has changed.</em> It’s 2015! We have iPhones. We have the Samsung Galaxy series of devices. <a href="http://www.mi.com/en/">Xiaomi</a> has tremendous traction in China. We interact with high-resolution displays of all shapes and sizes. There are <a href="https://en.wikipedia.org/wiki/Internet_refrigerator">Web browsers in refrigerators</a>, for crying out loud. We wear <a href="http://www.android.com/wear/">the Web on our wrist</a> and we carry the Web in our pocket.</p>
  494. <p>We have “web apps!” I don’t really know what that means or how a “web app” is different from a website, but still… We have things called “web apps!”</p>
  495. <p>On the Web design front, <a href="http://unstoppablerobotninja.com/">Ethan Marcotte</a> clued us in to <a href="https://en.wikipedia.org/wiki/Responsive_web_design">responsive Web design</a>, native <a href="https://responsiveimages.org/">responsive images</a> are just around the corner, and our ability to tap in to device APIs—<a href="https://developer.mozilla.org/en-US/docs/Web/API/Geolocation">geolocation</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/API/DeviceLightEvent">ambient light detection</a>, and more—expands on a weekly basis.</p>
  496. <p>Most importantly, there are more human beings than ever using more devices than ever connecting to the Web in more diverse—and often <a href="http://trentwalton.com/2014/03/10/device-agnostic/">hostile</a>—conditions than ever before.</p>
  497. <h3>Opportunity vs. Availability</h3>
  498. <p>While we now have more <em>opportunity</em> to connect to the Internet than ever before, the <em>availability</em> and wildly variable <em>quality</em> of that connection is likewise greater than ever before. We’ll talk more about availability in a minute, but you’ve no doubt experienced this opportunity versus availability challenge in your own daily life.</p>
  499. <p>If you regularly take public transportation, particularly the subway or the train, then you know the pains of intermittent cellular data network connections. If you work in cafés, libraries, or other public spaces, then you know the pains of slow WiFi connections. Visit anywhere outside of major metropolitan centers and you’ll quickly feel the excrutiating pain of browsing the Web on <a href="https://en.wikipedia.org/wiki/General_Packet_Radio_Service">GPRS or EDGE networks</a>.</p>
  500. <p>Unfortunately, these challenges—the opportunity to connect versus the availability and quality of the connection—aren’t unique to us Web designers. The users of our products deal with these challenges in their daily lives as well and, as much as we wish the opposite were true, we don’t get to decide how, when, and where our audience interacts with our websites.</p>
  501. <h3>Internet Trends</h3>
  502. <p>Kleiner Perkins' <a href="http://www.slideshare.net/kleinerperkins/internet-trends-v1">2015 Internet Trends Report</a> just came out and, according to their research, there are 2.8 billion people online, accounting for 39% of the world’s population. Contrast that with the <a href="http://www.internetworldstats.com/emarketing.htm">roughly 700 million people online in 2003</a> and you’ll get a sense for how much has changed. Of those 2.8 billion people online in 2014, 70% percent of them live outside of Europe and the United States.</p>
  503. <p>The report also found a whopping 5.2 billion people—73% of all living humans on this planet—own mobile phones. Of those mobile phones, 40%—nearly 2.1 billion—are smartphones. Presuming each of those smartphones has <em>at least</em> one proper Web browser and a handful of apps with in-app browsers, we quickly arrive at a practically infinite number of combinations of browsers and devices.</p>
  504. <p><em>The mind reels.</em></p>
  505. <h3>A Different Approach for a Changed Web?</h3>
  506. <p>The question then is: Does this notion of progressive enhancement, as originally conceived in 2003, espousing a content-first, accessible, inclusive, layered approach to building websites, still make sense on today’s Web?</p>
  507. <p>I contend that, yes, this approach makes more sense now than ever before!</p>
  508. <p>How we think and talk about this approach has evolved dramatically, though.</p>
  509. <p>Over the last twelve years, the conversation around progressive enhancement shifted and lost focus as the term itself became too closely associated with a singular technology: JavaScript. Rather than referring to a broader, layered approach to building websites, “progressive enhancement” became tantamount to “dealing with users who have JavaScript turned off.”</p>
  510. <p>The general thinking devolved into fallacious statements like:</p>
  511. <ul>
  512. <li>“We can’t do cool things if we have to do progressive enhancement!”</li>
  513. <li>“Progressive enhancement means we have to waste time and money supporting old versions of Internet Explorer!”</li>
  514. <li>“No one in our target audience turns off JavaScript!”</li>
  515. </ul>
  516. <p>The waters were further muddied when we rekindled our torrid love affair with JavaScript. The quick rise—and often just as quick fall—of libraries and frameworks like <a href="http://prototypejs.org/">Prototype</a>, <a href="http://jquery.com/">jQuery</a>, <a href="http://backbonejs.org/">Backbone</a>, <a href="https://angularjs.org/">Angular</a>, and <a href="https://facebook.github.io/react/">React</a> have brought with them a ton of new ideas and opportunities. What they’ve also brought with them—and I believe unintentionally so—are misconceptions about the nature of the Web and actual users' experiences with the Web.</p>
  517. <p>I mentioned earlier the dangerous assumptions Web designers made using the graceful degradation methodology: coding for a particular browser or expecting a certain amount of bandwidth. While not the fault of any one particular framework, many of these same assumptions are creeping their way back into our work.</p>
  518. <h3>An Evolved Definition</h3>
  519. <p>I’d like for us to reframe the conversation around progressive enhancement; to <em>take it back</em> as it were. The timing of CSS Summit is fortuitous as it closely follows this year’s <a href="https://edgeconf.com/2015-london">Edge Conference</a> in London, held at the end of last month. <a href="http://www.lyza.com/">Lyza Danger Gardner</a> moderated a panel discussion on progressive enhancement and out of that conversation spun a number of blog posts and tweets from folks sharing their perspectives on the subject. It’s been a thought-provoking ten days that’s reshaped how I think about progressive enhancement.</p>
  520. <p>While at its core, progressive enhancement remains a content-first, accessible, inclusive, layered approach to building websites, a newer definition is emerging. Progressive enhancement in 2015 has evolved to mean:</p>
  521. <p><em>Making available to all users a baseline experience with access to core content and functionality by reducing assumption.</em></p>
  522. <p>Let’s dissect that.</p>
  523. <h4>Availability</h4>
  524. <p>Stuart Langridge brought <a href="http://www.kryogenix.org/days/2015/06/28/availability/">availability</a> to the conversation and further demonstrated his point with some <a href="http://www.kryogenix.org/code/browser/why-availability/">smiling diagrams</a>. Stuart writes:</p>
  525. <blockquote>
  526. <p>I’m going to be talking about availability. About reach. About my web apps being for everyone even when the universe tries to get in the way.</p>
  527. </blockquote>
  528. <p>And rest assured, the universe will get in the way. Websites can fail for many reasons: dodgy WiFi, a <a href="https://en.wikipedia.org/wiki/Content_delivery_network">CDN</a> goes down for ten seconds, an asset server crashes. These are real things that happen every day on the Web despite our best efforts. Our awareness of this reality should inform our design and development process.</p>
  529. <p>Pertaining to availability, here are a few questions to keep in mind as you design and build your website:</p>
  530. <ul>
  531. <li>“Is my website’s core content and functionality available in the initial HTML sent from the server to the user’s browser?”</li>
  532. <li>“Would someone be able to accomplish their tasks if one or more of my website’s components—images, CSS, or JavaScript—failed to load?”</li>
  533. <li>“What advanced technologies (e.g. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage">localStorage</a>) could I take advantage of to account for unforeseen circumstances?”</li>
  534. </ul>
  535. <h4>Baselines</h4>
  536. <p>Progressive enhancement’s foundation rests on the baseline experience. But what is that baseline experience?</p>
  537. <p>We often couch baseline experiences in terms of browsers and versions: “This site will work in Internet Explorer 8 and above; the latest versions of Chrome, Firefox, and Safari; and on iPhone and iPad.” While this kind of thinking lends itself nicely to QA checklists, it fails to acknowledge the real-world diversity of device and browser combinations.</p>
  538. <p>Instead of thinking in terms of browsers, <a href="https://adactio.com/journal/9206">Jeremy Keith defines a baseline experience</a> as “the minimum required technology to allow a user to accomplish the <em>core</em> task.” He specifically differentiates the <em>core</em> task from nice-to-haves that rely on more sophisticated technology.</p>
  539. <p>There are three technologies required to deliver the absolute bare minimum website: a running Web server, HTTP, and HTML. A server, a protocol, and a text file containing structured content. That’s it!</p>
  540. <p>You may determine that the baseline for your project requires additional technology, but for many, many, many projects, these three basic, reliable tools will do the job.</p>
  541. <p>The question to keep in mind here is: “What are the <em>most basic</em> technologies required to deliver a functional website?”</p>
  542. <h4>Core Functionality</h4>
  543. <p>We established earlier that progressive enhancement is a content-first approach to design. Given the participatory nature of today’s Web, we must expand that content-first approach to include user actions.</p>
  544. <p>Instead of determining a website’s core content and ensuring its delivered in an accessible way, we must ensure that a website’s core content <em>and</em> functionality are delivered accessibly. This is what Jeremy refers to as the <em>core task</em>. The nature of that core task will vary depending on the purpose of your website:</p>
  545. <ul>
  546. <li>Reading a news article or blog post.</li>
  547. <li>Looking up critical health care information.</li>
  548. <li>Managing finances or applying for a loan.</li>
  549. </ul>
  550. <p>Identify those core tasks and ensure that users can quickly and efficiently complete them with and without enhancements like images, CSS, and JavaScript.</p>
  551. <p>The key question to think about here is an obvious one: “For any given page or flow on my website, what is the core task?”</p>
  552. <h4>Reducing Assumptions</h4>
  553. <p>I’ve mentioned assumptions several times this morning, mostly in a negative context. I want to be clear, though, that not all assumptions are bad or evil or wrong, or that we aren’t allowed to make assumptions in our work. Practicality—particularly in the agency setting—requires us to make assumptions and tradeoffs every day; it’s built into the nature of our work.</p>
  554. <p>We can—and should—work tirelessly to eliminate assumption wherever possible, though. <a href="http://timkadlec.com/">Tim Kadlec</a>, in his recent post “<a href="http://timkadlec.com/2015/06/thriving-in-unpredictability/">Thriving in Unpredictability</a>,” expertly writes:</p>
  555. <blockquote>
  556. <p>Assumptions will naturally be made at some point. But I want to make as few of those assumptions as possible. Because every assumption I make introduces fragility. Every assumption introduces another way that my site can break.</p>
  557. </blockquote>
  558. <p>Every assumption we build into our work introduces fragility and the possibility of something breaking. Tim’s post is a brilliant miniature manifesto in which he divests himself of control over devices, browsers, contexts, the network, and more.</p>
  559. <p>In a lot of ways, “Thriving in Unpredictability” reminds me of John Allsopp’s “<a href="http://alistapart.com/article/dao">A Dao of Web Design</a>,” published fifteen years ago on A List Apart. “Dao” is a must-read piece of Web design literature full of lessons still applicable to our work today. In it, John rightly insists that we relinquish control and “accept the ebb and flow of things.”</p>
  560. <p>By reducing assumption, we accept the unpredictability of the Web; the “ebb and flow of things.” Constantly ask yourself, “What assumptions am I making and what can be done to reduce those assumptions?”</p>
  561. <h3>Ch-ch-changes?</h3>
  562. <p>Progressive enhancement’s twelve years old. “A Dao of Web Design” is <em>fifteen</em> years old. And yet, the lessons we can take from each remain relevant today. So has anything <em>really</em> changed?</p>
  563. <p>Let’s take another look at the modernized definition of progressive enhancement:</p>
  564. <p><em>Making available to all users a baseline experience with access to core content and functionality by reducing assumption.</em></p>
  565. <p>That feels pretty good, right?</p>
  566. <p>Nowhere have we said that, if you build a progressively-enhanced website, you can’t take advantage of the latest-and-greatest browser features. <em>Quite the opposite, in fact.</em> Applying progressive enhancement affords you the opportunity to utilize new, cutting-edge browser features in a way that ensures users without those capabilities aren’t left out in the cold. When you start with an accessible baseline experience, the sky’s the limit!</p>
  567. <p>A colleague of mine recently declared: “In 2015, I don’t think JavaScript is an enhancement—it’s the baseline.”</p>
  568. <p>I reject that notion, though. Based on everything we’ve looked at so far—devices, browsers, networks, contexts—I can’t in good conscience accept a statement like that. Particularly when building progressively-enhanced websites—and yes, even <em>web apps</em>—is perfectly achievable with a little bit of planning, know-how, and elbow grease.</p>
  569. <h2>Applying Progressive Enhancement</h2>
  570. <p>Earlier, I noted how, in conversations about progressive enhancement, the technique is often misrepresented as only being concerned with the behavior layer of the front-end Web stack. While JavaScript is an important part of building progressively-enhanced websites, it’s certainly not the only layer to benefit from the approach.</p>
  571. <p>Let’s take a look at some examples of progressive enhancement applied to HTML, CSS, and JavaScript.</p>
  572. <h3>HTML</h3>
  573. <p>It’s surprisingly easy to apply the principles of progressive enhancement to our markup. The most obvious enhancement? Take advantage of <a href="http://diveintohtml5.info/semantics.html#new-elements">new HTML5 elements</a>!</p>
  574. <h4>New HTML5 Elements</h4>
  575. <p>For example, here we have a very basic structure for a blog post:</p>
  576. <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"blog-post"</span><span class="nt">&gt;</span>
  577. <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"blog-post-header"</span><span class="nt">&gt;</span>
  578. <span class="nt">&lt;h1&gt;</span>My Sweet Blog Post<span class="nt">&lt;/h1&gt;</span>
  579. <span class="nt">&lt;/div&gt;</span>
  580. <span class="nt">&lt;p&gt;</span>…<span class="nt">&lt;/p&gt;</span>
  581. <span class="nt">&lt;/div&gt;</span>
  582. </code></pre></div>
  583. <p>With some small changes, we can provide additional semantics to newer browsers and assistive technologies using HTML5’s <a href="http://html5doctor.com/the-article-element/"><code>&lt;article&gt;</code></a> and <a href="http://html5doctor.com/the-header-element/"><code>&lt;header&gt;</code></a> elements.</p>
  584. <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;article</span> <span class="na">class=</span><span class="s">"blog-post"</span><span class="nt">&gt;</span>
  585. <span class="nt">&lt;header</span> <span class="na">class=</span><span class="s">"blog-post-header"</span><span class="nt">&gt;</span>
  586. <span class="nt">&lt;h1&gt;</span>My Sweet Blog Post<span class="nt">&lt;/h1&gt;</span>
  587. <span class="nt">&lt;/header&gt;</span>
  588. <span class="nt">&lt;p&gt;</span>…<span class="nt">&lt;/p&gt;</span>
  589. <span class="nt">&lt;/article&gt;</span>
  590. </code></pre></div>
  591. <p>Nice and easy, right?</p>
  592. <h4>ARIA Roles</h4>
  593. <p>I’ve mentioned accessibility throughout this presentation so far and, as you might’ve guess by now, progressive enhancement and accessibility go hand-in-hand. In our markup, we can improve our website’s accessibility by adding <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA">ARIA</a> landmark roles to particular components with the <code>role</code> attribute.</p>
  594. <p>There are only a handful of <a href="http://www.w3.org/TR/wai-aria/roles#landmark_roles">ARIA landmark roles</a> and they’re easily applied to our markup. Let’s take a look at a basic page structure:</p>
  595. <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;header&gt;</span>
  596. <span class="nt">&lt;h1&gt;</span>My Website’s Header<span class="nt">&lt;/h1&gt;</span>
  597. <span class="nt">&lt;/header&gt;</span>
  598. <span class="nt">&lt;main&gt;</span>
  599. <span class="nt">&lt;p&gt;</span>My website’s content!<span class="nt">&lt;/p&gt;</span>
  600. <span class="nt">&lt;/main&gt;</span>
  601. <span class="nt">&lt;footer&gt;</span>
  602. <span class="nt">&lt;p&gt;</span>Send me a tweet, I’m @jgarber!<span class="nt">&lt;/p&gt;</span>
  603. <span class="nt">&lt;/footer&gt;</span>
  604. </code></pre></div>
  605. <p>In this example, we have a document with a header, main content area, and a footer. As you’ve noticed, I’m using new HTML5 sectioning elements. Adding landmark roles would look like:</p>
  606. <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;header</span> <span class="na">role=</span><span class="s">"banner"</span><span class="nt">&gt;</span>
  607. <span class="nt">&lt;h1&gt;</span>My Website’s Header<span class="nt">&lt;/h1&gt;</span>
  608. <span class="nt">&lt;/header&gt;</span>
  609. <span class="nt">&lt;main</span> <span class="na">role=</span><span class="s">"main"</span><span class="nt">&gt;</span>
  610. <span class="nt">&lt;p&gt;</span>My website’s content!<span class="nt">&lt;/p&gt;</span>
  611. <span class="nt">&lt;/main&gt;</span>
  612. <span class="nt">&lt;footer</span> <span class="na">role=</span><span class="s">"contentinfo"</span><span class="nt">&gt;</span>
  613. <span class="nt">&lt;p&gt;</span>Send me a tweet, I’m @jgarber!<span class="nt">&lt;/p&gt;</span>
  614. <span class="nt">&lt;/footer&gt;</span>
  615. </code></pre></div>
  616. <p>I’ve added three roles: <a href="http://www.w3.org/TR/wai-aria/roles#banner"><code>banner</code></a>, <a href="http://www.w3.org/TR/wai-aria/roles#main"><code>main</code></a>, and <a href="http://www.w3.org/TR/wai-aria/roles#contentinfo"><code>contentinfo</code></a>. The <code>banner</code> role defines a region of site-specific content, <code>main</code> denotes the primary content of a document, and <code>contentinfo</code>, as its name implies, surrounds a block of content containing information about the document.</p>
  617. <p>Notice the duplication on the main content container:</p>
  618. <p><a href="http://html5doctor.com/on-html-belts-and-aria-braces/">There are some rules</a> around when you should and shouldn’t use ARIA roles alongside HTML elements. For the time being, though, I <em>think</em> it’s worth using both HTML5’s structural elements <em>and</em> relevant ARIA roles as not all browsers and assistive technologies recognize newer semantics.</p>
  619. <p>ARIA roles are just the tip of the accessibility iceberg, though. How we can better build accessibility into our markup is a much, much larger discussion and one deserving of more time than I have allotted here today.</p>
  620. <h4>microformats</h4>
  621. <p>This is the last markup-centric enhancement I’ll cover this morning and it’s a personal favorite. <a href="http://microformats.org/">microformats</a> are community-developed patterns for marking up a variety of common data structures: <a href="http://microformats.org/wiki/h-card">people</a>, <a href="http://microformats.org/wiki/h-adr">locations</a>, <a href="http://microformats.org/wiki/h-event">events</a>, <a href="http://microformats.org/wiki/h-entry">blog posts</a>, and <a href="http://microformats.org/wiki/microformats2">much more</a>.</p>
  622. <p>They’re an excellent way to quickly add enhanced semantics to your website’s markup, exposing additional structured content to browsers by way of <a href="http://microformats.org/wiki/browsers">browser extensions, plugins, and bookmarklets</a>.</p>
  623. <p>Implementing microformats is a cinch, too. Let’s use the blog post markup example from earlier:</p>
  624. <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;article</span> <span class="na">class=</span><span class="s">"blog-post"</span><span class="nt">&gt;</span>
  625. <span class="nt">&lt;header</span> <span class="na">class=</span><span class="s">"blog-post-header"</span><span class="nt">&gt;</span>
  626. <span class="nt">&lt;h1&gt;</span>My Sweet Blog Post<span class="nt">&lt;/h1&gt;</span>
  627. <span class="nt">&lt;/header&gt;</span>
  628. <span class="nt">&lt;p&gt;</span>…<span class="nt">&lt;/p&gt;</span>
  629. <span class="nt">&lt;/article&gt;</span>
  630. </code></pre></div>
  631. <p>There’s an established microformat for marking up blog posts known as <a href="http://microformats.org/wiki/h-entry">h-entry</a>, so we can update our markup accordingly:</p>
  632. <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;article</span> <span class="na">class=</span><span class="s">"blog-post h-entry"</span><span class="nt">&gt;</span>
  633. <span class="nt">&lt;header</span> <span class="na">class=</span><span class="s">"blog-post-header"</span><span class="nt">&gt;</span>
  634. <span class="nt">&lt;h1</span> <span class="na">class=</span><span class="s">"p-name"</span><span class="nt">&gt;</span>My Sweet Blog Post<span class="nt">&lt;/h1&gt;</span>
  635. <span class="nt">&lt;/header&gt;</span>
  636. <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"e-content"</span><span class="nt">&gt;</span>
  637. <span class="nt">&lt;p&gt;</span>…<span class="nt">&lt;/p&gt;</span>
  638. <span class="nt">&lt;/div&gt;</span>
  639. <span class="nt">&lt;/article&gt;</span>
  640. </code></pre></div>
  641. <p>In this example, we’ve added the root class value <code>h-entry</code> to the <code>&lt;article&gt;</code> element, indicating that the content contained within is a discrete, syndicatable piece of content. The <code>p-name</code> class value on the heading identifies the entry’s title and an <code>e-content</code> class value wraps the post’s full content.</p>
  642. <p>By <a href="http://microformats.org/wiki/principles">design</a>, microformats utilize the <code>class</code> attribute to declare properties. This <code>class</code>-based implementation—reusing existing building blocks from established standards—sets microformats apart from other, more complicated, Semantic Web technologies like <a href="https://en.wikipedia.org/wiki/Microdata_(HTML)">Microdata</a> and <a href="https://en.wikipedia.org/wiki/RDFa">RDFa</a>.</p>
  643. <p>There’s plenty more to the <a href="http://microformats.org/wiki/h-entry">h-entry spec</a> than what I’ve shown here—structures for adding authors, tags, and publication date—so I encourage you to give the documentation a look.</p>
  644. <h3>CSS</h3>
  645. <p>As we move up the front-end stack to the presentation layer, we’re met with ample opportunity to apply progressive enhancement. And, like our HTML examples, these are generally easier than you’d think.</p>
  646. <h4>Progressively-Enhanced Aesthetics</h4>
  647. <p>Starting with an obvious example, we can use newer CSS features in ways that enhance our interfaces without adversely impacting users. For instance, when applying <a href="https://css-tricks.com/css3-gradients/">CSS gradients</a> to elements, make sure to include a generic background color:</p>
  648. <div class="highlight"><pre><code class="language-css" data-lang="css"><span class="nc">.fancy-button</span> <span class="p">{</span>
  649. <span class="k">background-color</span><span class="o">:</span> <span class="m">#c00</span><span class="p">;</span>
  650. <span class="k">background-image</span><span class="o">:</span> <span class="n">linear</span><span class="o">-</span><span class="n">gradient</span><span class="p">(</span><span class="m">#f00</span><span class="o">,</span> <span class="m">#a00</span><span class="p">);</span>
  651. <span class="k">color</span><span class="o">:</span> <span class="m">#fff</span><span class="p">;</span>
  652. <span class="p">}</span>
  653. </code></pre></div>
  654. <p>By first setting a background color and <em>then</em> declaring a gradient as a background image, we’re providing modern browsers with an aesthetically-pleasing gradient while also supplying a solid background color to browsers lacking support for CSS-generated gradients. We’ve also made our design more resilient by ensuring that the button’s white text will never accidentally appear on a white background, rendering the button inaccessible.</p>
  655. <p>Progressive enhancement and accessibility: <em>two great tastes that taste great together</em>. The <a href="https://en.wikipedia.org/wiki/Reese%27s_Peanut_Butter_Cups">Reese’s Peanut Butter Cups</a> of the Web.</p>
  656. <p>You can apply this same technique to your use of other aesthetic properties: <code>border-radius</code>, <a href="https://css-tricks.com/rgba-browser-support/">RGBA colors with fallbacks</a>, and <a href="http://www.css3.info/preview/multiple-backgrounds/">multiple background images</a>.</p>
  657. <h4>Media Queries</h4>
  658. <p>I’ve mentioned already this notion of starting small: setting a baseline and enhancing upward from there. <a href="https://bryanrieger.com/">Bryan Rieger</a>, in his presentation “<a href="http://www.slideshare.net/bryanrieger/rethinking-the-mobile-web-by-yiibu">Rethinking the Mobile Web</a>,” noted that:</p>
  659. <blockquote>
  660. <p>The absence of support for @media queries is in fact the first @media query.</p>
  661. </blockquote>
  662. <p>If we take that thinking, combine it with a <a href="http://abookapart.com/products/mobile-first">mobile first</a> structuring of our CSS, we can apply progressive enhancement by using <code>min-width</code>-based media queries. Each <code>min-width</code>-based media query would be, in effect, an enhancement of the layout based on increasing viewport real estate.</p>
  663. <p>It’s important to note here that this <em>only</em> has to do with layout and not browser or device capabilities. While width- and height-based media queries are the easiest to work with, there are <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Media_queries">a number of features</a> that we can progressively hook in to: <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Media_queries#color">color</a>, <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Media_queries#aspect-ratio">aspect ratio</a>, and <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Media_queries#orientation">orientation</a>, for instance. As with everything progressive enhancement-related, if you start from a solid foundation, you’re free to enhance upward as much as possible.</p>
  664. <h4>Advanced Layout with Flexbox</h4>
  665. <p>I’ll get this out of the way: <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes">Flexbox</a> is awesome and terrifying. <a href="http://www.lemondesign.co/">Chris</a> has a presentation on the subject later today, so I’ll keep this example pretty high-level and introductory.</p>
  666. <p>While browser support for flexbox is <a href="http://caniuse.com/#search=flexbox">surprisingly good</a>, you may consider treating its use as an enhancement. I’ve created <a href="http://codepen.io/jgarber/pen/pJpdYx">a basic example</a> showing how you can easily reorder content using but a tiny fraction of flexbox’s power.</p>
  667. <p>As you can see if you pull up <a href="http://codepen.io/jgarber/pen/pJpdYx">the demo on Codepen</a>, there’s an advertisement for <a href="http://www.amazon.com/dp/1430238763/?tag=sixtwothree-20">a <em>fantastic</em> book about HTML and CSS</a>—one which I encourage you all to rush out and purchase—at the bottom of the page. At viewports wider than 900 pixels, the advertisement is moved to the top of the page using a smattering of flexbox-related properties:</p>
  668. <div class="highlight"><pre><code class="language-css" data-lang="css"><span class="k">@media</span> <span class="o">(</span><span class="nt">min-width</span><span class="o">:</span> <span class="nt">50em</span><span class="o">)</span> <span class="p">{</span>
  669. <span class="nc">.main</span> <span class="p">{</span>
  670. <span class="k">display</span><span class="o">:</span> <span class="n">flex</span><span class="p">;</span>
  671. <span class="n">flex</span><span class="o">-</span><span class="k">direction</span><span class="o">:</span> <span class="n">column</span><span class="p">;</span>
  672. <span class="p">}</span>
  673. <span class="nc">.intro</span><span class="o">,</span>
  674. <span class="nc">.social</span> <span class="p">{</span>
  675. <span class="n">order</span><span class="o">:</span> <span class="m">1</span><span class="p">;</span>
  676. <span class="p">}</span>
  677. <span class="nc">.advert</span> <span class="p">{</span>
  678. <span class="n">order</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span>
  679. <span class="p">}</span>
  680. <span class="p">}</span>
  681. </code></pre></div>
  682. <p>It’s a silly example and a non-critical layout change, but it succinctly demonstrates how a small application of a tool like flexbox can enhance an existing layout.</p>
  683. <h3>JavaScript</h3>
  684. <p>Here it is, the elephant in the room: <em>JavaScript</em>. The final layer in the front-end Web technology stack.</p>
  685. <p>I want you to know that I love JavaScript. I don’t always love the things we do with it, and while it’s a hot mess of a language, it’s <em>our</em> hot mess of a language.</p>
  686. <p>There are so many great progressively-enhanced JavaScript examples out there. I thought a lot about what to show you here today and narrowed it down to a couple of techniques and a pretty cool example. Let’s start with the techniques.</p>
  687. <h4>Object Detection</h4>
  688. <p>Given the utter insanity of <a href="http://useragentstring.com/pages/All/">the browser user agent string</a> and the futility of attempting to match against it, you should lean heavily on <a href="http://www.quirksmode.org/js/support.html">object detection</a> to determine a browser’s support for JavaScript features. While testing for features varies, at a basic level you’ll wrap your code in a conditional like so:</p>
  689. <div class="highlight"><pre><code class="language-js" data-lang="js"><span class="k">if</span> <span class="p">(</span><span class="s1">'addEventListener'</span> <span class="k">in</span> <span class="nb">window</span><span class="p">)</span> <span class="p">{</span>
  690. <span class="c1">// Your code using addEventListener goes here…</span>
  691. <span class="p">}</span>
  692. </code></pre></div>
  693. <p>The code within this conditional <em>only</em> executes in browsers that respond affirmatively to the question: “Does your <code>window</code> object include a method named <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener"><code>addEventListener</code></a>?” This particular object detection is often used to keep versions of Internet Explorer prior to 9 from executing the JavaScript within.</p>
  694. <h4>Cutting the Mustard</h4>
  695. <p>The BBC, as part of their <a href="http://responsivenews.co.uk/">responsive news redesign project</a>, took object detection a step further, combining several key feature detections to put into action their browser support matrix. They dubbed their technique “<a href="http://responsivenews.co.uk/post/18948466399/cutting-the-mustard">Cutting the Mustard</a>.”</p>
  696. <div class="highlight"><pre><code class="language-js" data-lang="js"><span class="k">if</span> <span class="p">(</span><span class="s1">'querySelector'</span> <span class="k">in</span> <span class="nb">document</span>
  697. <span class="o">&amp;&amp;</span> <span class="s1">'localStorage'</span> <span class="k">in</span> <span class="nb">window</span>
  698. <span class="o">&amp;&amp;</span> <span class="s1">'addEventListener'</span> <span class="k">in</span> <span class="nb">window</span><span class="p">)</span> <span class="p">{</span>
  699. <span class="c1">// Bootstrap the JavaScript application…</span>
  700. <span class="p">}</span>
  701. </code></pre></div>
  702. <p>The team at the BBC grouped browsers into “HTML4 browsers” and “HTML5 browsers” and used these object detections to filter browsers based on their capabilities rather than how browsers identify themselves. “HTML4 browsers” receive a perfectly usable website while “HTML5 browsers” run the full-featured, progressively-enhanced <em>experience</em>.</p>
  703. <h4>Working with <code>&lt;datalist&gt;</code></h4>
  704. <p>I’ve borrowed this final example from a <a href="https://adactio.com/journal/4272">2011 blog post by Jeremy Keith</a> and more recently shared by <a href="http://www.aaron-gustafson.com/">Aaron Gustafson</a> in his presentation “<a href="http://www.slideshare.net/AaronGustafson/falling-in-love-with-forms-microsoft-edge-web-summit-2015">Falling in Love with Forms</a>.” I’ve made a couple of enhancements and posted <a href="http://codepen.io/jgarber/pen/OVzzJz">a demo on Codepen</a>.</p>
  705. <p>The <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist"><code>&lt;datalist&gt;</code> element</a> behaves similarly to the familiar <code>&lt;select&gt;</code> form control, accepting as children a series of <code>&lt;option&gt;</code> elements:</p>
  706. <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"state"</span> <span class="na">id=</span><span class="s">"state-label"</span><span class="nt">&gt;</span>State<span class="nt">&lt;/label&gt;</span>
  707. <span class="nt">&lt;datalist</span> <span class="na">id=</span><span class="s">"states"</span><span class="nt">&gt;</span>
  708. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Alabama"</span><span class="nt">&gt;</span>Alabama<span class="nt">&lt;/option&gt;</span>
  709. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Alaska"</span><span class="nt">&gt;</span>Alaska<span class="nt">&lt;/option&gt;</span>
  710. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Arizona"</span><span class="nt">&gt;</span>Arizona<span class="nt">&lt;/option&gt;</span>
  711. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Arkansas"</span><span class="nt">&gt;</span>Arkansas<span class="nt">&lt;/option&gt;</span>
  712. <span class="nt">&lt;/datalist&gt;</span>
  713. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">id=</span><span class="s">"state"</span> <span class="na">name=</span><span class="s">"state"</span> <span class="na">list=</span><span class="s">"states"</span><span class="nt">&gt;</span>
  714. </code></pre></div>
  715. <p>When associated with another <code>&lt;input&gt;</code> element (via the <code>list</code> attribute), <code>&lt;datalist&gt;</code> acts as a browser-native auto-complete field. No JavaScript required!</p>
  716. <p>Jeremy took his demo a step further, wrapping those <code>&lt;option&gt;</code> elements in a <code>&lt;select&gt;</code>:</p>
  717. <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"state"</span> <span class="na">id=</span><span class="s">"state-label"</span><span class="nt">&gt;</span>State<span class="nt">&lt;/label&gt;</span>
  718. <span class="nt">&lt;datalist</span> <span class="na">id=</span><span class="s">"states"</span><span class="nt">&gt;</span>
  719. <span class="nt">&lt;select&gt;</span>
  720. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Alabama"</span><span class="nt">&gt;</span>Alabama<span class="nt">&lt;/option&gt;</span>
  721. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Alaska"</span><span class="nt">&gt;</span>Alaska<span class="nt">&lt;/option&gt;</span>
  722. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Arizona"</span><span class="nt">&gt;</span>Arizona<span class="nt">&lt;/option&gt;</span>
  723. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Arkansas"</span><span class="nt">&gt;</span>Arkansas<span class="nt">&lt;/option&gt;</span>
  724. <span class="nt">&lt;/select&gt;</span>
  725. <span class="nt">&lt;/datalist&gt;</span>
  726. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">id=</span><span class="s">"state"</span> <span class="na">name=</span><span class="s">"state"</span> <span class="na">list=</span><span class="s">"states"</span><span class="nt">&gt;</span>
  727. </code></pre></div>
  728. <p>Browsers that are <code>&lt;datalist&gt;</code>-aware ignore any content <em>other than</em> <code>&lt;option&gt;</code> elements. Browsers lacking support for <code>&lt;datalist&gt;</code> ignore the containing element and render a standard <code>&lt;select&gt;</code> input.</p>
  729. <p>This works thanks to the manner in which browsers parse HTML documents. Rather than grinding to a halt and stopping page rendering, Web browsers simply ignore elements they don’t recognize and carry on rendering. The essence of progressive enhancement is baked into the design of HTML!</p>
  730. <p>Jumping ahead, the completed example’s markup looks like:</p>
  731. <div class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt">&lt;form&gt;</span>
  732. <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">"state"</span> <span class="na">id=</span><span class="s">"state-label"</span><span class="nt">&gt;</span>State<span class="nt">&lt;/label&gt;</span>
  733. <span class="nt">&lt;datalist</span> <span class="na">id=</span><span class="s">"states"</span><span class="nt">&gt;</span>
  734. <span class="nt">&lt;select</span> <span class="na">name=</span><span class="s">"state"</span> <span class="na">id=</span><span class="s">"state-select"</span> <span class="na">aria-labelledby=</span><span class="s">"state-label"</span><span class="nt">&gt;</span>
  735. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Alabama"</span><span class="nt">&gt;</span>Alabama<span class="nt">&lt;/option&gt;</span>
  736. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Alaska"</span><span class="nt">&gt;</span>Alaska<span class="nt">&lt;/option&gt;</span>
  737. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Arizona"</span><span class="nt">&gt;</span>Arizona<span class="nt">&lt;/option&gt;</span>
  738. <span class="nt">&lt;option</span> <span class="na">value=</span><span class="s">"Arkansas"</span><span class="nt">&gt;</span>Arkansas<span class="nt">&lt;/option&gt;</span>
  739. <span class="nt">&lt;/select&gt;</span>
  740. <span class="nt">&lt;p</span> <span class="na">id=</span><span class="s">"other-label"</span><span class="nt">&gt;</span>If other, please specify:<span class="nt">&lt;/p&gt;</span>
  741. <span class="nt">&lt;/datalist&gt;</span>
  742. <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">id=</span><span class="s">"state"</span> <span class="na">name=</span><span class="s">"state"</span> <span class="na">list=</span><span class="s">"states"</span><span class="nt">&gt;</span>
  743. <span class="nt">&lt;/form&gt;</span>
  744. </code></pre></div>
  745. <p>In addition to the aforementioned <code>&lt;select&gt;</code> element, we’ve nested an explanatory paragraph within the <code>&lt;datalist&gt;</code>. Like the <code>&lt;select&gt;</code>, this element will <em>only</em> show in browsers lacking native <code>&lt;datalist&gt;</code> support.</p>
  746. <p>This is a pretty solid pattern, but it irked me that, in browsers lacking support for <code>&lt;datalist&gt;</code>, the <code>&lt;label&gt;</code> wasn’t associated with the <code>&lt;select&gt;</code> and a paragraph acted as the text input’s label.</p>
  747. <p>A little bit of JavaScript solved the problem:</p>
  748. <div class="highlight"><pre><code class="language-js" data-lang="js"><span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="s1">'list'</span> <span class="k">in</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'input'</span><span class="p">)))</span> <span class="p">{</span>
  749. <span class="kd">var</span> <span class="nx">stateLabel</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'state-label'</span><span class="p">),</span>
  750. <span class="nx">otherLabel</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'other-label'</span><span class="p">);</span>
  751. <span class="nx">stateLabel</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="s1">'for'</span><span class="p">,</span> <span class="s1">'state-select'</span><span class="p">);</span>
  752. <span class="nx">otherLabel</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="s1">'&lt;label for="state"&gt;'</span> <span class="o">+</span> <span class="nx">otherLabel</span><span class="p">.</span><span class="nx">innerText</span> <span class="o">+</span> <span class="s1">'&lt;/label&gt;'</span><span class="p">;</span>
  753. <span class="p">}</span>
  754. </code></pre></div>
  755. <p>With this code, we’ve associated the “State” label with the <code>&lt;select&gt;</code> element and swapped out the explanatory paragraph with a properly-associated <code>&lt;label&gt;</code> element. All it took was a bit of object detection and some simple DOM manipulation.</p>
  756. <h2>In Conclusion…</h2>
  757. <p>We’ve covered a lot of ground this morning. We’ve looked back at the history of progressive enhancement, evaluated its relevance in our modern design process, and walked through useful applications of the technique in all layers of the front-end Web stack.</p>
  758. <p>I’ll leave you with a final thought: Much like the Web, progressive enhancement exists on a <a href="https://adactio.com/journal/6692">continuum</a>. It’s not a binary decision: “You either build with progressive enhancement or you don’t.” It’s entirely possible to introduce progressive enhancement into your design process in small ways at first. Remember: <em>define a baseline and enhance from there</em>.</p>
  759. <p>Christopher and Ari have put together a tremendous lineup here at CSS Summit and it’s been an honor kicking things off with you this morning. Over the next three days, as you learn about some awesome new design and development tools and techniques—SVG, Sass, and Angular—think about how you can best apply those tools and techniques in a <a href="https://medium.com/@jjaybrown98/it-s-time-to-progress-702e0779df3a">progressive</a>, <a href="https://twitter.com/scottjehl/status/615580565404839936">resilient</a>, <a href="http://futurefriendlyweb.com/">future-friendly</a> fashion.</p>
  760. <p>Thank you!</p>
  761. </article>
  762. </section>
  763. <nav id="jumpto">
  764. <p>
  765. <a href="/david/blog/">Accueil du blog</a> |
  766. <a href="http://sixtwothree.org/posts/designing-with-progressive-enhancement">Source originale</a> |
  767. <a href="/david/stream/2019/">Accueil du flux</a>
  768. </p>
  769. </nav>
  770. <footer>
  771. <div>
  772. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  773. <p>
  774. Bonjour/Hi!
  775. 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>
  776. 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>).
  777. </p>
  778. <p>
  779. 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>.
  780. </p>
  781. <p>
  782. Voici quelques articles choisis :
  783. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  784. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  785. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  786. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  787. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  788. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  789. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  790. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  791. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  792. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  793. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  794. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  795. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  796. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  797. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  798. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  799. </p>
  800. <p>
  801. 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>.
  802. </p>
  803. <p>
  804. Je ne traque pas ta navigation mais mon
  805. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  806. conserve des logs d’accès.
  807. </p>
  808. </div>
  809. </footer>
  810. <script type="text/javascript">
  811. ;(_ => {
  812. const jumper = document.getElementById('jumper')
  813. jumper.addEventListener('click', e => {
  814. e.preventDefault()
  815. const anchor = e.target.getAttribute('href')
  816. const targetEl = document.getElementById(anchor.substring(1))
  817. targetEl.scrollIntoView({behavior: 'smooth'})
  818. })
  819. })()
  820. </script>