Alsacreations.com - Apprendre - Archives (avril 2014)

Les dernières ressources publiées sur Alsacreations.com

Le: 14 04 2014 à 11:00 Auteur: Geoffrey C.

Le gros problème du Responsive Web Design tient probablement dans la gestion des ressources chargées et utilisées sur une page web, utiles à notre terminal et adaptées à notre écran ou notre fenêtre de consultation. Stéphanie nous en parlait déjà avec Responsive Webdesign - présent et futur de l'adaptation mobile.

Je vous avais parlé l'an dernier de l'annonce du moteur WebKit (12 août 2013) concernant son support de l'attribut srcset ; c'est aujourd'hui Google qui publie la version 34.0.1847.116 (retenez 34, ça suffira) de son navigateur Chrome (qui est passé sous moteur Blink, fork récent de WebKit). Parmi les mises à jour, on retrouve les corrections de sécurité habituelles, mais également la prise en charge partielle de l'attribut srcset pour les éléments images <img>.

L'attribut srcset, principes

Lorsque vous insérez une image dans votre page web, il y a de fortes chances pour que vous utilisiez un code semblable à :

<img src="mon-image.jpg" width="850" height="475" alt="">

Ce code vous permet de charger une image en réservant un espace de 850 pixels de large aussi bien sur un écran classique que sur un écran de smartphone. Avec un peu de chance vous avez un code CSS bien construit qui vous permet de redimensionner l'image pour éviter les débordement.

img {
    max-width: 100%;
    height: auto;
}

Mais vous conviendrez que charger une image de 850 x 475 px n'est pas très adapté sur un écran de 320 px de large (si on prend comme exemple la largeur actuelle gérée par l'iPhone). Une image de cette taille pèse environ 150 Ko (compression de 40% sur une photographie), là où une image adaptée de 320 x 179 px ferait environ 23 Ko avec la même compression. Soit une différence de 127 Ko, multiplié par le nombre d'images du même genre dans votre page.

Attribut srcset : exemple

L'attribut srcset vient apporter une solution à ce problème en vous permettant de définir une image adaptée au terminal de consultation en ciblant la taille de l'écran, et également la densité de pixels. Voici par exemple une utilisation envisageable de l'attribut srcset :

<img src="mon-image.jpg"
     srcset="mon-image.jpg 1x,
             mon-image-320.jpg 320w 1x,
             mon-image-640.jpg 320w 2x"
     width="850" height="475" alt="">

Dans cet exemple, une image de 850 pixels de large est chargée grâce à src. Cela permet aux navigateurs ne prenant pas en charge l'attribut srcset de charger une image de contenu. Les autres navigateurs vont vérifier s'ils trouvent une correspondance dans les critères de srcset, s'ils ne trouvent rien ils chargeront l'image de base, autrement ils chargeront une image adaptée.

La syntaxe de la valeur d'attribut est la suivante :

<adresse-de-l-image> [critère( critère)](, <adresse-de-l-image> [critère( critère)])

Si le ou les critères (entre crochets) correspondent au terminal qui consulte la page web, alors l'image (entre crochet) sur la gauche du critère sera chargée.

Dans l'exemple précédent nous avons plusieurs alternatives pour chaque image :

  • 1x : cas d'une densité de pixels égale à 1 (correspondant en fait à notre valeur de src ici)
  • 320w 1x : cas où la largeur du viewport est inférieure ou égale à 320px (iPhone 3 par exemple)
  • 320w 2x : cas où la largeur du viewport est inférieure ou égale à 320px et où la densité de pixel est inférieure ou égale à 2 (iPhone 4 par exemple)... et supérieure à 1 puisqu'il y a déjà un intervalle pour les densités inférieures ou égales à 1 dans notre srcset

Une image correspondante sera chargée, et uniquement celle-ci afin d'éviter le chargement des images inutilisées.

Démonstration

Particularité et problèmes à prévoir

