传递2个背景图像:1个用于移动设备,1个用于PHP桌面,而不必重复HTML内容?
Let's say we need to display 2 different images for mobile and desktop. We would usually do something like this:
HTML
<div class="container"></div>
CSS
.container {
background-image: url('image-for-mobile.jpg');
}
@media (min-width: 1024px) {
.container {
background-image: url('image-for-desktop.jpg');
}
}
But what happens when we are getting those images from the server? Let's say from Wordpress or any other source?
One way to do it, would be:
HTML
<div class="container for-mobile" style="background-image: url(<?php echo $img_for_mobile; ?>);"></div>
<div class="container for-desktop" style="background-image: url(<?php echo $img_for_desktop; ?>);"></div>
CSS
.for-mobile {
display: block;
}
.for-desktop {
display: none;
}
@media (min-width: 1024px) {
.for-mobile {
display: none;
}
.for-desktop {
display: block;
}
}
For obvious reasons, even though this "works" this is not right because we are repeating the markup. What if we have a ton of content inside '.container'? We would have to repeat all that, only to have a different background image.
Another option would probably be passing the variables as data attributes and then with jQuery getting those variables and assigning the right background image in relation to the screen size. Something like this:
HTML
<div class="container" data-mobile="<?php echo $img_for_mobile; ?>" data-desktop="<?php echo $img_for_desktop; ?>"></div>
jQuery
// This is pseudo code, not tested
var imgForMobile = $('.container').data('mobile');
var imgForDesktop = $('.container').data('desktop');
$(window).on('resize', function() {
if ($(window).width() < 1024) {
$('.container').css('background-image', 'url(' + imgForMobile + ')');
}
else {
$('.container').css('background-image', 'url(' + imgForDesktop + ')');
}
});
How could we attack this situation in a more elegant and proper way? Any thoughts would be much appreciated. Thanks in advance!
The correct way:
This is what image srcset
is for!
https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images
<img srcset="elva-fairy-320w.jpg 320w,
elva-fairy-480w.jpg 480w,
elva-fairy-800w.jpg 800w"
sizes="(max-width: 320px) 280px,
(max-width: 480px) 440px,
800px"
src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy">
If I had to guess though, I think you would benefit from using this and object-fit
together. Do you want the background image to be sized to cover
?
If so, this is way the super responsive and efficient way to do this:
.container {
position: relative;
}
.container img {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
object-fit: cover;
}
<div class="container">
<img srcset="elva-fairy-320w.jpg 320w,
elva-fairy-480w.jpg 480w,
elva-fairy-800w.jpg 800w"
sizes="(max-width: 320px) 280px,
(max-width: 480px) 440px,
800px"
src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy">
</div>
The older server side way:
If you really wanted to do it in PHP like you have in the example, this is the pattern we use for things like this in WordPress.
$image = 'desktop.jpg';
switch (true) {
case wp_is_mobile() :
$image = 'mobile.jpg';
break;
}
<div class="container" style="background-image: url(<?php echo $image; ?>);"></div>
You can still use the CSS approach, by passing in a full URL or CDN.
If the rule inside of a media query that is false
, that image won't be loaded by the browser.
.container {
background-image: url('https://www.example.com/image-for-mobile.jpg');
}
@media (min-width: 1024px) {
.container {
background-image: url('https://www.example.com/image-for-desktop.jpg');
}
}
There are alternatives which place this logic in either your HTML, JS, or even server code. HTML's answer is using a srcset
attribute with an image, or using a <picture>
element instead which was introduced in HTML5. srcset
on an image is typically used to handle differences in pixel density, while the <picture>
element is used to serve varying images using media queries. The first <source>
whose media query matches the document is served, and you can include a general fallback, which allows backward compatibility for older browsers, however this approach loads at least 2 images - as the fallback will always be loaded.
<picture>
<source srcset="big.jpg 1x, big-2x.jpg 2x, big-3x.jpg 3x" media="(min-width: 40em)" />
<source srcset="med.jpg 1x, med-2x.jpg 2x, med-3x.jpg 3x" />
<img src="fallback.jpg" alt="fancy pants" />
<!-- fallback.jpg is *always* downloaded -->
</picture>
The way I did it in my site was I used JQuery to check if its a mobile browser (quick google will find the if statement used, its rather long)
Edit:
Here: if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
$('body').addClass('mobile');
}
I made it append the body tags with class='mobile' and then in my CSS I have two sets:
body {
background:black;
}
.mobile body {
background: blue;
}