A place to cache linked articles (think custom and personal wayback machine)
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  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>Le web mobile et la performance (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.24joursdeweb.fr/2014/le-web-mobile-et-la-performance/">
  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. Le web mobile et la performance (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.24joursdeweb.fr/2014/le-web-mobile-et-la-performance/">Source originale du contenu</a></h3>
  445. <p>Tout site sortant aujourd’hui doit avoir été pensé avec des contraintes mobiles, et utiliser des techniques d’amélioration progressive pour délivrer rapidement les fonctionnalités sur toutes plateformes.</p>
  446. <p>En attendant cette conclusion, nous commencerons par essayer de connaître notre utilisateur, puis nous verrons les tactiques et stratégies propres au mobile.</p>
  447. <h2>Où est le problème ?</h2>
  448. <p>La <abbr title="Téléphonie 4e génération">4G</abbr> a débarqué, des mobiles à 8 processeurs se vendent, et la plupart des gens utilisent leur mobile depuis chez eux : en Wifi ! À priori le métier de spécialiste performance web serait donc mort et vous me trouverez en train de parler <abbr title="Hypertext markup language, langage de marquage hypertexte">HTML</abbr>5 à mes chèvres dans le Larzac, merci au revoir. À moins que…</p>
  449. <h3>L’utilisation</h3>
  450. <p>La « situation de mobilité » est-elle un mythe ? L’expérience et une <a href="http://services.google.com/fh/files/misc/omp-2013-fr-local.pdf">étude Google</a> montrent clairement que les ¾ des gens utilisent majoritairement leur mobile depuis le confort de leur canapé / lit / lunette, derrière le wifi familial. 15% de ces mêmes Français ont même la fibre.</p>
  451. <p>Le temps passé dans une situation confortable est majoritaire mais cela est justement dû à <strong>la réalité de la situation de mobilité : cela doit être très rapide</strong>. Dans un magasin, les gens vérifient les prix des concurrents sur le Web : si votre page ne s’affiche pas en plus de quelques secondes, vous avez perdu la guerre des prix dès la première bataille (afficher le prix) ! Dans la rue, l’utilisateur va vouloir connaître les horaires de cinéma ou les restaurants du coin : si c’est votre coeur de métier vous n’aurez toutes vos chances qu’en affichant rapidement l’information demandée. Dans les situations d’attente, les gens dégainent les téléphones pour consulter réseaux sociaux et mails : si votre page a la chance d’être dans leur fil d’information, il va falloir afficher la promesse très rapidement (un article sur les félins à travers les âges, une vidéo de chats, le lolcat du jour…). Enfin la préparation d’achat se fait fréquemment sur mobile (plus discret dans l’open space, à portée de main lors des pauses clope voire au feu rouge), même si la finalisation de la commande se fait encore majoritairement sur l’ordinateur du foyer voire sur tablette.</p>
  452. <p>Tout cela ne compte que pour quelques secondes dans les statistiques mais les utilisateurs se souviendront de votre marque de manière très positive si vous avez résolu leur problème rapidement.</p>
  453. <h3>La connexion</h3>
  454. <p>Les données de cette année montrent clairement une amélioration des débits <abbr title="Téléphonie de 3e génération">3G</abbr> (6 <abbr title="Megabytes">Mb</abbr>/<abbr title="seconde">s</abbr> en moyenne selon Akamai) et la <abbr>4G</abbr> à la française envoie du poney au galop (21-32 <abbr>Mb</abbr>/<abbr>s</abbr> <strong>constatés</strong> selon <a href="http://www.degrouptest.com/publications/14/Barometre-Internet-mobiles/4">Degrouptest</a>, pointes de 34 <abbr>Mb</abbr>/<abbr>s</abbr> selon <a href="http://www.akamai.com/dl/whitepapers/akamai-soti-a4-q214.pdf">Akamai</a>).</p>
  455. <p>Mais si vous êtes utilisateur régulier du mobile, vous devinez la vérité derrière ces excellentes moyennes : même avec une puce et un abonnement 4G vous ne chargez parfois pas du tout les pages et vous esquissez un sourire triomphant lorsqu’un site web se charge aussi bien qu’au bureau. C’est parce que l’ennemi numéro 1 du chargement de page web reste la <strong>latence réseau</strong>, et même sur une <abbr>4G</abbr> de bonne qualité les latences constatés par Degrouptest sont entre 50 et 100 <abbr title="millisecondes">ms</abbr>.</p>
  456. <p>Concrètement :</p>
  457. <ul>
  458. <li>ligne du haut : une <abbr>4G</abbr> de cadre parisien avec <strong>20 <abbr>Mb</abbr>/<abbr>s</abbr> de débit</strong> mais 200 <abbr>ms</abbr> de latence (les murs de Paris sont épais),</li>
  459. <li>ligne du bas : l’<abbr title="haut débit asymétrique">ADSL</abbr> de la mamie du Cantal avec <strong>2 <abbr>Mb</abbr>/<abbr>s</abbr></strong> et 20 <abbr>ms</abbr> de latence (oui son <abbr title="nœud de raccordement local au réseau">DSLAM</abbr> est proche).</li>
  460. </ul>
  461. <div id="attachment_728" class="wp-caption aligncenter"><a href="http://media.24joursdeweb.fr/2014/12/debit-vs-latence.jpg"><img class="size-full wp-image-728" src="http://media.24joursdeweb.fr/2014/12/debit-vs-latence.jpg" alt="La mamie du Cantal gagne (et avec un ping pareil, elle frag aussi de l’ado à tout va). "/></a><p class="wp-caption-text">La mamie du Cantal gagne<br/>(et avec un ping pareil, elle frag aussi de l’ado à tout va).</p></div>
  462. <p>L’affichage via la connexion à 2 <abbr>Mb</abbr>/<abbr>s</abbr> commence 1 seconde plus tôt, <strong>le formulaire est utilisable 2 secondes plus tôt</strong> et le site au complet se charge 5 secondes plus vite.</p>
  463. <p>Ajoutez à cela que les réseaux <abbr>3G</abbr> des grandes villes sont saturées, et qu’en fonction de l’endroit, de l’heure de la journée, du jour de la semaine et de la position de votre doigt sur le mobile, les performances ne sont pas du tout les mêmes. Dans certains cas pas un octet ne passe.</p>
  464. <p>Tout ça pour dire que les grands principes de la <strong>limitation du nombre de requêtes</strong> d’abord, puis <strong>du poids du contenu</strong> restent valables.</p>
  465. <h3>L’utilisateur</h3>
  466. <p>Tout le monde n’investit pas dans un bidule avec 8 processeurs et 3 <abbr title="Giga-octets">Go</abbr> de <abbr title="mémoire vive">RAM</abbr>, par contre les utilisateurs mobiles sont clairement habitués à ce que les interfaces soient fluides et réactives, et même à ce qu’on leur affiche des données en l’absence de réseau. Ajoutez à cela le fait que l’on sert fréquemment des sites mobiles minimalistes et vous comprendrez que l’utilisateur a bien du mal à accepter que les sites qu’il consulte mettent du temps à apparaître, ou laggent lorsqu’il scrolle.</p>
  467. <p>Du coup un tombereau d’études utilisateur ou d’analyse statistiques démontrent ce que l’on pressent déjà : le temps coûte cher.</p>
  468. <p>Absolument tous les indicateurs marketing sont touchés :</p>
  469. <ul>
  470. <li>le taux de rebond (<a href="http://radar.oreilly.com/2014/01/web-performance-is-user-experience.html" hreflang="en">Etsy</a> : ajouter 160<abbr title="Kilo-octets">Ko</abbr> d’images = +12% de taux de rebond),</li>
  471. <li>le taux de clic (<a href="http://doubleclickadvertisers.blogspot.fr/2011/06/cranking-up-speed-of-dfa-leads-to.html" hreflang="en">DoubleClick</a> : supprimer 1 redirection = +12% de taux de clic),</li>
  472. <li>l’abandon pur et simple de la page (<a href="http://www.radware.com/PleaseRegister.aspx?returnUrl=6442454446&amp;ref=prodoverview" hreflang="en">Radware</a> : 60% d’abandon après 4 secondes de page blanche),</li>
  473. <li>l’abandon du processus d’achat (<a href="http://minus.com/msM8y8nyh#1e" hreflang="en">Wallmart</a> : -50% de conversion par seconde),</li>
  474. <li>l’abandon du visionnage (<a href="http://people.cs.umass.edu/~ramesh/Site/HOME_files/imc208-krishnan.pdf" hreflang="en">Akamai</a> : -6% de vidéo vue par seconde d’attente),</li>
  475. <li>la <a href="http://calendar.perfplanet.com/2013/slow-pages-damage-perception/" hreflang="en">perception négative</a> de la marque.</li>
  476. </ul>
  477. <p>Le côté amusant de l’histoire : si vous surveillez vos taux de rebond sur mobile en vous disant « ça va encore, » dites-vous que les statistiques sont en dessous de la réalité puisque dans les cas des pages blanches, il est probable que la requête remontant sur le serveur qui comptabilise les hits ne soit jamais partie.</p>
  478. <h3>Nos sites !</h3>
  479. <p>Étant donné que les grands chefs regardent les sites sur des mobiles qui valent <a href="http://store.apple.com/fr/buy-iphone/iphone6/%C3%A9cran-5,5%C2%A0pouces-128go-or-d%C3%A9verrouill%C3%A9">le prix de ma première voiture</a>, via le wifi de la boite et qu’ils s'arrêtent à la homepage, forcément il y a un peu de laisser-aller sur les sites, y compris dédiés mobile. Le poids des sites dits dédiés mobile (mDot) <a href="http://www.webperformancetoday.com/2014/05/28/mobile-optimized-pages-bigger/" hreflang="en">augmente régulièrement</a>. La bonne idée d’avoir un site mobile dépouillé et ergonomiquement efficace s’efface pour laisser la place aux mauvaises habitudes des sites <span lang="en">desktop</span> : on met tout sur la <span lang="en">HomePage</span>, et on rajoute un maximum d’information sur les pages intérieures.</p>
  480. <p>Le <abbr title="responsive web design, design web réactif">RWD</abbr> devient la norme pour les refontes graphiques, mais rarement le « <i lang="en">mobile first</i> » : on se retrouve donc avec des spécifications planifiant 5 <i lang="en">breakpoints</i>, devant afficher des images « retina » tout en gérant <abbr title="Internet Explorer">IE</abbr> 6 (oui cette spécification existe vraiment). Le poids des sites en général a doublé en 3 ans et grâce au <abbr>RWD</abbr> on demande maintenant d’afficher des sites de 2 <abbr>Mo</abbr> et 100 requêtes sur mobile. Ça finirait par arriver si l’utilisateur était encore là pour le voir.</p>
  481. <p>Sur ces même sites <i lang="en">cross-device</i>, votre département marketing a bien sûr opté pour la totale :</p>
  482. <ul>
  483. <li>de l’<i lang="en">analytics</i> (augmentation du nombre de requêtes),</li>
  484. <li>des publicités (poids, temps d’exécution, requêtes),</li>
  485. <li>de l’<i lang="en">A/B Testing</i> (retardement <strong>volontaire</strong> de l’affichage, temps d’exécution),</li>
  486. <li>des boutons sociaux (le moindre bouton G+ rajoute 100 <abbr>Ko</abbr> et des dizaines de requêtes)</li>
  487. </ul>
  488. <p>Et les tendances webdesign du moment ne sont plus aux coins arrondis qu’on aurait pu régler en CSS3 en pouffant, mais aux polices de caractère (blocage temporaire du rendu, texte invisible, poids), aux « <i lang="en">hero images</i> » (l’image principale en 1200x800, <i lang="en">retina-ready</i>, cordialement) ou pire aux <i lang="en">slideshows</i> (<a href="http://www.doisjeutiliser.fr/unCarrousel/">pourtant une mauvaise idée</a>) qui peuvent charger de grosses images invisibles.</p>
  489. <p><a href="http://media.24joursdeweb.fr/2014/12/chargement-pmvc.jpg"><img class="alignnone wp-image-810 size-large" src="http://media.24joursdeweb.fr/2014/12/chargement-pmvc-860x82.jpg" alt="Chargement du site Promovacances"/></a></p>
  490. <div id="attachment_818" class="wp-caption alignnone"><a href="http://media.24joursdeweb.fr/2014/12/lequipe.jpg"><img class="wp-image-818 size-large" src="http://media.24joursdeweb.fr/2014/12/lequipe-860x115.jpg" alt="Chargement du site LEquipe.fr"/></a><p class="wp-caption-text">Veuillez patienter, un opérateur va prendre votre appel</p></div>
  491. <h2>L’arsenal technique</h2>
  492. <p>Le problème est donc bien réel et s’inscrit dans la durée : les utilisateurs seront de plus en plus exigeants, les sites de plus en plus gourmands, et la latence des réseaux mobiles ne fera pas de grands progrès. Ce qui tombe bien c’est qu’on peut y faire quelque chose.</p>
  493. <h3>Le chemin critique</h3>
  494. <p>D’accord le chemin critique est <a href="https://developer.yahoo.com/performance/rules.html" hreflang="en">connu depuis 2006</a>, désolé de redire les choses mais sur mobile il ne faut surtout pas se rater sur les bases. Prenons un cas un peu extrême (iOS &lt; 8, grosse latence, débit correct).</p>
  495. <div id="attachment_816" class="wp-caption alignnone"><a href="http://media.24joursdeweb.fr/2014/12/lemonde-deroule.jpg"><img class="wp-image-816 size-large" src="http://media.24joursdeweb.fr/2014/12/lemonde-deroule-860x128.jpg" alt="Chargement du site LeMonde.fr"/></a><p class="wp-caption-text">La fameuse angoisse de la page blanche (1 case = 1 seconde)</p></div>
  496. <p>Pourquoi 9 secondes avant le premier pixel, et 10 avant de voir quelque chose d’utile ? Regardons l’action au ralenti, avec la trace réseau suivante.</p>
  497. <div id="attachment_733" class="wp-caption aligncenter"><a href="http://media.24joursdeweb.fr/2014/12/lemonde-reseau.jpg"><img class="size-full wp-image-733" src="http://media.24joursdeweb.fr/2014/12/lemonde-reseau.jpg" alt="Vue réseau sur LeMonde.fr"/></a><p class="wp-caption-text">Le trait vert est le premier Graal.</p></div>
  498. <p>Vous pouvez considérer que tout ce qui est à gauche de la ligne verticale verte (l’affichage du premier pixel) est sur le chemin critique. Un effort d’optimisation est déjà en place car les <abbr title="Cascading stylesheets, feuilles de styles">CSS</abbr> sont déjà groupés et <strong>les JavaScript sont chargés de manière asynchrone</strong>. Sauf que c’est à cause de cette dernière optimisation que le site est ralenti : ce qui marche sur navigateur de bureau n’est pas forcément vrai sur mobile.</p>
  499. <p><strong>Déplacer les JavaScript en bas de page aurait aussi été une mauvaise idée</strong>, grâce à notre ami Safari iOS qui refuse d’afficher quoi que ce soit tant que ces fichiers ne sont pas là. Ici comme sur la plupart des sites, on gagnerait plusieurs secondes en chargeant de manière classique les <strong>fichiers <abbr title="Javascript">JS</abbr> agglomérés, en haut de page</strong>.</p>
  500. <p>Pour résumer :</p>
  501. <ul>
  502. <li>testez sur les vraies plate-formes avant d’appliquer des recettes qui marchent ailleurs.</li>
  503. <li>choisissez la bonne stratégie de chargement des <abbr>JS</abbr> : de manière classique en haut de page, ça marche souvent très bien</li>
  504. <li>les recettes classiques doivent être appliquées : groupement en 6 requêtes maximum des <abbr>HTML</abbr> / <abbr>CSS</abbr> / <abbr>JS</abbr></li>
  505. <li>minification et gzip des ressources de type texte</li>
  506. </ul>
  507. <h3>La police</h3>
  508. <p>Les <i lang="en">fonts</i> sont la grosse <a href="http://httparchive.org/trends.php?s=All&amp;minlabel=Nov+15+2011&amp;maxlabel=Nov+15+2014#perFonts" hreflang="en">tendance 2013</a> et sont maintenant présentes sur la moitié des sites. C’est joli tout plein mais ça retarde encore le moment où l’utilisateur peut accéder au contenu. En fait il y a 3 états possibles pour l’affichage de votre texte.</p>
  509. <div id="attachment_813" class="wp-caption alignnone"><a href="http://media.24joursdeweb.fr/2014/12/deroule-font-lequipe.jpg"><img class="wp-image-813 size-large" src="http://media.24joursdeweb.fr/2014/12/deroule-font-lequipe-860x364.jpg" alt="Chargement des polices sur LEquipe.fr"/></a><p class="wp-caption-text">Les phases possibles pour un chargement de police</p></div>
  510. <p><strong>Phase 1</strong> : pas de bras, pas de chocolat, le texte est là mais masqué. Un peu dommage pour un site essentiellement basé sur le contenu textuel.</p>
  511. <p><strong>Phase 2</strong> : le navigateur en a marre et vous sauve la mise en affichant le texte. Mal stylé mais fonctionnel.</p>
  512. <p><strong>Phase 3</strong> : tout va bien, le site est quasiment comme sur la maquette. On espère que l’utilisateur regarde encore.</p>
  513. <h4>Savoir coder</h4>
  514. <p>L’art ancestral de <strong>l’amélioration progressive </strong>doit aussi s’appliquer aux polices : la phase 2 n’existe que si vous avez bien pensé à préciser une police système de fallback. Dans le cas contraire <strong>l’utilisateur regardera plus longtemps le site sans rien pouvoir y lire</strong>.</p>
  515. <p>Pour raccourcir voire éliminer la phase sans tete lisible, il s’agit de faire un travail approfondi de coopération intégrateur / designer : 1 ou 2 polices maximum, de moins de 40<abbr>Ko</abbr>, testées sur toutes les plate-formes (mention spéciale à Chrome sur XP)</p>
  516. <p>Ensuite vient le travail d’optimisation :</p>
  517. <ul>
  518. <li>la <i lang="en">font</i> critique doit avoir sa<strong> place dans vos 6 premières requêtes</strong>.</li>
  519. <li>chargement asynchrone des polices secondaires (variantes, titres invisibles, police d'icônes…).</li>
  520. </ul>
  521. <p>Il y a des techniques plus avancées permettant de toujours afficher du texte même si ça n’est pas la <i lang="en">font</i> finale, ce qui ne plaît pas toujours. Vous pouvez également utiliser les <code>data:uri</code> et un encodage base64 de votre police directement dans le <abbr>CSS</abbr>, mais vous l’alourdissez du poids de la police.</p>
  522. <p>Testez.</p>
  523. <h3>Se méfier des autres</h3>
  524. <p>Je vois encore des développeurs inclure des scripts depuis des serveurs qui ne leur appartiennent pas. Il s’agit le plus souvent d’une version plus ou moins à jour de jQuery ou de <abbr>HTML</abbr>5 shim. Les bénéfices sont nuls, et le risque énorme. Vous pensiez sérieusement que les serveurs des grands de ce monde sont disponibles 100% du temps ? Ou qu’ils répondent toujours plus vite que vos propres serveurs ?</p>
  525. <p>Non.</p>
  526. <div id="attachment_741" class="wp-caption aligncenter"><a href="http://media.24joursdeweb.fr/2014/12/spof-facebook.jpg"><img class="size-full wp-image-741" src="http://media.24joursdeweb.fr/2014/12/spof-facebook.jpg" alt="Single Point Of Failure Facebook"/></a><p class="wp-caption-text"><abbr title="Single point of failure, point unique d'échec">SPOF</abbr> ? pouf.</p></div>
  527. <p>Sur ces graphes, on voit les temps d’affichage de sites majeurs (ligne du haut) <strong>augmenter de 20 secondes</strong> pendant le temps où les serveurs Facebook sont moins disponibles. Pour faire le point des dangers page par page, je vous conseille d’utiliser <a href="https://chrome.google.com/webstore/detail/spof-o-matic/plikhggfbplemddobondkeogomgoodeg" hreflang="en">SPOF-O-Matic</a>.</p>
  528. <p>Sur mobile la résolution du nouveau nom de domaine est particulièrement pénible à cause de la latence. Les stratégies sont relativement simples, en fonction de la nature de la ressource :</p>
  529. <ul>
  530. <li><i lang="en">widget</i> / bouton : utiliser la version asynchrone pour ne pas dépendre des autres,</li>
  531. <li><i lang="en">widget</i> / bouton : mieux, une version statique vous évite 100-200<abbr>Ko</abbr> et des temps d’exécution énormes,</li>
  532. <li>JavaScript ou <abbr>CSS</abbr> tiers : <strong>rapatriez le script bien au chaud chez vous, groupez-le avec les autres si il est critique</strong></li>
  533. <li>polices : rapatriement sur vos serveurs, quitte à payer une licence</li>
  534. </ul>
  535. <h4>Publicités, trackers et autres <i lang="en">A/B testing</i></h4>
  536. <p>Ils requièrent tous d’être en haut de page pour être exécutés en premier et sont massivement déployés sur les sites même dédiés mobiles. Le département marketing moderne se doit de posséder au moins un exemplaire de chaque catégorie.</p>
  537. <div id="attachment_823" class="wp-caption alignnone"><img class="size-medium wp-image-823" src="http://media.24joursdeweb.fr/2014/12/poignee-de-main-383x430.jpg" alt="Poignée de main"/><p class="wp-caption-text">« J’ai dépassé mon objectif de 42 régies pub sur la home, et toi ?  <br/>— Je viens de découvrir 4 fournisseurs d’<i lang="en">A/B testing</i>, ça part en prod demain »</p></div>
  538. <p>Les solutions techniques non bloquantes sont à négocier d’abord en interne pour faire prendre conscience du problème, puis auprès des fournisseurs, de moins en moins réfractaires. On arrive fréquemment à mettre les publicités dans des <i lang="en">iframes</i> et les scripts de <i lang="en">tracking</i> en asynchrone. Pour l’<i lang="en">A/B testing</i> ou certaines zones de publicité vitales, une bonne option, techniquement complexe, consiste à rapatrier en local, de préférence de manière automatisée, le code <abbr>JS</abbr> du prestataire, puis à l’inclure comme le reste des <abbr>JS</abbr> critiques en haut de page.</p>
  539. <h3>Les 3 caches</h3>
  540. <p>C’est comme les 3 coquillages : on peut faire sans, mais les gens du futur se moqueront. Partant du principe qu’il n’y a pas plus rapide qu’une requête qu’on ne fait pas, il convient de maîtriser rapidement les 3 techniques suivantes sur mobile.</p>
  541. <h4>Le cache <abbr title="Hypertext transfer protocol, Protocole de transfert hypertexte">HTTP</abbr></h4>
  542. <p>Depuis toujours la recette est simple :</p>
  543. <ul>
  544. <li>mettre des temps de cache très longs sur toutes les ressources statiques (plus d’1 mois),</li>
  545. <li>en cas de mise en production d’une nouvelle version, la mise à jour des caches clients se fait par le changement des <abbr title="Universal resource locator, emplacement de ressource unique">URL</abbr>s pointant sur les statiques.</li>
  546. </ul>
  547. <p>Point.</p>
  548. <p>Sur navigateurs de bureau, on pourrait s'arrêter là mais sur mobile le cache <abbr>HTTP</abbr> peut se révéler très volatile, voire capricieux. Si l’<abbr title="Operating system, Système d'exploitation">OS</abbr> estime qu’il a besoin de mémoire, il peut vider le cache du navigateur. C’est la raison pour laquelle certains sites ont développé leur propre système de mise en cache, en se basant sur <i lang="en">localStorage</i>.</p>
  549. <h4><i lang="en">DOM Storage</i></h4>
  550. <p><a href="https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage" hreflang="en"><i lang="en">localStorage</i></a> est un système simplissime de stockage de clé / valeur, de 5<abbr>Mo</abbr> minimum. Pour limiter les accès au serveur, stockez-y des informations aussi simples qu’un historique de navigation ou lourdes et complexes, comme une liste de toutes les marques automobile et des modèles. L’utilisation en est tellement facile que c’en est ennuyeux.</p>
  551. <p>Du coup certains en abusent.</p>
  552. <div id="attachment_737" class="wp-caption aligncenter"><a href="http://media.24joursdeweb.fr/2014/12/localstorage-google.jpg"><img class="size-full wp-image-737" src="http://media.24joursdeweb.fr/2014/12/localstorage-google.jpg" alt="localStorage sur Google"/></a><p class="wp-caption-text">Tiens, du <abbr>CSS</abbr> dans mon <i lang="en">localStorage</i></p></div>
  553. <p>Certains sites stockent carrément du <abbr>HTML</abbr>, du <abbr>CSS</abbr>, du JavaScript, des images ou des <i lang="en">fonts</i> puis via un système classique de gestion de session évitent de renvoyer les ressources au client.</p>
  554. <h4><i lang="en">Application Cache</i> (dit <i lang="en">offline</i>)</h4>
  555. <p>L’énorme avantage ergonomique d’une application native installée chez l’utilisateur, c’est qu’elle va s’ouvrir quand vous appuyez dessus, même si à ce moment-là vous transitez par le tunnel sous la manche. Imaginez que l’on puisse faire de même avec nos sites : il suffirait d’aller une seule fois sur une des pages pour rapatrier l’ensemble de l’interface, et toute la navigation se ferait en local. Les mises à jour du contenu ne se feraient que lorsque la connexion est rétablie et on ne dépendrait pas de la validation d’un <i lang="en">store</i> pour mettre à jour son application.</p>
  556. <p>Figurez-vous que la <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache" hreflang="en">technologie existe</a>, et date même d’une époque lointaine où Apple ne pensait pas encore à l’<i lang="en">app store</i> et à Objective C pour écrire des applications mais bien au Web et ses langages . Faites-moi plaisir et enfourchez votre mobile pour aller sur l’<abbr>URL</abbr> suivante :</p>
  557. <p><a href="http://appcache.offline.technology/demo/" hreflang="en">http://appcache.offline.technology/demo/</a></p>
  558. <p>Une fois la page chargée complètement (scrollez en bas pour voir les <i lang="en">logs</i>), <strong>passez <i lang="en">offline</i></strong> (mode avion), puis allez sur la 2<sup>de</sup> page nommée cache. Non seulement la page s’affiche comme si de rien n’était mais l’image du machin vert est également présente alors qu’elle ne peut pas être dans le cache HTTP classique.</p>
  559. <div id="attachment_827" class="wp-caption alignnone"><img class="size-medium wp-image-827" src="http://media.24joursdeweb.fr/2014/12/tbrun5-430x312.png" alt="Belle bête"/><p class="wp-caption-text">Belle bête</p></div>
  560. <p>Si vous utilisez Chrome, vous pouvez regarder sur <kbd>chrome://appcache-internals/</kbd> votre liste des sites utilisant cette technologie.</p>
  561. <p>À ce stade de la compétition vous avez peut être déjà entendu dire <a href="http://alistapart.com/article/application-cache-is-a-douchebag" hreflang="en">beaucoup de mal</a> sur appCache. C’est effectivement le genre d’<abbr title="Interface de programmation applicative">API</abbr> qui demande du temps et de l’amour pour être bien comprise, mais elle apporte un énorme confort utilisateur et est très bien <a href="http://caniuse.com/#feat=offline-apps" hreflang="en">supportée</a> sur mobile et même sur bureau. Elle est très adapté aux sites qui se comportent comme des applications (une seule page) mais il existe des techniques à base d’<i lang="en">iframe</i> pour partager ce super cache entre plusieurs pages d’un site plus classique.</p>
  562. <h3>Les images</h3>
  563. <p>Elles représentent fréquemment les deux tiers du poids des sites et ralentissent le chargement des ressources critiques.</p>
  564. <h4>Éviter de les charger</h4>
  565. <p>Captain Obvious a dit : c’est plus rapide sans image. C’est pas faux et il commence à y avoir pas mal de techniques permettant d’éviter des requêtes :</p>
  566. <ul>
  567. <li><abbr>CSS</abbr>3 pour les dégradés, arrondis, rotations et opacités. Dommage que ça ne soit plus à la mode.</li>
  568. <li>Les caractères unicodes des polices fournies avec les <abbr>OS</abbr> : ►★✓⇢ ✎♥☎ ♻⚠☻☺⇨ (attention si vous visez également <abbr>IE</abbr>8 sur Windows XP)</li>
  569. </ul>
  570. <p>Lorsque certaines images <strong>sont critiques pour votre interface</strong>, vous pouvez les embarquer directement dans le <abbr>HTML</abbr> ou le <abbr>CSS</abbr>. C’est la technique du <a href="http://css-tricks.com/data-uris/" hreflang="en"><code lang="en">data:uri</code> couplé à l’encodage en base64</a>. Oui ça a l’air sale mais uniquement si c’est mal fait.</p>
  571. <p>L’image la plus importante à charger est celle indiquant justement qu’il y a chargement ! Pourquoi ne pas mettre également le logo ou une image de contenu réellement importante.</p>
  572. <div id="attachment_820" class="wp-caption alignnone"><a href="http://media.24joursdeweb.fr/2014/12/loading-pmvc.jpg"><img class="wp-image-820 size-large" src="http://media.24joursdeweb.fr/2014/12/loading-pmvc-860x127.jpg" alt="Chargement du site Promovacances"/></a><p class="wp-caption-text">L’image d’attente arrive bien avant toutes les autres</p></div>
  573. <p>Il ne faut pas abuser de la technique car elle alourdit le <abbr>HTML</abbr> et le <abbr>CSS</abbr> qui sont des ressource critiques, mais sur quelques petites images stratégiques cela fait patienter l’utilisateur.</p>
  574. <h4>Chargement à la demande</h4>
  575. <p>C’est à se demander pourquoi les navigateurs ne le font pas déjà d’eux-mêmes : l’idée est bêtement de <strong>ne pas charger les images qui ne sont pas visibles </strong>! C’est radical pour les sites avec beaucoup d’images car cela libère la bande passante pour les ressources critiques et les images qui sont visibles. Voici un <a href="https://github.com/vvo/lazyload" hreflang="en">bon exemple de librairie</a>, utilisé notamment sur lequipe.fr, bureau ou mobile. Naviguez dessus (c’est pour le travail) et scrollez très vite : vous verrez les images apparaître au fur et à mesure de votre progression dans la page.</p>
  576. <h3>Cette technique seule sauve des dauphins tous les jours.</h3>
  577. <h3>Les images <i lang="en">responsive</i></h3>
  578. <p>Comment servir le meilleur rapport poids / qualité à l’utilisateur mobile ?</p>
  579. <h4>Le standard</h4>
  580. <p>Votre plus grand problème concernant les images à délivrer sur mobile est de comprendre ce que vous voulez réellement en faire. Le problème est de définir le problème si vous voulez, en répondant à ces 4 questions :</p>
  581. <ul>
  582. <li>adaptation à la taille du <i lang="en">viewport</i> : veut on servir des petites images aux petits écrans ?</li>
  583. <li>écran haute densité de pixels (ok, retina©) : veut-on leur servir des images de très haute qualité ?</li>
  584. <li><i lang="en">art direction</i> : pourquoi ne pas afficher des images au cadrage différent en fonction de la taille de l’écran ?</li>
  585. <li>format de l’image : veut-on servir du WebP à Chrome, du <abbr>JPG</abbr> <abbr>XR</abbr> à windows et du <abbr>JPG</abbr> 2000 à iOS ?</li>
  586. </ul>
  587. <p>Pour compliquer l’affaire, sachez que :</p>
  588. <ul>
  589. <li>un écran retina peut avoir un petit <i lang="en">viewport</i>,</li>
  590. <li>deviner la bande passante de l’utilisateur est hautement hasardeux,</li>
  591. <li>vous ne connaissez pas la seule valeur qui compte : la taille physique de l’écran et la distance écran-œil.</li>
  592. </ul>
  593. <p>Si vous êtes capable d’écrire un cahier des charges répondant à ces questions, alors vous pouvez vous pencher sur la réponse officielle et standard au problème : &lt;<a href="https://dev.opera.com/articles/responsive-images/" hreflang="en"><code lang="en">picture</code></a>&gt;. Le temps que ça marche partout, la librairie <abbr>JS</abbr> officielle est <a href="https://github.com/scottjehl/picturefill" hreflang="en">picturefill 2.0</a>.</p>
  594. <div id="attachment_822" class="wp-caption alignnone"><img class="size-medium wp-image-822" src="http://media.24joursdeweb.fr/2014/12/picture-430x257.jpg" alt="La balise &lt;picture&gt;"/><p class="wp-caption-text">La question est complexe, la réponse aussi.</p></div>
  595. <p>La peinture étant un peu fraîche, il n’y a pour l’instant pas de retour sur la mise en production de cette technique. L’amélioration de performances devra donc se tester chez vous, en particulier sur les plateformes sans <a href="http://caniuse.com/#search=picture">support</a>.</p>
  596. <h4>Fait à la main, roulé sous les aisselles</h4>
  597. <p>Difficile pour une solution générique de faire mieux que du code écrit spécifiquement. À force j’utilise généralement chez mes clients un petit ensemble de techniques :</p>
  598. <ul>
  599. <li><abbr>JPG</abbr> grande résolution, qualité 0 : pour une image unique à faire passer sur tous type d’écran, éditée à la main. Ça passe pour 90% des <abbr>JPG</abbr>. (<a href="http://bit.ly/jpg-0">à essayer</a> sur un écran haute densité),</li>
  600. <li>images basse définition pour remplir l’espace, suivies du chargement de la haute définition. Le <abbr>JPG</abbr> progressif marchant mal sur iOS, c’est une manière d’avoir le même effet,</li>
  601. <li><i lang="en">lazy-loading</i> pour la majorité des images, images embarquées pour les critiques,</li>
  602. <li>quand on peut, des formats vectoriels : <abbr title="Scalable vector graphics, images vectorielles scalables">SVG</abbr> et polices d’icônes.</li>
  603. </ul>
  604. <p>Combinez, testez et saupoudrez de <abbr>JS</abbr> pour obtenir de beaux effets. La maintenance n’est pas facile mais les résultats sont bons.</p>
  605. <h3>Interfaces fluides</h3>
  606. <p>Vous avez remarqué que les smartphones sont capables de jouer de manière fluide des jeux 3D mais ont des difficultés dès qu’il s’agit de retailler des <code>div</code>s ou de jouer avec du texte ? Au contraire de la 3D, il n’existe pas de puce dédiée à recalculer un <abbr title="Document object model, Modèle d'ojet document">DOM</abbr> qui bouge ou l’écoulement des caractères. Il va donc falloir aider un peu nos pages.</p>
  607. <h4>Animations</h4>
  608. <p>Elles peuvent être fluides si on les travaille au corps. D’abord il y a un certain nombre de propriétés CSS qu’il vaut mieux ne pas animer comme <i lang="en">top</i>, <i lang="en">left</i>, <i lang="en">width</i> et <i lang="en">height</i>. On leur préférera les variations de <i lang="en">transforms</i> comme <i lang="en">translateX()</i> ou <i lang="en">scale()</i> qui ont la bonne idée d’être pris en charge directement au niveau du processeur graphique.</p>
  609. <p>Vous pouvez essayer dans l’ordre :</p>
  610. <ul>
  611. <li>les <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transitions" hreflang="en">transitions <abbr>CSS</abbr></a>, qui suffisent à la plupart des sites,</li>
  612. <li>les <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_animations" hreflang="en">animations <abbr>CSS</abbr></a>, quipermettent des effets plus avancés</li>
  613. <li>enfin si <abbr>JS</abbr> doit tout piloter (un jeu par exemple), utilisez <code lang="en">requestAnimationFrame</code>, <strong>arrêtez jQuery animate</strong> et préférez des librairies spécialisées comme D3.js, GSAP ou TweenJS qui génèrent du <abbr>CSS</abbr>3.</li>
  614. </ul>
  615. <h4><abbr>CSS</abbr> 3 avec modération</h4>
  616. <p>Remplacer les images de décoration par <abbr>CSS</abbr> c’était une bonne idée jusqu’à ce que vous réalisiez que le scroll lag sérieusement depuis que vous avez rajouté une ombre portée sur toute la hauteur de votre liste. De fait, tous les effets d’ombre, de transparence et de coins arrondis sont calculés en continu et cela peut coûter cher.</p>
  617. <p>Une seule règle : tester, et sur de vrais mobiles bien sûr.</p>
  618. <h4>Calculs</h4>
  619. <p>On ne calcule pas tous les jours une suite de Fibonacci mais si ça vous arrive, utilisez les <i lang="en">Web Workers</i>. Sur les mobiles modernes ça vous donne accès à un second processeur pour exécuter du JavaScript. Sur les autres, la bonne veille technique du <code lang="en">setTimeout(0)</code> reste valable pour exécuter des boucles lourdes sans bloquer l’interface. Devinez qui vous a écrit <a href="https://gist.github.com/jpvincent/867010d224d61a6539d3">un script</a> pour ça ?</p>
  620. <h4>Testez !</h4>
  621. <p>Les derniers navigateurs mobiles acceptent enfin le déboguage à distance ! Cela signifie que vous allez pouvoir utiliser le <i lang="en">profiler</i> que vous connaissez sur de vrais téléphones et débusquer les endroits qui font ramer votre interface.</p>
  622. <div id="attachment_740" class="wp-caption aligncenter"><a href="http://media.24joursdeweb.fr/2014/12/profiler.jpg"><img class="size-full wp-image-740" src="http://media.24joursdeweb.fr/2014/12/profiler.jpg" alt="Vue réseau"/></a><p class="wp-caption-text">Oh la belle verte : c’est mon <abbr>CSS</abbr> qui est gourmand</p></div>
  623. <p>Pour les anciens <abbr>OS</abbr> comme Android 2.3, cela reste la devinette, rassurez vous.</p>
  624. <h2>Impliquer, mesurer, surveiller</h2>
  625. <p>On ne peut pas résoudre le problème qu’on ne voit pas. Avant de commencer tout projet de performance, il faut <strong>définir</strong> ce que doit être la performance, prendre un point de départ, choisir ses métriques, et surveiller automatiquement les performances dans le temps.</p>
  626. <p>Sinon le projet performance s'arrêtera après la mise en prod des premières améliorations de performance.</p>
  627. <p>Il fut un temps où il était possible d’avoir une équipe Web composée d’une seule personne : référencement, accessibilité, code, design, administration système, c’était fun. Mais aujourd’hui, à toutes vos compétences techniques il faut maintenant rajouter une grosse capacité à comprendre pourquoi l’on code et comment dialoguer avec le reste de la boite.</p>
  628. <p>Donc par pitié, ne partez pas en croisade solitaire contre les lenteurs de votre site, au risque que personne dans la boîte ne s’en aperçoive. Il faut d’abord sensibiliser et évangéliser sur le coût du manque de performance pour la société et l’image du produit. Toute l’introduction de cet article est là pour cela.</p>
  629. <p>Une fois que vous avez l’oreille des décideurs, faites écrire dans ce qui se rapproche le plus d’une spécification les objectifs de performance : en dessous de quels temps considère-t-on qu’il faut agir ? Vous pouvez par exemple prendre ces chiffres, relativement universels sans être trop ambitieux :</p>
  630. <ol>
  631. <li>Pour 80% des utilisateurs</li>
  632. <li>Premier rendu en moins de 2 secondes</li>
  633. <li>Fonctionnalité principale en moins de 5 secondes</li>
  634. <li>Navigation de page en page en moins de 2 secondes</li>
  635. </ol>
  636. <h3>Les utilisateurs et le premier rendu</h3>
  637. <p>Les deux premiers points demandent à déterminer l’équipement des utilisateurs :</p>
  638. <ul>
  639. <li>Quels navigateurs ?</li>
  640. <li>Quelle est la puissance des mobiles ?</li>
  641. <li>Quelle est la qualité de leur connexion ? (l’origine géographique peut suffire à la deviner)</li>
  642. </ul>
  643. <p>Les seuls moments où on vous a dit que le site était lent, c’est lorsque vos collaborateurs ont essayé de l’utiliser sans le Wifi du bureau. Comme des vrais gens donc. Il faut reproduire ces conditions de manière systématique et certaine pour constater les dégâts et juger des progrès avec le temps.</p>
  644. <p>Le temps de premier rendu est relativement facile à vérifier avec des outils comme WebPagetest.org. Ce qui est plus compliqué c’est de paramétrer WebPagetest avec une simulation de connexion qui soit réaliste par rapport à vos utilisateurs. Comme ce n’est pas le cas de Webpagetest.org par défaut, je vous donne mes paramètres beaucoup plus représentatifs de la France.</p>
  645. <div id="attachment_727" class="wp-caption aligncenter"><a href="http://media.24joursdeweb.fr/2014/12/connexion-webpagetest.png"><img class="size-full wp-image-727" src="http://media.24joursdeweb.fr/2014/12/connexion-webpagetest.png" alt="Connexions WebPageTest"/></a><p class="wp-caption-text">Des paramètres de connexion plus réalistes.</p></div>
  646. <p>WebPagetest s’installe également en interne, et peut <a href="https://code.google.com/p/mobitest-agent/" hreflang="en">piloter des mobiles</a>.</p>
  647. <h3>La fonctionnalité principale</h3>
  648. <p>Là ça se complique : comment <strong>déterminer le temps d’accès à la fonctionnalité principale</strong> ? Aucun outil ne peut faire cela automatiquement pour vous car seul vous connaissez bien votre interface (prends ça <a href="http://en.wikipedia.org/wiki/Skynet_%28Terminator%29" hreflang="en">Skynet</a>). Par contre vous pouvez collecter automatiquement des temps en JavaScript et vous les envoyer dans l’outil de tracking qui vous sied (G. Analytics peut suffire au début).</p>
  649. <p>Si vous êtes un site de news ou à contenu visuel, trackez la fin de téléchargement de la première image visible utile par exemple (tiens, <a href="https://github.com/jpvincent/requestTracker">voici du code</a> qui peut vous y aider). Si votre fonctionnalité principale dépend de JavaScript (vidéo, moteurs de recherche complexes, application…), il est encore plus facile de minuter le moment où le contenu devient interactif.</p>
  650. <h3>La navigation interne</h3>
  651. <p>Le dernier point consiste à <strong>ne pas décevoir l’utilisateur après la première page</strong>, que ce soit la vitesse de chargement des pages suivantes ou la fluidité de l’interface.</p>
  652. <p>Là vous pouvez surveiller les taux de mise en cache client (utilisation avancée de <a href="http://fr.slideshare.net/jpvincent/le-monitoring-de-la-performance-front">WebPagetest Monitor</a>) et simuler des navigations dans vos tests de performance.</p>
  653. <div id="attachment_744" class="wp-caption aligncenter"><a href="http://media.24joursdeweb.fr/2014/12/cache-F.png"><img class="size-full wp-image-744" src="http://media.24joursdeweb.fr/2014/12/cache-F.png" alt="Note de F en Cache Static Content"/></a><p class="wp-caption-text">Attention chérie ça va ramer</p></div>
  654. <p>Il n’y a pas de moyen facile et automatique de surveiller que l’interface elle-même est fluide sur mobile : contentez-vous d’une vérification systématique et digitale.</p>
  655. <h2>Stratégies de chargement</h2>
  656. <p>Il faut jouer avec la perception utilisateur et afficher quelque chose d’utile le plus rapidement possible. Cela demande à s'asseoir autour d’un café avec les autres équipes et à écrire la liste des priorités d’une page. Charge à vous de traduire cela en code pour régler l’ordre dans lequel les ressources vont être chargées par le navigateur.</p>
  657. <p>Prenons 2 exemples de sites qui ont fait ce travail de priorité des requêtes.</p>
  658. <h3>Home Google</h3>
  659. <p>La fonctionnalité principale est évidemment l’affichage du champ texte. Mais les fonctionnalités secondaires sont légion : <i lang="en">autocomplete</i> sur ce champ, l’obligatoire intégration Google+, le menu, la suggestion de géolocalisation et même une bannière d’auto-promotion.</p>
  660. <div id="attachment_731" class="wp-caption aligncenter"><a href="http://media.24joursdeweb.fr/2014/12/hp-google.jpg"><img class="size-full wp-image-731" src="http://media.24joursdeweb.fr/2014/12/hp-google.jpg" alt="Home de Google"/></a><p class="wp-caption-text">Ils ont de l’avenir</p></div>
  661. <p>Google n’attend pas : il embarque un <abbr>CSS</abbr> minimaliste et suffisant dans le <abbr>HTML</abbr>, le <abbr>HTML</abbr> ne contient que le champ et des éléments pour définir la structure de la page. <strong>En 1 requête et 22<abbr>Ko</abbr>, soit l’équivalent de 2 allers-retours réseau, la fonctionnalité principale est déjà utilisable</strong>. Ensuite arrivent plus de 200<abbr>Ko</abbr> de ressources diverses pour afficher et rendre fonctionnel le reste de la page.</p>
  662. <h3>Home avec carrousel massif</h3>
  663. <p>Cette homepage était principalement vue depuis la Chine, il a donc fallu la calibrer pour des petits débits / grosses latences : elle était déjà optimisée pour le mobile. Par contre il fallait également afficher dans un carrousel plusieurs images de haute qualité de 1200 pixels de large.</p>
  664. <div id="attachment_730" class="wp-caption aligncenter"><a href="http://media.24joursdeweb.fr/2014/12/hp-cma.jpg"><img class="size-full wp-image-730" src="http://media.24joursdeweb.fr/2014/12/hp-cma.jpg" alt="Home de CMA"/></a><p class="wp-caption-text">Le carrousel classique</p></div>
  665. <p>Du point de vue du réseau, charger plusieurs ressources en parallèle est généralement vu comme une bonne idée. Sauf lorsque le débit est ténu et les ressource trop grosses comme c’est le cas ici. Le chargement de plusieurs images en simultané ralentissait le chargement des ressources du chemin critique.</p>
  666. <p>Il a donc fallu prioriser : logo, texte, et image principale d’abord.</p>
  667. <p>Les fonctionnalités secondaires sont les icônes, un moteur de recherche (non visible ici) les <strong>autres images du carrousel</strong> et des images bien plus bas.</p>
  668. <p>Adieu donc la police, utilisation de <code>data:uri</code> pour embarquer le logo en base64, inclusion en <code>&lt;img src&gt;</code> traditionnel de la première image du carrousel (et seulement elle) et on développe un petit script pour <strong>aller chercher de manière asynchrone les photos suivantes</strong> avant de vraiment démarrer le carrousel.</p>
  669. <h2>Conclusion : <i lang="en">Mobile first</i></h2>
  670. <p>Ça n’est pas du lâcher de <i lang="en">buzzword</i> gratuit mais bien une adaptation à la manière dont nos utilisateurs utilisent nos sites, qu’ils soient en situation de mobilité, dans un pays lointain ou qu’ils fassent partie des 20% de français avec moins de 2<abbr>Mb</abbr>/<abbr>s</abbr>.</p>
  671. <p>Le <i lang="en">mobile first</i> est l’héritier de la pensée « amélioration progressive » : délivrons très rapidement la promesse initiale, chargeons les fonctionnalité supplémentaires après et en fonction des capacités du client. Cela oblige à se poser la vraie question : quelles sont les priorités de chaque page ?</p>
  672. <p>Cela s'intègre parfaitement avec un processus de conception moderne où designer et intégrateur web passent pas mal de temps l’un à côté de l’autre pour fignoler les maquettes sur les mobiles.</p>
  673. <p>Nous avons évoqué une palanquée de techniques : certaines sont connues depuis bientôt 10 ans, beaucoup émergent et certaines sont devenues dangereuses. Toutes répondent à une situation particulière donc c’est à vous de <strong>tester ce qui marche ou pas</strong>, page à page.</p>
  674. <p>Le processus de travail est presque aussi important que les techniques individuelles : la communication et l’effort de groupe sont vitaux pour maintenir la qualité à travers le temps. Sans monitoring ou automatisation des déploiements cela va rester amateur et pénible. Sans soutien hiérarchique du client (interne, externe, hiérarchique, bref celui qui vous paye) vous n’irez pas bien loin seul. Ou pire vous serez frustré par ce métier pourtant formidable qui est le nôtre.</p>
  675. </article>
  676. </section>
  677. <nav id="jumpto">
  678. <p>
  679. <a href="/david/blog/">Accueil du blog</a> |
  680. <a href="http://www.24joursdeweb.fr/2014/le-web-mobile-et-la-performance/">Source originale</a> |
  681. <a href="/david/stream/2019/">Accueil du flux</a>
  682. </p>
  683. </nav>
  684. <footer>
  685. <div>
  686. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  687. <p>
  688. Bonjour/Hi!
  689. 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>
  690. 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>).
  691. </p>
  692. <p>
  693. 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>.
  694. </p>
  695. <p>
  696. Voici quelques articles choisis :
  697. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  698. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  699. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  700. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  701. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  702. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  703. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  704. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  705. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  706. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  707. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  708. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  709. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  710. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  711. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  712. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  713. </p>
  714. <p>
  715. 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>.
  716. </p>
  717. <p>
  718. Je ne traque pas ta navigation mais mon
  719. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  720. conserve des logs d’accès.
  721. </p>
  722. </div>
  723. </footer>
  724. <script type="text/javascript">
  725. ;(_ => {
  726. const jumper = document.getElementById('jumper')
  727. jumper.addEventListener('click', e => {
  728. e.preventDefault()
  729. const anchor = e.target.getAttribute('href')
  730. const targetEl = document.getElementById(anchor.substring(1))
  731. targetEl.scrollIntoView({behavior: 'smooth'})
  732. })
  733. })()
  734. </script>