La syntaxe n'est pas forcément intuitive et ne nous dit rien sur le sens des critères attribués à chaque image.
S'agit-il d'une égalité à la valeur du critère, d'une limite haute ou d'une limite basse ? Pour comprendre le comportement attendu, il faut... lire la doc !

Valeur des critères

Celle-ci précise que "la limite haute est l'infini" – ça fait loin – "sauf si un autre critère vient remplacer cette limite haute". Ainsi, il est possible de comprendre que si je définis un critère à 320w, je définis une nouvelle limite haute pour mon image, c'est à dire que n'importe quel terminal se situant entre 1 et 320px de largeur correspondra à ce critère.
Dès lors que je cible deux limites hautes pour deux images différentes, je crée un intervalle. Par exemple :

<img src="mon-image.jpg"
     srcset="mon-image-320.jpg 320w,
             mon-image-640.jpg 640w"
     width="850" height="475" alt="">

Ce code permettrait de définir une image de 320px de large pour un terminal dont la largeur est comprise entre 1 et 320px, puis une image de 640. (Note : à l'heure actuelle, Chrome ne reconnaît pas les valeurs de viewport, donc cet exemple précis).

Image affichée VS image(s) chargée(s) ?

L'un des intérêt de cet attribut est qu'il prenne la place de l'attribut src si l'un des critères est validé, l'avantage étant, de ce fait, de ne charger que l'image la plus intéressant pour le terminal qui consulte votre page web. D'ailleurs le processus est détaillé sur la page du W3C.

Figurez-vous que c'est exactement ce que fait Chrome 34 (j'avais bien le droit d'en douter !), et c'est une bonne nouvelle. Il ne reste plus qu'à voir cela appliqué aux navigateurs "mobiles".

Mais comment réagit le navigateur s'il rencontre deux images dont les critères correspondent ?
Très bonne question, nous nous sommes posé la même. Pour effectuer le test, nous avons regroupé plusieurs images identiques dans leurs proportions et ajouté un mot dessus pour détecter rapidement laquelle est chargée. Puis nous avons appliqué des critères bidons et des critères correspondant à notre terminal de test (viewport 1920px, densité de 1.0).

Test N°1 : La densité
<img src="mon-image.jpg"
     srcset="mon-image-big.jpg 1x,
             mon-image-hd.jpg 2x"
     width="850" height="475" alt="">

L'image "big" correspondant au critère "1x" est chargée, donc tout va bien.

Test N°2 : L'absent
<img src="mon-image.jpg"
     srcset="mon-image-hd.jpg 2x"
     width="850" height="475" alt="">

Ici aucun critère de srcset ne correspond, l'image du src est chargée.

Test N°3 : Le viewport
<img src="mon-image.jpg"
     srcset="mon-image-320.jpg 320w,
             mon-image-big.jpg 1920w"
     width="850" height="475" alt="">

Là c'est la catastrophe ! Lorsqu'il y a un intervalle de Viewport, Chrome semble complètement bogué et prend systématiquement la première image qu'il rencontre. Même en plaçant un premier critère à 3000w, Chrome chargera la première image.

Test N°4 : Les correspondances multiples

Difficile de proposer un contrôle en remplissant le critère de densité d'une part, et le critère du viewport d'autre part, puisque le second est bogué. Du coup j'ai tenté avec deux fois le même critère en attendant de pouvoir faire mieux.

<img src="mon-image.jpg"
     srcset="mon-image-big.jpg 1x,
             mon-image-hd.jpg 1x"
     width="850" height="475" alt="">

L'image "big" est bien chargée et affichée, aucun autre chargement d'image n'est effectué.

Support et limites

Il ne s'agit donc que d'un support partiel proposé par Chrome 34. En effet le support de l'attribut semble bogué puisque dès que vous renseignez un critère en "Nw", le navigateur affiche la première image trouvée. Le support semble plutôt bon pour la densité de pixel par contre.

Attendons de voir ce que vont proposer les prochaines implémentations.

Navigateurs Versions Détails
Internet Explorer Internet Explorer Non supporté
Firefox Firefox
Firefox Mobile
Non supporté
Chrome Chrome 34+
Chrome Mobile
Partiellement supporté
Non supporté
Opera Opera
Opera Mobile
Non supporté
Safari

Safari
Safari Mobile

Non supporté
Android Browser Android Browser Non supporté

Le: 08 04 2014 à 10:30 Auteur: Stéphanie W.

L'accessibilité des couleurs et les contraintes liées au contraste ont souvent mauvaise presse auprès des designers. Certains craignent que les contraintes d’accessibilité des couleurs limitent leur palette et par la même occasion leur créativité. D’autres pensent (à tort) que l’accessibilité des couleurs n’est réservée qu’à une infime partie de la population atteinte de handicaps visuels comme le daltonisme, hors de la cible de leur site. Voici un petit tutoriel, pas à pas, pour créer une palette de couleurs accessible, sans avoir pour autant à brider sa créativité. [...]

Retrouvez l'intégralité de ce tutoriel multi-pages en ligne

Le: 03 04 2014 à 12:18 Auteur: Victor BRITO

Ce tutoriel a été initialement publié en anglais par Florent Verschelde sous l'intitulé Full page video background with HTML and CSS. Quelques adaptations ont été apportées par rapport au tutoriel original.

Je voulais implémenter une vidéo d'arrière-plan occupant toute une page :

  • avec l'élément HTML 5 <video>,
  • utilisant tout le viewport
  • et recouvrant le viewport (pas de bandes noires).

Afin de recouvrir pleinement le viewport avec la vidéo, on pourrait utiliser JavaScript, mesurer le viewport, puis dimensionner et positionner en conséquence la vidéo.

Cependant, il existe aussi des solutions entièrement en CSS, au moins pour le cas d'usage ci-dessus. Voici l'une de ces solutions, présentée ici dans un iframe (notez que la vidéo est saccadée parce qu'elle est animée image par image, et non pas parce qu'il y a des soucis de performances). Les explications se trouvent ci-après.

Format letterbox par défaut

Prendre un élément <video> et le faire recouvrir le viewport est aussi facile que pour n'importe quel élément HTML, par exemple avec un positionnement fixe :

#mavideo {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

Cela fait bel et bien prendre à notre élément <video> la largeur et la hauteur du viewport. Mais, si la source vidéo a un format différent de celui de l'élément <video> (et ce sera presque certainement le cas si l'on n'utilise que la largeur et la hauteur du viewport !), on obtient un affichage de type letterbox, c'est-à-dire de vilaines bandes noires.

Une source vidéo en 16:9 dans un élément <video> carré
Une source vidéo en 16:9

Comment corriger ça ? On remarque d'abord que le format letterbox est très semblable à la valeur contain de la propriété background-size. En fait, si notre élément <video> était un <div> classique et la vidéo affichée une image d'arrière-plan, le comportement par défaut du navigateur serait semblable à celui-ci :

video {
  background-color: black;
  background-image: /* Ici, notre vidéo */;
  background-position: center center;
  background-size: contain;
}

À présent, si vous vous êtes familiarisés avec la propriété background-size, vous savez qu'elle a une valeur cover qui produit exactement le type d'effet que nous essayons d'obtenir ici. Si seulement nous pouvions utiliser le même genre de chose pour les images de contenu et les vidéos !

Et nous le pouvons… avec la proprité object-fit. Malheureusement, il y a un écueil.

Utiliser object-fit

Sous les navigateurs qui prennent en charge la propriété CSS object-fit, nous pourrions facilement résoudre ce problème :

#mavideo {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  object-fit: cover;
}

