Search code examples
htmlcssimagestylingparallax

How to make img element parallax with css?


I would like to implement parallax on a bootstrap-based side. On the top of the page is a header with image. A picture with src-set img to be more concrete.

  <body>

  <header>
    <picture>
      <img
        class="main-img"
        sizes="(max-width: 1980px) 100vw, 1980px"
        srcset="
        /img/img-small.jpg   640w,
        /img/img-medium.jpg 1200w,
        /img/img-large.jpg  1980w
      "
      src="/img/img-medium.jpg"
    />
  </picture>
  <div class="header-content">
  ..
  </div>
</header>

<section ...>

In every solution i see the backgroud is set over css background: url(..). This would lose the responsive image loading.

Is it possible to implement parallax with this markup?


Solution

  • you could use a mix of position:sticky and grid , if i understand what you meant by parallax as a staic one.

    example from your code :(height and min-height value are instead real content tall enough )

    * {
      margin: 0;
    }
    
    header {
      display: grid;
      height: 200vh;
      min-height: 1200px;
    }
    
    picture img {
      position: sticky;
      top: 0;
    }
    
    picture,
    .header-content {
      grid-row: 1;
      grid-column: 1;
    }
    
    .header-content {
      margin-top: 56%;
      /*to preserve space according to ratio image */
      border: solid;
      height: 50vh;
      transform: scale(1);
      z-index: 1;
      background: lightgreen;
    }
    
    picture img {}
    <header>
      <picture style="width:100%;">
        <!-- calc(100vw - 1.2em) to mind a scrollbar -->
        <img class="main-img" sizes="(max-width: 1980px) calc(100vw - 1.2em), 1980px" srcset="
            https://dummyimage.com/640x380&text=small   640w,
            https://dummyimage.com/1280x720&text=medium 1280w,
            https://dummyimage.com/1980x1080&text=large   1980w
          " src="https://dummyimage.com/1200x600&text=medium" />
      </picture>
      <div class="header-content">
        .......
      </div>
    </header>

    another approach would be to get the picture ahead the header :

    * {
      margin: 0;
    }
    
    body {
      display: grid;
    }
    
    picture img {
      position: sticky;
      top: 0;
    }
    
    picture,
    header {
      grid-row: 1;
      grid-column: 1;
    }
    
    header {
      margin-top: 56%;
    }
    
    .header-content {
      height: 100vh;
      background: tomato;
      border: solid;
      transform: scale(1);
      z-index: 1;
    }
    
    .header-content:nth-child(odd) {
      background: repeating-linear-gradient(45deg, transparent 3px, gray 6px, gray 7px), repeating-linear-gradient(-45deg, transparent 3px, gray 6px, gray 7px)
    }
    main section {height:100vh;background:#bed}
    <picture style="width:100%;">
      <img class="main-img" sizes="(max-width: 1980px) calc(100vw - 1.2em), 1980px" srcset="
            https://dummyimage.com/640x380&text=small   640w,
            https://dummyimage.com/1280x720&text=medium 1280w,
            https://dummyimage.com/1980x1080&text=large   1980w
          " src="https://dummyimage.com/1200x600&text=medium.jpg" />
    </picture>
    <header>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
    
    </header>
    <main> Main
      <section>Section</section>
    </main>

    a parallax with image going slowly up

     
    
    body {
      perspective: 20px;
      perspective-origin: 0%;
      transform-style: preserve-3d;
    }
    * {
      margin: 0;
    }
    body {
      display: grid;
    }
    picture {
      transform-origin: 0 0;
      transform: translateZ(-2px) translatey(-5%);
    }
    picture img {
      position: sticky;
      top: 0;
      transform-origin: 0 0;
      transform: scale(1.1);
    }
    
    picture,
    header {
      grid-row: 1;
      grid-column: 1;
    }
    
    header {
      margin-top: 56%;
    }
    
    .header-content {
      height: 100vh;
      background: tomato;
      border: solid;
      transform: scale(1);
      z-index: 1;
    }
    
    .header-content:nth-child(odd) {
      background: repeating-linear-gradient(45deg, transparent 3px, gray 6px, gray 7px), repeating-linear-gradient(-45deg, transparent 3px, gray 6px, gray 7px)
    }
    main section {height:100vh;background:#bed}
    <picture style="width:100%;">
      <img class="main-img" sizes="(max-width: 1980px) calc(100vw - 1.2em), 1980px" srcset="
            https://dummyimage.com/640x380&text=small   640w,
            https://dummyimage.com/1280x720&text=medium 1280w,
            https://dummyimage.com/1980x1080&text=large   1980w
          " src="https://dummyimage.com/1200x600&text=medium.jpg" />
    </picture>
    <header>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
      <div class="header-content">
        .......
      </div>
    
    </header>
    <main> Main
      <section>Section</section>
    </main>