Search code examples
javascripthtmlcssfrontendweb-frontend

How to change background images based on screen-size in HTML/CSS/Javascript? (art direction)


I'm currently working on a project in which I have elements that are displayed as cards with an aspect-ratio of 5:6 on desktop. On mobile, the same elements are displayed as entries of a stylized list that are very different with a aspect-ratio 1:10. To accommodate for this situation, each element is currently split in two – one desktop version, and one mobile version. I'm currently trying to merge both versions to lay groundworks for future code changes, and to reduce maintenance time when adding new elements. This is an excerpt of the current code (in actuality there are more than 15 cards already, see the extended version and CSS here):

<div class="desktop-wrapper">
    <div class="card" style="background-image: url('[name]-l.webp')">
      <div class="card-flexbox">
        <h2 class="titel">Example 1</h2>
        <p class="hover-text">
          Lorem ipsum dolor sit amet, consectetur adipisici elit
        </p>
        <a href="#" class="card-btn">More info</a>
      </div>
      <!--some overlays for aesthetics-->
      <div class="img-overlay-2"></div>
      <div class="img-overlay-1"></div>
      <!--this link makes everything clickable-->
      <a href="#">
        <span class="link-span"></span>
      </a>
    </div>
    (...)
</div>
<!--mobile version-->
<div class="mobile-wrapper">
  <a href="#" class="mobile-card-link">
    <div class="mobile-karte" style="background-image: url('[name]-s.webp')">
      <h3 class="titel">Example 1</h3>
      <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px">
        <path class="chevron" d="(...)" /></svg>
      <!--overlay for aesthetics-->
      <div class="mobile-card-overlay"></div>
    </div>
  </a>
  (...)
</div>

The problem: Each version of the cards uses a different picture for art direction reasons. A wide version "[name]-s.webp" is used for the mobile version, and a taller version for desktop, "[name]-l.webp".

My preferred way of solving the issue would be having a script that takes advantage of the above mentioned naming convention. Ideally I'd just write <div class="mobile-karte" style="background-image: url('./img/stamp')">...</div> in my HTML and have the script extend the background-image url based on screen size — for example by adding "-s.webp" to the background-image url below a breakpoint of 600px. I'm thinking of something like this, just more automated.

Is this possible? If so, how?

Other options I thought about:

  1. Giving each element an individual ID and creating media queries to change out the background-image at a certain breakpoint. A good fallback-option, but I'd prefer a script to simplify things and reduce manual labour.
  2. Using image-set(). Seems like a lot of manual labour each time a new card has to be added. Also, it doesn't allow for specific breakpoints to the best of my knowledge.
  3. srcset. While it would allow for specific breakpoints, I'd have to create my background-images as img-elements, which seems a bit complicated.

Solution

  • I ended up finding a solution on my own. Using data-name attributes for the cards and then having a small script generate the according background-images (and even links) automatically. It looks something like this:

    <div class="card" data-name="example-1">
          <div class="flexbox">
            <a href="#" class="card-btn">
              More info
            </a>
          </div>
    </div>
    
    
    
    <script>
        const cardElements = document.querySelectorAll('.card');
    
        function updateBackgroundImage(cardElement) {
          const name = cardElement.getAttribute('data-name');
          const imageUrl = window.innerWidth > 600 ? `/assets/img/${name}-l.webp` : `/assets/img/${name}-s.webp`;
          cardElement.style.backgroundImage = `url('${imageUrl}')`;
        }
    
        function updateCardLinks(cardElement) {
          const name = cardElement.getAttribute('data-name');
          const links = cardElement.querySelectorAll('a');
    
          links.forEach(link => {
            link.href = `https://www.example.com/${name}/`;
          });
        }
    
        cardElements.forEach(cardElement => {
          updateCardLinks(cardElement);
          updateBackgroundImage(cardElement);
          window.addEventListener('resize', () => {
            updateBackgroundImage(cardElement);
          });
        });
    </script>