La fonctionnalité d'object-fit a été conçue pour les éléments liés aux médias visuels, y compris les images et les vidéos. Elle permet de dire aux navigateurs comment ils devraient faire rentrer un rectangle (la source du média) dans un autre (l'élément du média). En particulier, elle dispose des valeurs cover et contain, qui fonctionnent tout comme les valeurs semblables de background-size. Il y a également une propriété object-position, semblable à background-position, sauf qu'elle centre tout par défaut (object-position: 50% 50%).

Donc, object-fit fait tout ce que nous voulons ; mais, sa prise en charge par les navigateurs est faible, à l'heure actuelle :

  • elle a été d'abord implémentée par Opera, avant l'abandon de son propre moteur de rendu ;
  • elle a été récemment ajoutée à Chrome (dans Chrome 32) ;
  • dans la candidature à la recommandation de 2012 et le brouillon de l'auteur de 2013, la fonctionnalité est étiquetée en danger (c'est-à-dire en danger de suppression), même si sa prise en charge par Chrome pourrait convaincre le W3C de la maintenir ;
  • sa prise en charge par Firefox serait une bonne chose également (un bug a été, d'ailleurs, ouvert).
Tableau des compatibilités
Navigateurs Versions Détails
Chrome Chrome 32+  
Opera Opera 10.6+ et 12.1-
Opera 19+
Opera Mobile 11.0+ et 12.1-
Avec le préfixe -o- entre les versions 10.6 et 12.1, sans préfixe depuis Opera 19

De toute façon, cela ne marchera pas tout de suite pour nos besoins. Trouvons donc une solution en CSS qui marche.

Utiliser les media queries

Comment fonctionne le centrage d'une vidéo, au juste ? Il y a deux situations : la vidéo pourrait avoir besoin de déborder verticalement ou horizontalement (jamais les deux à la fois, ce serait du gâchis).

Une image pour aider à comprendre le propos :

La vidéo en gris, le viewport en pointillés
La vidéo en gris, le viewport en pointillés rouge

Si le format du viewport est plus grand que celui de la vidéo, la vidéo débordera en haut et en bas (premier exemple). Si le format du viewport est plus petit, la vidéo débordera sur la gauche et la droite.

À condition de connaître déjà le format de la vidéo, nous pouvons coder ceci en CSS (notez que nous aurons besoin de coder en dur le format — aspect ratio — de la vidéo dans les media queries) :

#mavideo {
  position: fixed;
  top: 0;
  left: 0;
}
@media (min-aspect-ratio: 16/9) {
  #mavideo {
    width: 100%;
    height: auto; /* En pratique : supérieur à la hauteur du viewport */
  }
}
@media (max-aspect-ratio: 16/9) {
  #mavideo {
    width: auto; /* En pratique : supérieur à la largeur du viewport */
    height: 100%;
  }
}

