├── .editorconfig ├── .github └── workflows │ └── lhci.yml ├── LICENSE ├── index.html ├── package-lock.json ├── package.json ├── readme.md ├── src ├── lite-yt-embed.css └── lite-yt-embed.js ├── testpage ├── poster-image-availability.html └── poster-image-summary.html ├── variants ├── custom-poster-image.html ├── js-api.html ├── multiple-embeds.html ├── params.html ├── pe.html ├── solo.html ├── title.html └── yt.html ├── vercel.json └── youtube-thumbnail-urls.md /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | trim_trailing_whitespace = true 9 | 10 | # prettier custom things 11 | quote_type = single 12 | max_line_length = 160 13 | 14 | [src/] 15 | indent_size = 4 16 | indent_style = space 17 | insert_final_newline = true 18 | -------------------------------------------------------------------------------- /.github/workflows/lhci.yml: -------------------------------------------------------------------------------- 1 | name: Build project and Run Lighthouse CI 2 | on: [push] 3 | jobs: 4 | lhci: 5 | name: Lighthouse CI 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - uses: actions/setup-node@v3 10 | with: 11 | node-version: 16 12 | - name: npm install, build 13 | run: | 14 | npm install 15 | - name: run Lighthouse CI 16 | run: | 17 | npm install -g @lhci/cli@0.12.x 18 | lhci autorun --collect.staticDistDir=./variants --upload.target=temporary-public-storage 19 | env: 20 | LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }} 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 Paul Irish 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | lite-youtube-embed 5 | 6 | 7 | 8 | 9 | 10 |

lite-youtube custom element

11 | 12 | 13 | 14 | 15 | 16 |

View isolated demos:

17 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lite-youtube-embed", 3 | "version": "0.3.3", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "lite-youtube-embed", 9 | "version": "0.3.3", 10 | "license": "Apache-2.0" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lite-youtube-embed", 3 | "version": "0.3.3", 4 | "description": "A faster youtube embed.", 5 | "license": "Apache-2.0", 6 | "main": "src/lite-yt-embed.js", 7 | "style": "src/lite-yt-embed.css", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/paulirish/lite-youtube-embed.git" 11 | }, 12 | "keywords": [ 13 | "youtube", 14 | "custom element", 15 | "web component" 16 | ], 17 | "author": "Paul Irish", 18 | "bugs": { 19 | "url": "https://github.com/paulirish/lite-youtube-embed/issues" 20 | }, 21 | "homepage": "https://github.com/paulirish/lite-youtube-embed#readme", 22 | "readme": "readme.md", 23 | "files": [ 24 | "src/**", 25 | "package.json", 26 | "package-lock.json", 27 | "readme.md" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Lite YouTube Embed [![NPM lite-youtube-embed package](https://img.shields.io/npm/v/lite-youtube-embed.svg)](https://npmjs.org/package/lite-youtube-embed) 2 | 3 | > #### Renders faster than a sneeze. 4 | 5 | Provide videos with a supercharged focus on visual performance. 6 | This custom element renders just like the real thing but approximately 224× faster. 7 | 8 | Demo: https://paulirish.github.io/lite-youtube-embed/ 9 | 10 | ## Comparison 11 | 12 | | Normal ` 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "github": { 3 | "silent": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /youtube-thumbnail-urls.md: -------------------------------------------------------------------------------- 1 | # Lo, the youtube placeholder image! 2 | ### (AKA the thumbnail, poster image, etc) 3 | 4 | YT thumbnails (eg https://i.ytimg.com/vi/ogfYd705cRs/sddefault.jpg) have multiple resolutions with the following widths: 5 | 6 | - `maxresdefault`: 1280px 7 | - `sddefault`: 640px 8 | - `hqdefault`: 480px (lol, naming is hard) 9 | - `mqdefault`: 320px 10 | - `default`: 120px 11 | 12 | There is [much internet debate](https://stackoverflow.com/q/2068344/89484) on the reliability of thumbnail URLs. And indeed, not every resolution thumbnail is available for every video. 13 | 14 | The Google I/O keynote video `ogfYd705cRs` is available in all, but the classic rickroll video (`lXMskKTw3Bc`) is missing maxresdefault. And poor ole "because of the lactose" `lQKdEdzHnfU` is missing the sddefault. (In many, but not all, cases, the deciding factor of having an sddefault is being published after ~2010.) 15 | 16 | ## Finding the right resolution to use 17 | 18 | Many folks have given up with a silver bullet and resort to using the YouTube Data API. 19 | 20 | amp-youtube also eschews using the API, so they just [try sddefault with a hqdefault fallback](https://github.com/ampproject/amphtml/blob/186d10a0adadcc8367aaa047b58598b587958946/extensions/amp-youtube/0.1/amp-youtube.js#L496-L527). 21 | 22 | I've started with using hqdefault from `i.ytimg` to optimize for origin reuse. 23 | 24 | ## Annoying Youtube 404 behavior 25 | 26 | When YouTube serves a response for a 404 thumbnail, they serve a true 404 response code (good), however they still serve [`content-type: image/jpeg` and valid JPEG data in the response body](https://stackoverflow.com/questions/58560120/why-do-image-and-picture-elements-display-images-despite-http-status-404). ([example](https://img.youtube.com/vi/lXMskKTw3Bc/maxresdefault.jpg)). I assume they do this to avoid people seeing broken image icons, but unfortunately this also means you can't rely on `img.onerror`. The linked SO post and [`amp-youtube` both](https://github.com/ampproject/amphtml/blob/186d10a0adadcc8367aaa047b58598b587958946/extensions/amp-youtube/0.1/amp-youtube.js#L519-L528) use `onload` plus a `naturalWidth` check to check instead. 27 | 28 | ## Aspect ratios 29 | 30 | `maxresdefault` and `mqdefault` are 30:17 (very close to 16:9, the HD standard aspect ratio). 31 | 32 | `sddefault`, `hqdefault`, `default` are 4:3. 33 | 34 | This difference ends up being mostly unimportant, in practice. The YT iframe is a 16:9 size by default. Using `background-position: center` ensures the (possible) black bars in the 4:3 images are hidden. 35 | 36 | ## WebP 37 | 38 | `https://i.ytimg.com/vi_webp/${videoid}/${width}.webp` 39 | 40 | I tested across some old and new videos and here's the best image they had available, counted: 41 | 42 | ``` 43 | "maxresdefault.webp (1280px)": 178, 44 | "sddefault.webp (640px)" : 21, 45 | "hqdefault.webp (480px)" : 8, 46 | "maxresdefault.jpg (1280px)" : 6, 47 | "sddefault.jpg (640px)" : 2, 48 | "hqdefault.jpg (480px)" : 89, 49 | ``` 50 | 51 | My test page (with a smaller set of test videos): https://paulirish.github.io/lite-youtube-embed/testpage/poster-image-summary.html 52 | 53 | I found no cases where it a smaller size was not available. For example, if they have the maxresdefault webp, then they definitely have the sddefault webp. 54 | 55 | All this means, it'd be very reasonable and efficient to try first for the `maxresdefault.webp`. If it isn't available (see annoying 404 behavior above), then fall back to `hqdefault.jpg`. 56 | 57 | In lite-youtube-embed's case though, we'll default to trying the `sddefault.webp` first, as that resolution is plenty for our uses. 58 | 59 | ## The best poster image for your video 60 | 61 | See https://paulirish.github.io/lite-youtube-embed/testpage/poster-image-availability.html 62 | 63 | 64 | --------------------------------------------------------------------------------