We often think of background images as texture or something that provides contrast for legible content — in other words, not really content. If it was content, you’d probably reach for an anyway, accessibility and whatnot. But there are times when the position or scale of a background image might sit somewhere between the poles of content and decoration. Context is king, right? If we change the background image’s position, it may convey a bit more context or experience. How so? Let’s look at a few examples I’ve seen floating around. As we get started, I’ll caution that there’s a fine line in these demos between images used for decoration and images used as content. The difference has accessibility implications where backgrounds are not announced to screen readers. If your image is really an image, then maybe consider an
tag with proper alt text. And while we’re talking accessibility, it’s a good idea to consider a user’s motion preference’s as well. Show me more! Chris Coyier has this neat little demo from several years back. CodePen Embed Fallback The demo is super practical in lots of ways because it’s a neat approach for displaying ads in content. You have the sales pitch and an enticing image to supplement it. The big limitation for most ads, I’d wager, is the limited real estate. I don’t know if you’ve ever had to drop an ad onto a page, but I have and typically ask the advertiser for an image that meets exact pixel dimensions, so the asset fits the space. But Chris’s demo alleviates the space issue. Hover the image and watch it both move and scale. The user actually gets more context for the product than they would have when the image was in its original position. That’s a win-win, right? The advertiser gets to create an eye-catching image without compromising context. Meanwhile, the user gets a little extra value from the newly revealed portions of the image. If you peek at the demo’s markup, you’ll notice it’s pretty much what you’d expect. Here’s an abridged version:
We could probably quibble over the semantics a bit, but that’s not the point. We have a container with a linked-up
In the CSS, we will create width and height variables to store the dimensions of the of the magnifier glass itself. Then we’ll give that .container some shape and a background-image: :root { –magnifer-width: 85; –magnifer-height: 85; } .container { width: 500px; height: 400px; background-size: cover; background-image: url(“/path/to/image.png”); background-repeat: no-repeat; position: relative; } There are some things we already know about the magnifier before we even see it, and we can define those styles up-front, specifically the previously defined variables for the .maginifier‘s width and height: .magnifier { position: absolute; width: calc(var(–magnifer-width) * 1px); height: calc(var(–magnifer-height) * 1px); border: 3px solid #000; cursor: none; background-image: url(“/path/to/image.png”); background-repeat: no-repeat; } It’s an absolutely-positioned little square that uses the same background image file as the .container. Do note that the calc function is solely used here to convert the unit-less value in the variable to pixels. Feel free to arrange that however you see fit as far as eliminating repetition in your code. Now, let’s turn to the JavaScript that pulls this all together. First we need to access the CSS variable defined earlier. We will use this in multiple places later on. Then we need get the mouse position within the container because that’s the value we’ll use for the the magnifier’s background position. // Get the css variables let root = window.getComputedStyle(document.documentElement); let magnifier_width = root.getPropertyValue(“–magnifer-width”); let magnifier_height = root.getPropertyValue(“–magnifer-height”); let container = document.querySelector(“.container”); let rect = container.getBoundingClientRect(); let x = (e.pageX – rect.left); let y = (e.pageY – rect.top); // Take page scrolling into account x = x – window.pageXOffset; y = y – window.pageYOffset; What we need is basically a mousemove event listener on the .container. Then, we will use the event.pageX or event.pageY property to get the X or Y coordinate of the mouse. But to get the exact relative position of the mouse on an element, we need to subtract the position of the parent element from the mouse position we get from the JavaScript above. A “simple” way to do this is to use getBoundingClientRect(), which returns the size of an element and its position relative to the viewport. Notice how I’m taking scrolling into account. If there is overflow, subtracting the window pageX and pageY offsets will ensure the effect runs as expected. We will first create the magnifier div. Next, we will create a mousemove function and add it to the image container. In this function, we will give the magnifier a class attribute. We will also calculate the mouse position and give the magnifier the left and top values we calculated earlier. Let’s go ahead and build the magnifier when we hear a mousemove event on the .container: // create the magnifier let magnifier = document.createElement(“div”); container.append(magnifier); Now we need to make sure it has a class name we can scope to the CSS: // run the function on `mousemove` container.addEventListener(“mousemove”, (e) => { magnifier.setAttribute(“class”, “magnifier”); } The example video I showed earlier positions the magnifier outside of the container. We’re gonna keep this simple and overlay it on top of the container instead as the mouse moves. We will use if statements to set the magnifier’s position only if the X and Y values are greater or equal to zero, and less than the container’s width or height. That should keep it in bounds. Just be sure to subtract the width and height of the magnifier from the X and Y values. // Run the function on mouse move. container.addEventListener(“mousemove”, (e) => { magnifier.setAttribute(“class”, “magnifier”); // Get mouse position let rect = container.getBoundingClientRect(); let x = (e.pageX – rect.left);…
(Note: I apologize, but it seems I have reached the maximum character limit for the response. I can continue the response in another reply if needed. Let me know if you would like me to do so.)
Source link