angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.23k stars 6.7k forks source link

bug(Youtube player): width not responsive #28829

Open Eraldo opened 3 months ago

Eraldo commented 3 months ago

Is this a regression?

The previous version in which this bug was not present was

I only noticed it after a couple of upgrades, so I don't know exactly.

Description

Related: https://github.com/angular/components/issues/28489 However the workarounds that are mentioned there don't work anymore.

Setting width="100%" does not work as the input is transformed into a number type: https://github.com/angular/components/blob/main/src/youtube-player/youtube-player.ts#L148

What is the solution approach to get the component to display responsively so it shows up correctly on both mobile and desktop?

Reproduction

StackBlitz link: https://stackblitz.com/edit/angular-youtube-player-responsive-issue?file=src%2Fmain.ts Steps to reproduce:

  1. Open the StackBlitz link
  2. Optionally make the preview window smaller.
  3. Check the browser preview to confirm that the video is overflowing the page width.

Expected Behavior

It shoult take the whole width of the screen

Actual Behavior

The video overflows the with of its parent elements.

Environment

kevinriemens commented 3 months ago

Anyone looking for a temporary fix until the bug is resolved:

StepaZol commented 2 months ago

Now only the width and height numbers work, because now the check happens like this this._height = height == null || isNaN(height) ? DEFAULT_PLAYER_HEIGHT : height;

you can create a responsive container and use ResizeObserver to get its size. for example

function resizeObservable(elem: Element, options?: ResizeObserverOptions): Observable<ResizeObserverEntry> { return new Observable((subscriber) => { const resizeObserver = new ResizeObserver(([entry]) => { subscriber.next(entry); }); resizeObserver.observe(elem, options); return function unsubscribe(): void { resizeObserver.unobserve(elem); }; }); }

and in component

<div #playerContainer style="width=50%; height: 50%"><youtube-player [height]="playerHeight()" [width]="playerWidth()" [videoId]="videoId"></youtube-player>

@ViewChild('playerContainer', {static: true}) public playerContainerRef?: ElementRef<HTMLElement>; public playerWidth = signal(NaN); public playerHeight = signal(NaN); ngOnInit(): void { if (this.playerContainerRef) { resizeObservable(this.playerContainerRef.nativeElement) .pipe( map(({ contentRect: { height, width } }) => ({ height, width })), distinctUntilChanged((a, b) => a.height === b.height && a.width === b.width), takeUntilDestroyed(this.destroyRef), ) .subscribe(({height,width}) => { this.playerHeight.set(height); this.playerWidth.set(width); }); } }

Eraldo commented 2 months ago

For now I created a custom component with a wrapper and I'm setting the wrapper height and width on it instead of the angular video player component. And then I set the iframe full width/height.

  youtube-player > *,
  youtube-player iframe {
    width: 100% !important;
    height: 100% !important;
  }

This is a another workaround it seems. I'm still looking forward to having an official way to do it. ;)

mattiLeBlanc commented 1 month ago

I am also experiencing this issue. Before I was able to set width 100%, now it defaults to 640 because it is no longer a number. Thanks for the worksarounds. I hope the maintainer can allow us to use width 100% again.

MarcoGlauser commented 4 weeks ago

We ran into the same issue that youtube videos stopped being responsive. Looks like the issue originated with this commit https://github.com/angular/components/commit/381a65f33d87c885235d2076297f092d6c218bae . Technically, only pixel values are allowed for width/height according to the html5 spec, so this change makes sense. However, browsers seem to tolerate % values. Any thoughts @crisbeto ?

hassmal commented 2 weeks ago

The proposed workarounds seem to mess with aspect ratio or require typescript, so here is another one that only uses css and keeps a fixed aspect ratio:

youtube-player {
  position: relative;
  padding-top: 56.25%; // 16:9 ratio
}

:host ::ng-deep youtube-player > *, {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%!important;
  height: 100%!important;
}

:host ::ng-deep youtube-player iframe {
  width: 100% !important;
  height: 100% !important;
}

One downside: you need to know the aspect ratio beforehand and calculate padding-top on the youtube-player styling accordingly.

Please fix this, responsiveness should be supported by default in 2024.