How to embed YouTube video in a webpage with a custom play-button, original poster at the best resolution and responsive container, keeping aspect ratio
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

il y a 3 ans
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. # styled-youtube-embedding-labwork
  2. > Embed YouTube video in a webpage with a custom play-button, original poster at the best resolution and responsive container, keeping aspect ratio.
  3. [Try it](https://chiefred.github.io/styled-youtube-embedding-labwork/) in action!
  4. Often we need to embed a YouTube video in a custom design (with a custom play button), but for that purpose, we only have the URL of that video. Let`s disassemble the task in several steps.
  5. ## Get \<id-of-video\> from URL
  6. YouTube video URLs can be provided in several formats, like:
  7. - https://youtu.be/jIHvgUAW5vE
  8. - https://youtu.be/jIHvgUAW5vE?t=2
  9. - https://www.youtube.com/embed/jIHvgUAW5vE
  10. - https://www.youtube.com/watch?v=jIHvgUAW5vE&ab_channel=MihaEr%C5%BEen
  11. In all the examples presented, the desired video identifier will be `jIHvgUAW5vE`. So, we need a way to extract it.
  12. In most cases, we will do this on the server side by regular expression and even in combination with check: if we have a valid YouTube video URL (of any format), then we can, for example, insert its poster image into the page.
  13. I will use PHP:
  14. ```php
  15. <? if (
  16. preg_match(
  17. '/[\/\=]{1}([a-zA-Z0-9_-]{11})([\?\&]{1}|$)/',
  18. $anyYouTubeVideoURL,
  19. $matches
  20. )
  21. ): ?>
  22. <img
  23. src="https://img.youtube.com/vi/<?=$matches[1]?>/maxresdefault.jpg"
  24. alt="video"
  25. />
  26. <? endif ?>
  27. ```
  28. ## Get the poster image for YouTube video
  29. As already shown above, poster image can be loaded from `img.youtube.com`. Best resolution images available at URLs like:
  30. ```html
  31. https://img.youtube.com/vi/<id-of-video>/maxresdefault.jpg</id-of-video>
  32. ```
  33. But in some cases they may not exist (when the original video was in low resolution).
  34. We can find the following variations of the image file names used:
  35. - maxresdefault
  36. - mqdefault
  37. - sddefault
  38. - hqdefault
  39. - default
  40. And we need to determine if the image exists or not. With the 404 error response, YouTube also transmits a default placeholder image, which prevents the `img` tag's `onerror` event handler from being called. Thus, we can only check the "natural dimensions" of the resulting image.
  41. The idea is to try to load the highest resolution image (`maxresdefault.jpg`) and test the result with onload script:
  42. ```html
  43. <img
  44. src="https://img.youtube.com/vi/<id-of-video>/maxresdefault.jpg"
  45. onload="window.youtube_img_load_check(this)"
  46. alt="video"
  47. />
  48. ```
  49. But before the `img` tag, we must register the `youtube_img_load_check` function in the `head` section of the web page:
  50. ```js
  51. window.youtube_img_load_check = function (e) {
  52. var thumbnail = [
  53. "maxresdefault",
  54. "mqdefault",
  55. "sddefault",
  56. "hqdefault",
  57. "default",
  58. ];
  59. var url = e.getAttribute("src");
  60. if (e.naturalWidth === 120 && e.naturalHeight === 90) {
  61. for (var i = 0, len = thumbnail.length - 1; i < len; i++) {
  62. if (url.indexOf(thumbnail[i]) > 0) {
  63. e.setAttribute("src", url.replace(thumbnail[i], thumbnail[i + 1]));
  64. break;
  65. }
  66. }
  67. }
  68. };
  69. ```
  70. If loading `maxresdefault.jpg` fails, the script will try the next option from the array. Etc.
  71. The default YouTube stub image size is 120 x 90 pixels. Thus, we can detect errors when checking the `naturalWidth` and `naturalHeight` of the resulting image.
  72. ## Preserve the aspect ratio of the poster image in a responsive design
  73. The YouTube documentation says, "The standard aspect ratio for YouTube on a computer is 16:9". And most videos are in this format.
  74. As I found, even videos with a 4:3 aspect ratio in most cases have a poster in 16:9 format, until `default.jpg` which 120x90 (same as 404 error image).
  75. Thus, we cannot determine the aspect ratio of the video when measuring the loaded poster. That's why I just think all YouTube videos in 16:9 format. The result for my cases is acceptable. Here is the layout.
  76. HTML:
  77. ```html
  78. <div class="youtube-video">
  79. <div class="youtube-video__aspect">
  80. <div class="youtube-video__wrapper">
  81. <img
  82. class="youtube-video__poster"
  83. src="https://img.youtube.com/vi/<id-of-video>/maxresdefault.jpg"
  84. onload="window.youtube_img_load_check(this)"
  85. alt="video"
  86. loading="lazy"
  87. />
  88. <div
  89. class="youtube-video__play-icon"
  90. data-link="https://www.youtube.com/embed/<id-of-video>"
  91. ></div>
  92. </div>
  93. </div>
  94. </div>
  95. ```
  96. CSS:
  97. ```css
  98. .youtube-video {
  99. width: 100%;
  100. }
  101. .youtube-video__aspect {
  102. width: 100%;
  103. height: 0;
  104. position: relative;
  105. padding-top: 56.25%; /* This line gives 16:9 aspect ratio */
  106. }
  107. .youtube-video__poster {
  108. width: 100%;
  109. height: 100%;
  110. position: absolute;
  111. top: 0;
  112. left: 0;
  113. }
  114. .youtube-video__wrapper {
  115. /* Needed to properly resize video */
  116. width: 100%;
  117. height: 100%;
  118. position: absolute;
  119. top: 0;
  120. left: 0;
  121. display: flex;
  122. justify-content: center;
  123. align-items: center;
  124. }
  125. .youtube-video__play-icon {
  126. ...;
  127. }
  128. .youtube-video__iframe {
  129. /* Needed to properly resize video */
  130. width: 100%;
  131. height: 100%;
  132. }
  133. ```
  134. ## Launch YouTube video player
  135. One final piece of the puzzle - we need to replace the poster image with a real YouTube player when the user hits the play button. This JS can be placed at the bottom of the page.
  136. ```js
  137. const videos = document.querySelectorAll(
  138. ".youtube-video .youtube-video__play-icon"
  139. );
  140. videos.forEach(function (video) {
  141. video.addEventListener("click", function (e) {
  142. const link = e.target.dataset.link || null;
  143. const parent = e.target.closest(".youtube-video__wrapper");
  144. if (link && parent) {
  145. parent.classList.add("loading");
  146. parent.innerHTML =
  147. '<iframe class="youtube-video__iframe" src="' +
  148. link +
  149. '?autoplay=1" frameborder="0" allowfullscreen' +
  150. 'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"' +
  151. "></iframe>";
  152. }
  153. });
  154. });
  155. ```
  156. You can optionally use the `.youtube-video__wrapper.loading` CSS selector to show the loading indicator.
  157. Now [try it](https://chiefred.github.io/styled-youtube-embedding-labwork/) in action!