Search code examples
javascripthtmlcssreactjs

Layout issues with <video> element


I'm having a layout issues with <video> element. The issue is that it overflows and adds a vertical scroll (at 1839px of width and above). At smaller resolutions it doesn't occur.I want everything to be aligned perfectly and fit in that 100vh .App container and no scroll being added.

I made a simple reproduction. You have to open rendered solution in another page to see the misalignment of .video-container element. Once you open that you can see button does not fit in 100vh.

Code reproduction - https://codesandbox.io/p/sandbox/optimistic-river-5r5gq4?file=%2Fsrc%2FApp.js%3A6%2C26

Rendered solution in another page - https://5r5gq4.csb.app/


Solution

  • I want everything to be aligned perfectly and fit in that 100vh .App container and no scroll being added.

    display: grid can achieve this:

    const App = () => (
      <div className="App">
        <header className="header">Header</header>
        <div className="sidebar">Sidebar</div>
        <main>
          <ReactPlayer
            className="player"
            controls
            height="100%"
            url="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
            width="100%"
          />
        </main>
        <footer>
          <button>Test</button>
        </footer>
      </div>
    )
    
    ReactDOM.createRoot(root).render(<App />)
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    .App {
      display: grid;
      height: 100vh;
      grid-template: 'header header' auto 'sidebar main' 1fr 'sidebar footer' auto / 300px 1fr;
    }
    
    header {
      background-color: lightcoral;
      grid-area: header;
      padding: 1rem;
      text-align: center;
    }
    
    .sidebar {
      grid-area: sidebar;
      background-color: lightblue;
    }
    
    main {
      grid-area: main;
      align-self: stretch;
      position: relative;
    }
    
    main video {
      object-fit: cover;
    }
    
    .player {
      position: absolute;
      inset: 0;
    }
    
    footer {
      grid-area: footer;
    }
    
    button {
      font-size: 18px;
      padding: 0.3rem 3.5rem;
      width: max-content;
    }
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src='https://unpkg.com/[email protected]/dist/ReactPlayer.js'></script>
    <div id="root"></div>

    • pay attention to the markup (DOM structure) changes, not only the CSS (header, .sidebar, main and footer are siblings inside .App)
    • header and footer have no hard-coded heights, main and .sidebar adjust to the remaining space
    • if you want the sidebar contents to remain accessible even when they need more than the available height, place overflow-y: auto on it.
    • note I'm taking .player out of content flow and having it match its parent size (inset: 0; position: absolute;). This way, the parent main has no size constraints whatsoever from the <video />
    • the hard-coded 300px width of .sidebar might become a problem on mobiles. perhaps hide it and allow users to open it as overlay!? (I've added a basic demo to the sandbox linked below).
    • the verbose syntax for grid-template would be:
    .App {
      grid-template-areas: "header header" "sidebar main" "sidebar footer";
      grid-template-columns: 300px 1fr;
      grid-template-rows: auto 1fr auto;
    }
    

    Codesandbox demo.