ARTICLE AD BOX
I'm making a Hero section for a website I'm building that uses 16:9 aspect ratio images as its background. At final production I will have 3-4 image slideshow as a background (pulled remotely), so I need to use Next/Image to handle this.
Here are the following behaviors I want achieved:
1. Keep the images original 16/9 aspect ratio as long as there's enough screen width; as the screen size shrinks (from resizing or using small devices), crop the image without warping/deforming it; finally, on smartphones, crop it to 1/1 aspect ratio (or 3:4, iPad portrait view or 5:3 DVD/book case) without warping/deforming it.
1.1. Have a gradient overlaying the image that's the exact same height as the image itself
1.2 With these 2 on the same <div> container, have them placed below the text that'll be overlaying them.
- See Appendix 1 the following GIF for all these behaviors combined (click here for website link):

2. Although the image should be the full width & height on computer screens, its size must be restricted once the user's screen's aspect ratio is very wide past 16:9 width-wise (think 21:9 ultrawide monitor screens, or when zooming out); that'll mean applying a max-width on the root HTML body and the image must respect that.
- See Appendix 2.1 & 2.2 to see this behavior (website link for GIF 1 and GIF2):


As well-defined as my own requirements are, I've been nowhere close into achieving the following behaviours in my own website while using Next.js's Image component:

