skip to Main Content

So, I have a little bit of a weird idea. The background image for the landing of my (work in progress) website is a building I made in blender, and my idea is to put a simple div exactly over the door of the building, which will redirect the user from the landing page to the real homepage upon click.
I have two different versions of this background image, that I switch between via media query: a standard (horizontal) version for devices that have a landscape orientation, and an aptly cut (vertical) version for devices that have a portrait orientation. This means that the position of the door is wildly inconsistent between devices.
Now, the issue is that I’m going insane trying to find a solution to position this "door" div with good responsiveness. Any tricks to avoid using a billion media queries? If not, at least what’s the smartest way to go about those queries? (Using percentages? Using vh and vw? Using pixels?)
Thanks in advance.

3

Answers


  1. I think you have to use @media unless you use tools like bootstrap or tailwind.
    I know there are standards though to make it a little easier.

    Mobile: 320-480px
    Tablet: 481-768px
    Desktop: 769-1024px
    Xl Desktop: 1201px and up

    I use Tailwind and for this you write inline css like md: lg: xl: instead of pixels

    What front end framework are you using?

    Login or Signup to reply.
  2. You could try and build that with a display of grid.

    Also there’s a kinda new way instead of @media which is @container . you can check this video i think it can be really helpfull.

    Login or Signup to reply.
  3. The way to do this is by creating an SVG which contains both your image and its clickable areas (implemented as SVG shapes or paths). This ensures that both the image and its clickable areas will stay in sync as the SVG scales, stretches or crops.

    Let’s start with the image. For this example, I’ve chosen an image from picsum.photos which contains three doors:

    enter image description here

    It’s image number 819, and I’ll scale it down to 1000 pixels wide:

    http://picsum.photos/id/819/1000

    The first step is to define an SVG <image> element to reference this, setting the width and height to match the intrinsic width and height of the image. This image happens to be square, so both width and height are 1000 pixels.

    <image width="1000" height="1000" href="http://picsum.photos/id/819/1000"></image>
    

    Then set the SVG viewbox to match.

    <svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">
      <image width="1000" height="1000" href="http://picsum.photos/id/819/1000"></image>
    </svg>
    

    Then define the clickable areas within this space. We can use any SVG shapes or paths to do this; in this case the doors are simple rectangles, so we can use <rect>. An SVG editing application can help make this step easy, particularly if you are needing more complex shapes for the clickable areas.

    <svg viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">
      <image width="1000" height="1000" href="http://picsum.photos/id/819/1000"></image>
      <rect x="242" y="673" width="133" height="187"/>
      <rect x="432" y="673" width="133" height="187"/>
      <rect x="621" y="673" width="133" height="187"/>
    </svg>
    

    Finally, we need to wrap each <rect> in an anchor <a> tag, so that we can use it as a link. Usually you would just set the href attribute to specify the link destination, but in this snippet I am using Javascript to trigger an alert box. Run it and tap on each of the three doors.

    document.querySelector('.s1').addEventListener('click', evt => {
      if (evt.target.nodeName=='rect')
        alert(`door ${evt.target.closest('a').dataset.door} opened`)
    })
    .s1 {
      max-height: 90vh;
    }
    
    .s1 a {
      fill: transparent;
    }
    
    .s1 a:hover {
      fill: #fff7;
    }
    <svg class="s1" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg">
    
      <image width="1000" height="1000" href="http://picsum.photos/id/819/1000"></image>
     
      <a data-door="1">
        <rect x="242" y="673" width="133" height="187"/>
      </a>
    
      <a data-door="2">
        <rect x="432" y="673" width="133" height="187"/>
      </a>
      
      <a data-door="3">
        <rect x="621" y="673" width="133" height="187"/>
      </a>
    </svg>

    The final step is to make the SVG cover the viewport. With an image, this would be achieved by styling the image with object-fit and object-position, but these don’t work with inline SVG. Similar effects can be achieved using SVG’s preserveAspectRatio attribute; the following value is the equivalent of object-fit: cover combined with object-position: center bottom :

    preserveAspectRatio="xMidYMax slice"
    

    Here is a snippet to demonstrate the finished solution. After running it, use the full page link to properly test the responsive behaviour.

    document.querySelector('.door').addEventListener('click', evt => {
      if (evt.target.nodeName=='rect')
        alert(`door ${evt.target.closest('a').dataset.door} opened`)
    })
    html, body, .door {
      height: 100%;
    }
    
    body {
      margin: 0;
    }
    
    .door {
      width: 100%;
    }
    
    .door a {
      fill: transparent;
    }
    
    .door a:hover {
      fill: #fff7;
    }
    <svg class="door" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMax slice">
    
      <image width="1000" height="1000" href="http://picsum.photos/id/819/1000"></image>
     
      <a data-door="1">
        <rect x="242" y="673" width="133" height="187"/>
      </a>
    
      <a data-door="2">
        <rect x="432" y="673" width="133" height="187"/>
      </a>
      
      <a data-door="3">
        <rect x="621" y="673" width="133" height="187"/>
      </a>
    </svg>

    It’s also worth taking the ImageMapper website for a spin; it is a code generator which does the hard work for you with a sweet point-and-click interface.

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