fix(html): simplify styles for slotted video (#953)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sam Potts
2026-03-15 22:41:46 +11:00
committed by GitHub
co-authored by Claude Opus 4.6
parent c39b1f8809
commit d6e471a837
12 changed files with 96 additions and 68 deletions
@@ -93,22 +93,24 @@ function getVideoTemplateHTML(attrs: Record<string, string>): string {
return /*html*/ `
<style>
:host {
display: inline-block;
line-height: 0;
display: contents;
}
video {
max-width: 100%;
max-height: 100%;
min-width: 100%;
min-height: 100%;
display: block;
width: 100%;
height: 100%;
border-radius: var(--media-video-border-radius);
object-fit: var(--media-object-fit, contain);
object-position: var(--media-object-position, 50% 50%);
object-position: var(--media-object-position, center);
}
video::-webkit-media-text-track-container {
transform: var(--media-webkit-text-track-transform);
transition: var(--media-webkit-text-track-transition);
transition: transform var(--media-caption-track-duration, 0) ease-out;
transition-delay: var(--media-caption-track-delay, 0);
transform: translateY(var(--media-caption-track-y, 0)) scale(0.98);
z-index: 1;
font-family: inherit;
}
</style>
<slot name="media">
+10 -12
View File
@@ -2,24 +2,22 @@ video-player {
display: contents;
}
video-player video,
video-player hls-video,
video-player simple-hls-video {
/*
Required to override any default video styles (such as Tailwind's CSS reset)
and ensure the video element fills the container as expected.
*/
video-player video {
display: block;
width: 100%;
height: 100%;
object-fit: var(--media-object-fit, contain);
object-position: var(--media-object-position, center);
}
video-player video::-webkit-media-text-track-container {
transition: transform var(--media-caption-track-duration, 150ms) ease-out;
transition-delay: var(--media-caption-track-delay, 600ms);
transition: transform var(--media-caption-track-duration, 0) ease-out;
transition-delay: var(--media-caption-track-delay, 0);
transform: translateY(var(--media-caption-track-y, 0)) scale(0.98);
z-index: var(--media-caption-track-z, 1);
z-index: 1;
font-family: inherit;
}
@media (prefers-reduced-motion: reduce) {
video-player video::-webkit-media-text-track-container {
transition-duration: 50ms;
}
}
+4
View File
@@ -1,3 +1,7 @@
media-tooltip-group {
display: contents;
}
:host {
display: grid;
}
@@ -3,6 +3,7 @@
========================================================================== */
.media-default-skin {
--media-caption-track-duration: 150ms;
--media-caption-track-delay: 600ms;
--media-caption-track-y: -0.5rem;
@@ -10,11 +11,15 @@
--media-caption-track-delay: 25ms;
--media-caption-track-y: -3.5rem;
}
@media (prefers-reduced-motion: reduce) {
--media-caption-track-duration: 50ms;
}
}
.media-default-skin video::-webkit-media-text-track-container {
/* NOTE: The delay must account for the controls delay/duration */
transition: transform 150ms ease-out;
transition: transform var(--media-caption-track-duration) ease-out;
transition-delay: var(--media-caption-track-delay);
transform: translateY(var(--media-caption-track-y)) scale(0.98);
z-index: 1;
@@ -7,9 +7,11 @@
display: block;
width: 100%;
height: 100%;
object-fit: var(--media-object-fit, contain);
object-position: var(--media-object-position, center);
}
.media-default-skin ::slotted(video) {
border-radius: var(--media-border-radius, 2rem);
border-radius: var(--media-video-border-radius);
}
.media-default-skin video {
border-radius: inherit;
@@ -24,7 +26,8 @@
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
object-fit: var(--media-object-fit, contain);
object-position: var(--media-object-position, center);
transition: opacity 0.25s;
pointer-events: none;
border-radius: inherit;
@@ -38,11 +41,7 @@
Fullscreen
========================================================================== */
.media-default-skin:fullscreen video,
.media-default-skin:fullscreen ::slotted(video),
.media-default-skin:fullscreen > img {
.media-default-skin:fullscreen video {
object-fit: contain;
}
.media-default-skin:fullscreen ::slotted(video) {
border-radius: 0;
}
+7 -1
View File
@@ -28,6 +28,7 @@
--media-surface-outer-border-color: oklch(0 0 0 / 0.1);
--media-surface-shadow-color: oklch(0 0 0 / 0.15);
--media-surface-backdrop-filter: blur(16px) saturate(1.5);
--media-video-border-radius: var(--media-border-radius, 2rem);
@media (prefers-color-scheme: dark) {
--media-border-color: oklch(1 0 0 / 0.1);
@@ -45,7 +46,7 @@
}
&:fullscreen {
border-radius: 0;
--media-border-radius: 0;
}
}
@@ -92,6 +93,11 @@
}
}
/* Hide cursor when controls are hidden in fullscreen */
.media-default-skin--video:fullscreen:has(.media-controls:not([data-visible])) {
cursor: none;
}
/* ==========================================================================
Sliders
========================================================================== */
@@ -21,41 +21,43 @@ export const root = (isShadowDOM: boolean) =>
'after:inset-0 after:ring-1 after:ring-inset after:ring-black/10 dark:after:ring-white/10',
// Video element
{
'[&_::slotted(video)]:block [&_::slotted(video)]:w-full [&_::slotted(video)]:h-full [&_::slotted(video)]:rounded-(--media-border-radius,2rem)':
'[&_::slotted(video)]:block [&_::slotted(video)]:w-full [&_::slotted(video)]:h-full [&_::slotted(video)]:rounded-(--media-video-border-radius) [&_::slotted(video)]:[object-fit:var(--media-object-fit,contain)] [&_::slotted(video)]:[object-position:var(--media-object-position,center)]':
isShadowDOM,
'[&_video]:block [&_video]:w-full [&_video]:h-full [&_video]:rounded-[inherit]': !isShadowDOM,
'[&_video]:block [&_video]:w-full [&_video]:h-full [&_video]:rounded-[inherit] [&_video]:[object-fit:var(--media-object-fit,contain)] [&_video]:[object-position:var(--media-object-position,center)]':
!isShadowDOM,
},
'[--media-video-border-radius:var(--media-border-radius,2rem)]',
// Poster image
'[&>img]:absolute [&>img]:inset-0 [&>img]:w-full [&>img]:h-full [&>img]:rounded-[inherit]',
'[&>img]:object-cover [&>img]:pointer-events-none',
'[&>img]:[object-fit:var(--media-object-fit,contain)] [&>img]:[object-position:var(--media-object-position,center)] [&>img]:pointer-events-none',
'[&>img]:transition-opacity [&>img]:duration-250',
'[&>img:not([data-visible])]:opacity-0',
// Caption track CSS variables (consumed by the native caption bridge in light DOM)
'[--media-caption-track-delay:600ms]',
'[--media-caption-track-y:-0.5rem]',
'[--media-caption-track-delay:600ms]',
'[--media-caption-track-duration:150ms]',
'motion-reduce:[--media-caption-track-duration:50ms]',
'has-[[data-controls][data-visible]]:[--media-caption-track-delay:25ms]',
'has-[[data-controls][data-visible]]:[--media-caption-track-y:-3.5rem]',
// Native caption track container
!isShadowDOM
? [
'[&_video::-webkit-media-text-track-container]:transition-transform',
'[&_video::-webkit-media-text-track-container]:duration-150',
'[&_video::-webkit-media-text-track-container]:duration-(--media-caption-track-duration)',
'[&_video::-webkit-media-text-track-container]:ease-out',
'[&_video::-webkit-media-text-track-container]:delay-(--media-caption-track-delay)',
'[&_video::-webkit-media-text-track-container]:translate-y-(--media-caption-track-y)',
'[&_video::-webkit-media-text-track-container]:scale-98',
'[&_video::-webkit-media-text-track-container]:z-1',
'[&_video::-webkit-media-text-track-container]:font-[inherit]',
'motion-reduce:[&_video::-webkit-media-text-track-container]:duration-50',
]
: [],
// Fullscreen
'[&:fullscreen]:rounded-none',
'[&:fullscreen]:[--media-border-radius:0]',
{
'[&:fullscreen_video]:object-contain': !isShadowDOM,
'[&:fullscreen_::slotted(video)]:object-contain [&:fullscreen_::slotted(video)]:rounded-none': isShadowDOM,
},
'[&:fullscreen>img]:object-contain'
'[&:fullscreen_::slotted(video)]:object-contain': isShadowDOM,
}
);
/* ==========================================================================
@@ -3,6 +3,7 @@
========================================================================== */
.media-minimal-skin {
--media-caption-track-duration: 150ms;
--media-caption-track-delay: 600ms;
--media-caption-track-y: -0.5rem;
@@ -10,19 +11,17 @@
--media-caption-track-delay: 25ms;
--media-caption-track-y: -3rem;
}
@media (prefers-reduced-motion: reduce) {
--media-caption-track-duration: 50ms;
}
}
.media-minimal-skin video::-webkit-media-text-track-container {
/* NOTE: The delay must account for the controls delay/duration */
transition: transform 150ms ease-out;
transition: transform var(--media-caption-track-duration) ease-out;
transition-delay: var(--media-caption-track-delay);
transform: translateY(var(--media-caption-track-y)) scale(0.98);
z-index: 1;
font-family: inherit;
}
@media (prefers-reduced-motion: reduce) {
.media-minimal-skin video::-webkit-media-text-track-container {
transition-duration: 50ms;
}
}
@@ -7,9 +7,11 @@
display: block;
width: 100%;
height: 100%;
object-fit: var(--media-object-fit, contain);
object-position: var(--media-object-position, center);
}
.media-minimal-skin ::slotted(video) {
border-radius: var(--media-border-radius, 0.75rem);
border-radius: var(--media-video-border-radius);
}
.media-minimal-skin video {
border-radius: inherit;
@@ -24,10 +26,11 @@
inset: 0;
width: 100%;
height: 100%;
border-radius: inherit;
object-fit: cover;
object-fit: var(--media-object-fit, contain);
object-position: var(--media-object-position, center);
transition: opacity 0.25s;
pointer-events: none;
border-radius: inherit;
&:not([data-visible]) {
opacity: 0;
@@ -38,11 +41,7 @@
Fullscreen
========================================================================== */
.media-minimal-skin:fullscreen video,
.media-minimal-skin:fullscreen ::slotted(video),
.media-minimal-skin:fullscreen > img {
.media-minimal-skin:fullscreen video {
object-fit: contain;
}
.media-minimal-skin:fullscreen ::slotted(video) {
border-radius: 0;
}
+7 -1
View File
@@ -22,6 +22,7 @@
.media-minimal-skin--video {
background: oklch(0 0 0);
--media-border-color: oklch(0 0 0 / 0.15);
--media-video-border-radius: var(--media-border-radius, 0.75rem);
@media (prefers-color-scheme: dark) {
--media-border-color: oklch(1 0 0 / 0.15);
@@ -40,7 +41,7 @@
/* Fullscreen */
&:fullscreen {
border-radius: 0;
--media-border-radius: 0;
}
}
@@ -90,6 +91,11 @@
}
}
/* Hide cursor when controls are hidden in fullscreen */
.media-minimal-skin--video:fullscreen:has(.media-controls:not([data-visible])) {
cursor: none;
}
/* ==========================================================================
Sliders
========================================================================== */
@@ -19,41 +19,43 @@ export const root = (isShadowDOM: boolean) =>
'dark:after:ring-white/15',
// Video element
{
'[&_::slotted(video)]:block [&_::slotted(video)]:w-full [&_::slotted(video)]:h-full [&_::slotted(video)]:rounded-(--media-border-radius,0.75rem)':
'[&_::slotted(video)]:block [&_::slotted(video)]:w-full [&_::slotted(video)]:h-full [&_::slotted(video)]:rounded-(--media-video-border-radius) [&_::slotted(video)]:[object-fit:var(--media-object-fit,cover)] [&_::slotted(video)]:[object-position:var(--media-object-position,center)]':
isShadowDOM,
'[&_video]:block [&_video]:w-full [&_video]:h-full [&_video]:rounded-[inherit]': !isShadowDOM,
'[&_video]:block [&_video]:w-full [&_video]:h-full [&_video]:rounded-[inherit] [&_video]:[object-fit:var(--media-object-fit,contain)] [&_video]:[object-position:var(--media-object-position,center)]':
!isShadowDOM,
},
'[--media-video-border-radius:var(--media-border-radius,0.75rem)]',
// Poster image
'[&>img]:absolute [&>img]:inset-0 [&>img]:w-full [&>img]:h-full [&>img]:rounded-[inherit]',
'[&>img]:object-cover [&>img]:pointer-events-none',
'[&>img]:[object-fit:var(--media-object-fit,contain)] [&>img]:[object-position:var(--media-object-position,center)] [&>img]:pointer-events-none',
'[&>img]:transition-opacity [&>img]:duration-250',
'[&>img:not([data-visible])]:opacity-0',
// Caption track CSS variables (consumed by the native caption bridge in light DOM)
'[--media-caption-track-delay:600ms]',
'[--media-caption-track-y:-0.5rem]',
'[--media-caption-track-delay:600ms]',
'[--media-caption-track-duration:150ms]',
'motion-reduce:[--media-caption-track-duration:50ms]',
'has-[[data-controls][data-visible]]:[--media-caption-track-delay:25ms]',
'has-[[data-controls][data-visible]]:[--media-caption-track-y:-3.5rem]',
// Native caption track container
!isShadowDOM
? [
'[&_video::-webkit-media-text-track-container]:transition-transform',
'[&_video::-webkit-media-text-track-container]:duration-150',
'[&_video::-webkit-media-text-track-container]:duration-(--media-caption-track-duration)',
'[&_video::-webkit-media-text-track-container]:ease-out',
'[&_video::-webkit-media-text-track-container]:delay-(--media-caption-track-delay)',
'[&_video::-webkit-media-text-track-container]:translate-y-(--media-caption-track-y)',
'[&_video::-webkit-media-text-track-container]:scale-98',
'[&_video::-webkit-media-text-track-container]:z-1',
'[&_video::-webkit-media-text-track-container]:font-[inherit]',
'motion-reduce:[&_video::-webkit-media-text-track-container]:duration-50',
]
: [],
// Fullscreen
'[&:fullscreen]:rounded-none',
'[&:fullscreen]:[--media-border-radius:0]',
{
'[&:fullscreen_video]:object-contain': !isShadowDOM,
'[&:fullscreen_::slotted(video)]:object-contain [&:fullscreen_::slotted(video)]:rounded-none': isShadowDOM,
},
'[&:fullscreen>img]:object-contain'
'[&:fullscreen_::slotted(video)]:object-contain': isShadowDOM,
}
);
/* ==========================================================================
+8 -2
View File
@@ -25,9 +25,15 @@ export default function HeroVideo({
<Player.Provider>
<SkinComponent
className={className}
style={{ '--media-border-radius': `calc(var(--spacing) * 6)`, ...style } as React.CSSProperties}
style={
{
'--media-border-radius': `calc(var(--spacing) * 6)`,
'--media-object-fit': 'cover',
...style,
} as React.CSSProperties
}
>
<HlsVideo src={VJS10_DEMO_VIDEO.hls} playsInline className="object-cover" />
<HlsVideo src={VJS10_DEMO_VIDEO.hls} playsInline />
<Poster src={poster} />
</SkinComponent>
</Player.Provider>