skip to Main Content

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.

2

Answers


  1. Chosen as BEST ANSWER

    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>
    

  2. To be honest, I don’t think you need any JS code to handle your problem. Just better media-query management.

    I created a codepen with a working solution, here

    Basically, I entirely removed the mobile section.

    <div class="wrapper">
        <div class="karte">
          <div class="karte-flexbox">
            <h2 class="titel">
              Example 1
            </h2>
            <p class="hover-text">
              Lorem ipsum dolor sit amet, consectetur adipisici elit
            </p>
            <a href="#" class="karte-btn">
              More info
            </a>
            <svg class="mobile-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px">
            <path class="chevron" d="M6.1,19.1c-0.3,0-0.7-0.1-0.9-0.4c-0.5-0.5-0.5-1.3,0-1.8l6.9-6.9L5.2,3.1c-0.5-0.5-0.5-1.3,0-1.8
                                     s1.3-0.5,1.8,0l7.8,7.8c0.5,0.5,0.5,1.3,0,1.8L7,18.7C6.8,19,6.4,19.1,6.1,19.1z" />
            </svg>
          </div>
          <div class="bild-overlay-2"></div>
          <div class="bild-overlay-1"></div>
          <!--this link makes everything clickable-->
          <a href="#">
            <span class="link-span"></span>
          </a>
          
        </div>
        <div class="karte">
          <div class="karte-flexbox">
            <h2 class="titel">
              Example 2
            </h2>
            <p class="hover-text">
              Lorem ipsum dolor sit amet, consectetur adipisici elit
            </p>
            <a href="#" class="karte-btn">
              More info
            </a>
            <svg class="mobile-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20px">
            <path class="chevron" d="M6.1,19.1c-0.3,0-0.7-0.1-0.9-0.4c-0.5-0.5-0.5-1.3,0-1.8l6.9-6.9L5.2,3.1c-0.5-0.5-0.5-1.3,0-1.8
                                     s1.3-0.5,1.8,0l7.8,7.8c0.5,0.5,0.5,1.3,0,1.8L7,18.7C6.8,19,6.4,19.1,6.1,19.1z" />
            </svg>
          </div>
          <div class="bild-overlay-2"></div>
          <div class="bild-overlay-1"></div>
          <!--this link makes everything clickable-->
          <a href="#">
            <span class="link-span"></span>
          </a>
        </div>
     </div>
    

    Then, I moved all the :hover interactions inside a media query, since they are used only for the desktop version.

    @media (min-width: 600px){
    
    
     /* hover effects are useful only in desktop mode */
      
      .karte:hover {
        box-shadow: 4px 4px 7px 1px rgba(0, 0, 0, 0.2);
        left: -2px;
        top: -2px;
      }
      .karte:hover .bild-overlay-2 {
        opacity: 1;
      }
      .karte:hover .karte-flexbox {
        top: 0%;
        opacity: 1;
      }
      .karte:hover .titel {
        margin: 0;
        font-size: 22px;
      }
      .karte:hover .hover-text,
      .karte:hover .karte-flexbox .karte-btn {
        opacity: 1;
      }
      .karte-btn:hover {
        background: #fff;
        /* border: 2px solid #b4eb14; */
        color: #b4eb14;
      }
      .mobile-icon {
        display: none;
      }
    }
    

    After that, inside a media query, I modified the already present sections to fit correctly inside the mobile view:

    @media (max-width: 600px) {
    
    
      .wrapper {
        flex-direction: column;
      }
      .karte {
        width: 100%;
        background-image: url('https://i.ibb.co/PCZRF9m/stamp-s.webp');
        height: 60px;
        border-radius: 10px;
      }
      
      .karte-btn, .hover-text {
        display: none;
      }
     
      .titel{
        font-weight: normal;
      }
      
      .karte-flexbox{
        position: relative;
        top: 0px;
        left: 0px;
        padding: 0px 10px;
        width: 90%;
        height: 100%;
        flex-direction: row;
        font-weight: 400;
      }
      
      .bild-overlay-2{
        opacity: 1;
        background: linear-gradient(
        90deg,
        rgba(0, 110, 145, 0.8) 42%,
        rgba(0, 0, 0, 0) 100%
      );
      }
    }
    

    Most important parts for the mobile media queries:

    • the wrapper gets a flex-direction: row to handle the new orientation
    • the .kart changes the background image and its dimentions
    • the .karte-flexbox is now positioned relative to the parent, since we don’t need to animate it animore
    • we reuse the .bild-overlay-2 to give the same linear gradient, just rotated of 90deg instead of 180deg

    The are also some others small changes as the SVG being visible only in the mobile view.

    The codepen is usable and gets a result nearly identical to yours, but using only one version of each card

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search