Avec cela, nous avons les bonnes dimensions, pleinement responsive, pour notre vidéo, quelles que soient les dimensions du viewport. Mais, elle n'est pas encore centrée.

Astuce pour centrer

Nous pourrions essayer de centrer la vidéo en utilisant des valeurs négatives pour top (ou margin-top) ou left (ou margin-left) ; mais, il n'est pas facile de décaler la vidéo du bon nombre de pixels en toutes circonstances. J'ai essayé d'utiliser calc() et les unités relatives au viewport : ça marchait sous Firefox, mais pas sous Chrome et Safari, et le code produit était, dans l'ensemble, très obscur. Ce n'était pas une bonne solution.

Alors, comment centrer un truc plus large ou plus haut que le viewport si nous n'en connaissons pas les dimensions exactes ? Facile ! Nous créons un conteneur à la fois plus grand que la vidéo et le viewport.

Voici l'idée en image :

Schémas de centrage d'une vidéo

Les pointillés représentent encore notre viewport, le rectangle clair notre vidéo et la zone foncée notre conteneur. Nous pouvons alors utiliser n'importe quelle technique de centrage en CSS (par exemple, flexbox) pour centrer la vidéo à l'intérieur du conteneur.

Mais, savez-vous ce qui fonctionne comme un conteneur qui centre automatiquement une vidéo ? L'élément <video> ! Nous pouvons donc sauter la création d'un <div> et l'utilisation des techniques de centrage en CSS ! À présent, nous n'avons besoin que de rendre beaucoup trop haut ou beaucoup trop large notre élément <video> et laisser le navigateur se charger de centrer automatiquement et par défaut (cela agit un peu comme un <div> avec une image d'arrière-plan à laquelle s'appliquerait background-size: contain).

