Les dernières ressources publiées sur Alsacreations.com
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>
.
srcset
, principesLorsque 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.
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 :
srcset
. Une image correspondante sera chargée, et uniquement celle-ci afin d'éviter le chargement des images inutilisées.
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 !
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).
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).
<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.
<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.
<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.
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é.
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 | Non supporté | |
Firefox Firefox Mobile |
Non supporté | |
Chrome 34+ Chrome Mobile |
Partiellement supporté Non supporté |
|
Opera Opera Mobile |
Non supporté | |
Safari |
Non supporté | |
Android Browser | Non supporté |
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
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 :
<video>
,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.
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.
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.
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 :
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 ;
Navigateurs | Versions | Détails |
---|---|---|
Chrome 32+ | ||
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.
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 :
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.
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 :
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.
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 !
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