skip to Main Content

I have below example where I am trying to render a YouTube card. The issue I am facing is that the play button white background is not adjusting into the play icon that I am setting through my CSS styles. I am trying to undertand why that is not working.

Also, when I hover the card, I should see a background that says Video Test, but that never gets rendered.

https://stackblitz.com/edit/ndu1t6?file=src%2Fexample.tsx,src%2FYoutubeCard.tsx

Why is this part giving the trouble?

'&:hover': {
  transform: 'scale(1.05)',
  boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)',
},
'&:hover $overlay': {
  backgroundColor: 'rgba(0, 0, 0, 0.6)',
},
'&:hover $textOverlay': {
  opacity: 1,
},
'&:hover $playButton': {
  opacity: 0,
},

2

Answers


  1. I tried many ways to handle the nested code issue and checked the documentation, but I could not find any way to style the child on parent hover inside makeStyles. Finally, I use a similar package called react-jss to style elements.

    NOTE: Some property is not working because they are override by fluent ui so I have added !important in many properties without it properties will not be applied.

    You can use react-jss package to achieve your output:

    Install react-jss package:

    npm i react-jss
    
    // YoutubeCard.styles.tsx
    import { createUseStyles } from "react-jss"
    
    const useStyles = createUseStyles({
        card: {
            width: "300px",
            border: "1px solid #ccc",
            borderRadius: "8px",
            overflow: "hidden",
            position: "relative",
            cursor: "pointer",
            transition: "transform 0.3s, box-shadow 0.3s",
            "&:hover": {
                transform: "scale(1.05)",
                boxShadow: "0 4px 8px rgba(0, 0, 0, 0.2)",
                "& $overlay": {
                    backgroundColor: "rgba(0, 0, 0, 0.6)",
                },
                "& $textOverlay": {
                    opacity: 1,
                },
                "& $playButton": {
                    opacity: 0,
                },
            },
        },
        overlay: {
            position: "absolute",
            top: 0,
            left: 0,
            width: "100%",
            height: "100%",
            backgroundColor: "rgba(0, 0, 0, 0)",
            transition: "background-color 0.3s",
        },
        textOverlay: {
            position: "absolute",
            top: "50%",
            left: "50%",
            transform: "translate(-50%, -50%)",
            color: "white",
            opacity: 0,
            transition: "opacity 0.3s",
    
            height: "100%",
            display: "flex !important", // Without !important property override
            flexDirection: "column",
            justifyContent: "center",
            alignItems: "center",
            textAlign: "center",
        },
        playButton: {
            position: "absolute",
            top: "50%",
            left: "50%",
            width: "3rem !important",
            height: "3rem !important",
            display: "flex !important",
            justifyContent: "center",
            alignItems: "center",
            transform: "translate(-50%, -50%)",
            backgroundColor: "rgba(255, 255, 255, 0.8)",
            borderRadius: "50%",
            transition: "opacity 0.3s",
        },
        playButtonTriangle: {
            width: "50%",
            height: "50%",
            backgroundColor: "red",
            marginLeft: ".5rem",
            clipPath: "polygon(78% 52%, 0 0, 0 100%)",
        },
    })
    
    export default useStyles
    
    // YoutubeCard.tsx
    import { Card, CardPreview, Image } from "@fluentui/react-components"
    import * as React from "react"
    import useStyles from "./YoutubeCard.styles"
    
    export type YoutubeCardProps = {
        card: string
    }
    
    export const YoutubeCard: React.FC<YoutubeCardProps> = React.memo((_) => {
        const videoId = "h3BKjZMGoIw"
        const thumbnailUrl = `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`
        const styles = useStyles()
    
        const handleCardClick = () => {
            window.open(`https://www.youtube.com/watch?v=${videoId}`, '_blank');
        }
    
        return (
            <Card className={styles.card} onClick={handleCardClick}>
                <CardPreview>
                    <Image
                        src={thumbnailUrl}
                        alt="YouTube Thumbnail"
                        style={{ width: "100%" }}
                    />
                    <div className={styles.overlay}></div>
                    <div className={styles.textOverlay}>
                        <p>Video Test</p>
                        <p>Vide Test Test</p>
                    </div>
                    <div className={styles.playButton}>
                        <div className={styles.playButtonTriangle}></div>
                    </div>
                </CardPreview>
            </Card>
        )
    })
    
    YoutubeCard.displayName = "YoutubeCard"
    
    Login or Signup to reply.
  2. I think the underlying issues are:

    1. Specificity: some of your styled are being overwritten by the fluentui css styled. By adding !important you can force your styles to be used.
    2. The overlay, textOverlay and playButton should probably not be seperated into sibling div-elements, instead you can group them together.

    Here is my code (although the styling might not be exactly what you intended to do):

    import { makeStyles } from '@fluentui/react-components';
    
    export const useVideoYoutubeCardStyles = makeStyles({
        card: {
            width: '300px',
            border: '1px solid #ccc',
            borderRadius: '8px',
            overflow: 'hidden',
            position: 'relative',
            cursor: 'pointer',
            transition: 'transform 0.3s, box-shadow 0.3s',
            '&:hover': {
                transform: 'scale(1.05)',
                boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)',
            },
        },
        overlay: {
            position: 'absolute',
            top: '0px',
            width: '100%',
            height: '100%',
            backgroundColor: 'rgba(0, 0, 0, 0)',
            transition: 'background-color 0.3s',
            '&:hover': {
                // backgroundColor: 'rgba(0, 0, 0, 0.6)', <-- moved this to textOverlay:hover
            },
        },
        textOverlay: {
            position: 'absolute',
            top: '50%',
            left: '50%',
            transform: 'translate(-50%, -50%)',
            color: 'white',
            fontSize: '14px',
            fontWeight: 100,
            textAlign: 'center',
            opacity: 0,
            transition: 'opacity 0.3s',
            fontFamily: 'Arial, sans-serif',
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
            justifyContent: 'center',
    
            '&:hover': {
                opacity: 1,
                backgroundColor: 'rgba(0, 0, 0, 0.6)' //<-- this comes from overlay
            },
        },
        playButton: {
            position: 'absolute',
            top: '30%',
            left: '30%',
            width: '100px !important', //<-- add !important because they are otherwise being overwritten
            height: '100px !important', //<-- add !important because they are otherwise being overwritten
            backgroundColor: 'rgba(255, 255, 255, 0.8)',
            borderRadius: '50%',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
            transition: 'opacity 0.3s',
        },
        playButtonTriangle: {
            position: 'absolute',
            left: '37px',
            top: '28px',
            width: '30px',
            height: '0px',
            borderLeft: '30px solid gray',
            borderTop: '20px solid transparent',
            borderBottom: '20px solid transparent',
            marginLeft: '3px',
        },
    });
    import { Card, CardPreview, Image } from '@fluentui/react-components';
    import * as React from 'react';
    import { useVideoYoutubeCardStyles } from './YoutubeCard.styled.tsx';
    
    export type YoutubeCardProps = {
        card: string;
    };
    export const YoutubeCard: React.FC<YoutubeCardProps> = React.memo((_) => {
        const styles = useVideoYoutubeCardStyles();
        const videoId = 'h3BKjZMGoIw';
        const thumbnailUrl = `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`;
    
        const handleCardClick = () => {
            window.open(`https://www.youtube.com/watch?v=${videoId}`, '_blank');
        };
    
        return (
            <Card className={styles.card} onClick={handleCardClick}>
                <CardPreview>
                    <Image
                        src={thumbnailUrl}
                        alt="YouTube Thumbnail"
                        style={{ width: '100%' }}
                    />
                    {/*black overlay when hovering*/}
                    <div className={styles.overlay}></div>
                    <div id="textOverlay" className={styles.textOverlay}>
                        <p style={{margin: 0}}>Video Test</p>
                        <div id="playButton" className={styles.playButton}>
                            <div className={styles.playButtonTriangle}></div>
                        </div>
                        {/*    <p style={{ margin: 0 }}>Vide Test Test</p>*/}
                    </div>
                </CardPreview>
            </Card>
        );
    });
    
    YoutubeCard.displayName = 'YoutubeCard';
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search