#mavideo {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
@media (min-aspect-ratio: 16/9) {
  #mavideo {
    height: 300%;
    top: -100%;
    /* Ou bien height: 200%; top: -50%; */
    /* Ou bien height: 400%; top: -150%; */
  }
}
@media (max-aspect-ratio: 16/9) {
  #mavideo {
    width: 300%;
    left: -100%;
    /* Ou bien width: 200%; left: -50%; */
    /* Ou bien width: 400%; left: -150%; */
  }
}

Cela fonctionnera à merveille. Mais, je recommanderais également d'utiliser un conteneur <div> pour envelopper la vidéo et donner à ce conteneur les dimensions du viewport (cf. les pointillés). Pourquoi, vous demandez-vous ? Parce que si vous voulez ajouter des boutons scriptés avec votre vidéo, ou tous autres métadonnée ou contenu que vous voulez afficher par-dessus la vidéo quand elle est jouée, cela s'avérera utile. Alors, utilisons une configuration légèrement plus verbeuse :

<div id="video-fond">
  <video controls>
    <!-- Source vidéo par défaut -->
    <source type="video/mp4" src="mavideo.mp4" media="(orientation: landscape)">
    <source type="video/webm" src="mavideo.webm" media="(orientation: landscape)">
    <!-- Utilisez des sources vidéo carrées pour économiser la bande passante -->
    <source type="video/mp4" src="mavideo_carree.mp4" media="(orientation: portrait)">
    <source type="video/webm" src="mavideo_carree.webm" media="(orientation: portrait)">
  </video>
  <!-- Ici les boutons ou les métadonnées -->
</div>

Dans cet exemple, je suggère que vous pourriez utiliser une source vidéo différente pour le mode portrait. Bien entendu, vous pourriez vouloir ne pas utiliser du tout ce type d'affichage de vidéo en pleine page ou d'arrière-plan vidéo sur de petits écrans et/ou en mode portrait.

Je ne vais pas détailler ces cas d'usage ni les solutions, mais vous aurez besoin d'adapter en conséquence les media queries, et sans doute votre code d'initialisation JavaScript.

Ajoutons object-fit, après tout

Bien que cette technique de centrage soit plutôt sympathique, object-fit est, en fait, plus fiable (particulièrement pour de très hauts ou de très larges viewports). Elle pourrait également être mieux performante sous Chrome ou, à l'avenir, sous les navigateurs en général : puisqu'elle est faite pour ce genre de chose, les développeurs de navigateur pourraient optimiser pour cette dernière, et non pas pour notre technique virant légèrement au hack.

Puisque nous nous tournons vers l'avenir, et en ciblant également les versions récentes de Chrome, nous pouvons utiliser la règle CSS @supports pour détecter la prise en charge d'object-fit et écraser certains styles.

#video-fond {
  overflow: hidden;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
#video-fond > video {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}
/* 1. Pas de support d'object-fit */
@media (min-aspect-ratio: 16/9) {
  #video-fond > video {
    height: 300%;
    top: -100%;
  }
}
@media (max-aspect-ratio: 16/9) {
  #video-fond > video {
    width: 300%;
    left: -100%;
  }
}
/* 2. En cas de support d'object-fit, écrase les règles en (1) */
@supports (object-fit: cover) {
  #video-fond > video {
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    object-fit: cover;
  }
}

Et… ça y est !

Voir la page de démonstration

Vous pouvez redimensionner la fenêtre de votre navigateur pendant que la vidéo est jouée. Si vous essayez sous Firefox / Safari / IE d'une part, et sous Chrome d'autre part, vous pourrez remarquer que la dimension de 300 % ne suffit pas à bien gérer des viewports extrêmement étroits (sous Firefox / Safari / IE), alors que, sous Chrome, object-fit: cover fonctionne, même dans ces derniers cas.

Retrouvez l'intégralité de ce tutoriel multi-pages en ligne