- The image is a block element, so it won't place under the text
- the gradient is taller than the image
- The image(s) is 100vw & 100vh regardless how zoomed out I am (and it's not intended to be setup that way at all)
I've been banging my head at this problem for 3 days now and I'm just burnt out on how to programmatically get what I want. I kindly ask if anyone can help me here.
Just for reference (not exactly what it'll look like at the code down below), this is a screenshot from an older version of my Hero Section (1 week ago) that I want the Hero Section to look like

(sadly I had to scrap this version, for the image is neither responsive nor respecting the website's max-width constraint nor its parent container's size due to the fill={true} property on the <Image> tag. But conceptually - I mean conceptually and visually - this is how I want my hero section to look like.)
BTW before posting your answers, I wish that your setup is exactly the same as mine so your code will work flawlessly. Please use the following next-create-app settings to make it like mine

P.S. Please install sass as well via pnpm
All right! Below are the following code blocks in order (I pray it's not too convoluted):
globals.scss layout.tsx heroSection.tsx heroSection.module.scss page.tsx [where the HeroSection() is used] /* NOTE(s): - This file is renamed from "globals.css" to "globals.scss" - Minimal change is made to ensure I can default back to Next's default styling when mine breaks - In cases wherein I must make changes to styling, new classes & IDs are made to use those instead. */ :root { // Next.js defaults --background: hsl(0, 0%, 100%); --foreground: hsl(0, 0%, 9%); /******************************** CUSTOM VARIABLES FOR THIS WEBSITE ********************************/ --defaultBorderRadius: 8px; --navigationBarHeight: 54px; --maxScreenWidth: 1280px; // Plan for this is to limit screen size to 16 / 9 aspect ratio } @media (prefers-color-scheme: dark) { // Next.js defaults // I merged the two @media queries into just one :root { --background: hsl(0, 0%, 4%); --foreground: hsl(0, 0%, 93%); } html { color-scheme: dark; } } html, body { /* Next.js defaults - "overflow-x" is not used as it breaks horizontal scrolling on the final website - https://stackoverflow.com/questions/47095596/body-overflow-x-hidden-breaks-position-sticky */ max-width: 100vw; // overflow-x: hidden; // This breaks the NavigationBar(), wherein the sticky property is ignored overflow-x: clip; } body { // Next.js defaults color: var(--foreground); background: var(--background); // background: black; font-family: Arial, Helvetica, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } * { // Next.js defaults box-sizing: border-box; padding: 0; margin: 0; } a { // Next.js defaults color: inherit; text-decoration: none; } /*************************************** CLASSES & IDS TAILORED FOR THIS WEBSITE ***************************************/ .pageStructure { /* - This sets the final layout of every page of this website - It's used at the top-level by "@/app/layout.tsx" - The rest can go either way - in "layout.tsx" or in any "page.tsx" file */ display: grid; grid-template-columns: 1fr; grid-auto-rows: auto; } .sectionHeight { /* - Setting to make every <div> section to be as tall as the current screen - May come into future conflicts, but this is the current settings */ min-height: 100vh; } .sectionPadding { /* - This sets the padding on all pages - However, it's only applied to each <div> blocks on each page - As applying this on the root element may possibly break the current page's background */ padding: 8px 20px; } .navigationBarSpacer { /* - The idea is that each page is given the spacing of the navigation bar - This is so that content won't look squish/short as user scrolls down the page */ padding-top: var(--navigationBarHeight); } .limitPageSize { /* Preferably this is where aspect ratio is limit to 16:9, but I'm at my wit's end on this */ max-width: 1280px; margin: 0 auto; // background-color: aqua; } export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <body className={`${geistSans.variable} ${geistMono.variable} pageStructure`} > <NavigationBar /> <div>{children}</div> // this is just the HeroSection() {/* <div className={"limitPageSize"}>{children}</div> */} {/* <FooterSection /> */} </body> </html> ); } import styles from "./heroSection.module.scss"; import Image from "next/image"; export default function HeroSection() { const backgroundWidth = 800, backgroundHeight = backgroundWidth / (16 / 9); return ( <main className={`${styles.main} sectionHeight`}> <div className={styles.bannerContainer}> <div id={styles.gradient}></div> {/** * When trying this, use the following picturs linked from below as your "src": * - https://drive.usercontent.google.com/download?id=1mpHFsyhonKg0JbR3oSgNuCaOIisrDTLf&exp * - https://drive.usercontent.google.com/download?id=12wBe8M3QPwLFZ5Jj0qpCXJKsNz9ajl3D&exp * * Credits belong to "elaymm4 (aka Laymer)" * Find it hosted here: * - https://sites.google.com/view/hot-pursuit-challenges/media * * In final production, the site will be having a slideshow * of 4-6 images retrieved remotely (from AWS, Vercel or something similar) */} <Image src="/background/HPC-Wallpaper-KeyartOld-Desktop.png" alt="background" id={styles.image} // fill={true} width={backgroundWidth} height={backgroundHeight} /> </div> <div className={`${styles.heroTextSection} sectionPadding`}> <div id={styles.heroTitle}> <h1>Lorem ipsum dolor sit amet.</h1> </div> <div id={styles.heroDescription}> <h2>Ipsum qui repudiandae cumque est commodi, rem nihil vel a in!</h2> </div> <div id={styles.heroMoreInfo}> <p> Lorem ipsum dolor, sit amet consectetur adipisicing elit. Sit deleniti expedita et aliquam placeat ullam totam molestias ipsam quibusdam beatae numquam odio autem similique natus delectus eius ratione, soluta voluptate. Lorem ipsum dolor sit amet consectetur adipisicing elit. Facilis delectus reprehenderit quam omnis, minima autem eius, ipsum nisi quod totam natus. Dolore ad distinctio eum iure animi corporis deserunt numquam. </p> </div> </div> </main> ); } $textSectionWidth: 55%; .main { // Text color color: white; // max-height: 70vh; } .bannerContainer { width: 100%; height: auto; background: green; #image { z-index: -999; // Make image brighter filter: brightness(105%); /* Size properties - Make image fill entire width; auto-adjust height - Make image 16 / 9 aspect ratio (by defafult) - Crop image to 1 / 1 aspect ratio on smartphones */ width: 100%; height: 100%; aspect-ratio: 16 / 9; object-fit: "cover"; // display: block; } #gradient { height: 100%; width: 100%; position: absolute; // display: block; /* In short: - Have a gradient from left "to right" to make text visible - Have a gradient from bottom "to top" to make image blend with the background color (set in globals.scss) */ background: linear-gradient( to right, black -10%, hsla(0, 0%, 0%, 0) $textSectionWidth ), linear-gradient(to top, black 10%, hsla(0, 0%, 0%, 0) 25%); } } .heroTextSection { // display: none; // visibility: hidden; z-index: 999; display: grid; grid-template-columns: 1fr; grid-template-rows: repeat(2, 1fr); place-content: center; width: calc($textSectionWidth - 5%); // width: $textSectionWidth; #heroTitle { * { // Make the text LARGE and BOLD font-size: 3.8rem; font-weight: 900; } } #heroDescription { * { font-size: 2rem; } } #heroMoreInfo { width: 80%; * { text-align: justify; color: hsl(0, 0%, 90%); } font-size: 14px; } } // @media (max-width: globalsVariables.$maxScreenWidth) { // .main .heroTextSection { // width: 100%; // #heroMoreInfo { // width: 100%; // } // } // } // @media (max-width: 600px) { // .bannerContainer { // #image { // height: auto; // } // } // } import { CSSProperties } from "react"; import Image from "next/image"; // This is simply just a regular div block // It only incoprporates the standard padding & navigation bar spacing // Otherwise, nothing more is affected export const GenericSection = ({ children, className = "", id = "", style = {}, }: Readonly<{ children?: React.ReactNode; className?: string; id?: string; style?: CSSProperties; }>) => { return ( <div className={`sectionHeight sectionPadding navigationBarSpacer ${className}`} // className={`sectionHeight sectionPadding navigationBarSpacer ${className}`} id={id} style={style} > {children} </div> ); }; export default function Home() { // UI Layout return ( <div> <HeroSection /> <GenericSection> <div> <h1>This is the title!</h1> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut dolorum maiores eveniet omnis cumque esse minus neque ex nulla eum porro iure laudantium unde quos praesentium, numquam alias aut! A! </p> </div> </GenericSection> <GenericSection style={{ backgroundColor: "pink", }} > <div> <h1>This is the title!</h1> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut dolorum maiores eveniet omnis cumque esse minus neque ex nulla eum porro iure laudantium unde quos praesentium, numquam alias aut! A! </p> </div> </GenericSection> </div> ); }Thanks in advance to those that'll have helped me! I sincerely mean it.
