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.
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 n'es pas encore complète à l'heure actuelle.
Tableau des compatibilités object-fit
Navigateurs | Versions | Détails |
---|---|---|
- Pas de support pour l'instant (ni Explorer ni Edge) | ||
Firefox 36+ |
|
|
Chrome 31+ Chrome Mobile 55+ |
||
Opera 19+ Opera Mobile 12.1+ |
||
Safari 8+ |
- Avant Safari 10, |
|
Android Browser 4.4.4+ |
|
À moins de laisser tomber complètement Internet Explorer, nous allons devoir trouver 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 :
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 :
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 est plus performante pour les navigateurs qui la reconnaissent 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.
Commentaires
Merci à l'auteur et au traducteur pour ce très bel article :)
Merci pour ces informations claires. Est-il possible de placer une vidéo provenant de Viméo ou Youtube avec cette technique?
@dubuismedia http://www.seanmccambridge.com/tubular/
@dubuismedia : Oui et non (et plutôt non). Ce que Vimeo et YouTube fournissent comme contenu à intégrer (embedded), ce sont des scripts JS qui vont générer soit un élément VIDEO (HTML5), soit un élément OBJECT ou EMBED appelant une application Flash. Donc la technique ne peut pas être utilisée telle quelle. Tu peux éventuellement adapter cette technique pour créer un conteneur tel qu’un DIV, et utiliser une technique de centrage horizontal (simple) ou vertical (un peu plus compliqué) pour centrer les éléments générés par le script de Vimeo ou YouTube (VIDEO ou OBJECT ou EMBED ou même une DIV contenant l’un de ces éléments).
Donc ça peut s’adapter, avec un minimum de travail. (Les outils de développement des navigateurs, et de nombreux tests, sont tes amis.)
Le problème, c’est que ces scripts génèrent aussi toute une interface avec informations, boutons de contrôle, etc. Et si une partie de la vidéo dépasse du viewport (ce qui est nécessaire pour notre technique de fond de page, donc ça sera le cas…), ces éléments d’interfaces vont être coupés, et pour l’utilisateur final l’affichage de ta vidéo aura l’air plus bugué qu’autre chose. Donc je ne recommande pas.
Autant une image d'arrière plan prend toute sa légitimité esthétique en mode portrait, autant une vidéo en a beaucoup moins car les images cinématographiques ne sont pas destinées à être regardées dans le sens vertical. A-t-on déjà vu un écran de cinéma plus haut que large ?
Même s'il s'agit ici de considérer la vidéo comme un élément de décoration plus qu'autre chose, le choix ne me semble pas pertinent, surtout s'il s'agit d'adapter la vidéo à tous les formats d'écran.
Je remercie en tous cas l'auteur d'avoir signalé qu'il était possible de ne pas utiliser le mode portrait pour le cas des vidéos. Peut-être aurait-il fallu le souligner davantage ?
Super tuto où je découvre également un exemple concret de @supports! Admettons que la propriété object-fit s'implante dans tous les navigateurs, cela voudrait dire qu'elle remplacerait la propriété background-size si je comprend bien ?
@Interned : Ce n’est effectivement pas un article du type «je prends le lecteur par la main pour lui expliquer la vie». :) Il présente juste une astuce technique, et suppose un minimum de connaissance (ou une volonté de se renseigner) sur l’élément VIDEO en HTML5 et sur les Media Queries en CSS. Côté design, l’article ne cherche pas à conseiller quoi que ce soit ou suppléer à l’incompétence du lecteur. ^^
En l’occurrence, j’ai imaginé cette technique pour le site de présentation d’un film indépendant. La bande-annonce est affichée, sur demande (clic sur un bouton) en fond de page, en gardant uniquement le logo du site en surimpression. Sur les écrans en format portrait, la vidéo est affichée avec des bandes noires, ce qui s’obtient simplement en laissant l’élément VIDEO prendre 100% de la hauteur et de la largeur du viewport (sans dépassement). Côté CSS, on rend les deux Media Queries plus restrictives avec une condition supplémentaire:
@media (orientation: landscape) and (min-aspect-ratio: 16/9) {…}
@media (orientation: landscape) and (max-aspect-ratio: 16/9) {…}
Et de même pour l’utilisation d’object-fit, à restreindre:
@supports (object-fit: cover) {
@media (orientation: landscape) {…}
}
Une question qui s’est posée côté design, c’est de savoir si la présentation d’une vidéo 16/9e dans un format qui peut être plus haut (4/3, voire un format s’approchant du carré) avec des côtés rognés est acceptable. Ce n’est bien sûr pas un respect strict du format du film. En l’occurrence, l’effet a été jugé intéressant car immersif, permettant de faire un lien entre les qualités du film et celles du design du site (qu’on espère pas trop pire ^^). Dans d’autres cas on pourra juger que non, jamais de la vie, on veut l’image intégrale et pas rognée car ça nuit au film / fait insulte à l’auteur / etc. À noter qu’on opte pour cette solution pour une bande-annonce, mais on ne le ferait pas pour un film intégral, y compris pour un court-métrage.
(Point droit d’auteur français: recadrer une vidéo ou une photo peut être une atteinte au droit moral de l’auteur/autrice.)
@lj44 : Non, object-fit ne remplace pas du tout background-size. Ces deux propriétés se ressemblent, mais elles ne s’appliquent pas aux mêmes éléments.
• background-size et background-position: pour les images de fond.
• object-fit et object-position: pour les éléments IMG et VIDEO.
Ok merci Florent! J'ai saisi la nuance ;)
@Interned : A-t-on déjà vu des créatifs s'arrêter à ce genre de considérations ? ^^
J'ai lu hier un article d'A List Apart avec 6 vidéos plus hautes que larges et je tombe aujourd'hui sur ton commentaire donc je te fais profiter de ce cas d'usage : http://alistapart.com/article/the-z-axis-desi... L'usage est créatif (reproduire fidèlement les animations d'une page web), les vidéos elles-mêmes n'ont rien de cinématographiques... Mais il n'y a pas que le cinéma comme usage des vidéos !
Merci beaucoup pour cet excellent article :)
Une petite question : cela est-il compatible sur smartphones et tablettes ?
Merci pour ce tuto.
Quand je teste l’exemple sur IE11 mode Edge ouvert en plein écran, la vidéo ne s'affiche pas au chargement de la page, mais lorsque je redimensionne le navigateur, le script fonctionne ;) Une idée ? Une alternative ?
Merci
Merci pour ce super billet. Je suis tombé sur ce codePen plutôt sympa pour utiliser object-fit avec un fallback pour IE
https://codepen.io/arniebradfo/pen/eFtdf
Si ça peut en aider quelques uns :)