I have a web page in which i need to show SVG logos. This is quite easily possible in the latest browsers, but I need to make it compatible with older browsers too. Some how I need to display an alternate image to the user if the browser does not support SVG.
I have come across a method called HTTP-content negotiation, but how can I implement it to get the desired result?
I tried the <object> tag but it does not seem to work with IE and is very hard to style when tried with Firefox.
I'd implement this client side with the help of Modernizr. Given a markup such as...
<!-- Start with bitmaps because
they will show up in all browsers even
if javascript is not enabled -->
<img src="logo1.png" class="logo" />
<img src="logo2.png" class="logo" />
<img src="logo3.png" class="logo" />
<img src="logo4.png" class="logo" />
You can do...
$(document).ready(function(){
if (Modernizr.svg){
$('.logo').each(function(){
var src = $(this).attr("src");
var svg = src.substr(0, src.lastIndexOf('.')) + ".svg";
$(this).attr("src", svg)
})
}
})
Related
I'm playing around with a basic Dot-Net web assembly application. In the application I'm displaying two images using two different image tags image and img. The size of the image is bound to a private variable Size. I've noticed a problem where images do not render in a specific scenario using the image tag.
Replication:
dotnet new blazorwasm
I downloaded the SVG from: Bootstrap icons, then I placed the SVG file in "wwwroot/Media/".
In index.razor I've updated the code as follows:
#page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<img src="Media/search.svg" alt="Bootstrap" width="#Size" height="#Size">
<image src="Media/search.svg" alt="Bootstrap" width="#Size" height="#Size"/>
#code
{
private static string Size => "75";
}
The result of running the above code shows only one image displaying
Through process of elimination, the image defined using the image tag is the problem here. If you tweak the code to use hardcoded values i.e.
<image src="Media/search.svg" alt="Bootstrap" width="75" height="75"/>
then the code works again as expected.
I'm aware that <image> is deprecated, but I'd like to understand if the reason the binding breaks the image displaying is due to the deprecation or something else?
Update
The generated HTML using the template is
<!--!--><div class="top-row px-4" b-vv8m6rf2se="">About</div>
<article class="content px-4" b-vv8m6rf2se=""><!--!--><!--!--><!--!--><!--!-->
<!--!--><h1 tabindex="-1">Hello, world!</h1>
Welcome to your new app.
<img src="Media/search.svg" alt="Bootstrap" width="75" height="75">
<image src="Media/search.svg" alt="Bootstrap" width="75" height="75"></image></article>
An interesting find, although of course not of any practical value, just use <img>.
I could easily reproduce this with a jpg image so it's not about svg.
Now for a speculative answer:
Blazor treats <image> like any other tag and the generated HTML looks like expected. But according to this answer,
The HTML5 parsing spec requires that the tag is mapped to the img element at the tree construction stage
This makes me think that when the complete tag is rendered just once it works fine, handling is up to the browser.
But after Blazor has filled in the #Size it will try to update the HTML it generated earlier. If the Browser really changed <image> to <img> internally then the JS Bridge will have trouble finding the element again and the updates fail.
Next.js has an Image component that lazy loads images and also provides a srcset for a given image.
However, sometimes we want to deliver different images for different devices (art redirection).
Mozilla says we should use <picture> element for this purpose, providing different images for different media queries.
I can't find an article (even in next.js official docs) to tell us how can we do that using <Image> component.
Is it possible? How can I use next.js <Image> component and HTML <picture> element together?
I have searched for hundreds of websites, this is the only solution I found which workable on Next.js ( with tailwindcss ).
import Image from 'next/image'
<div>
<div className="md:hidden">
<Image src="Banner-767x500.webp" height={500} width={767} />
</div>
<div className="hidden md:inline-flex lg:hidden">
<Image src="Banner-1023x500.webp" height={500} width={1023} />
</div>
<div className="hidden lg:inline-flex xl:hidden">
<Image src="Banner-1400x500.webp" height={500} width={1400} />
</div>
<div className="hidden xl:inline-flex">
<Image height={500} width={2000} src="Banner-2000x500.webp" />
</div>
</div>
The new version of Next Image component removes a lot of the extraneous HTML and styles and allows full flexibility of the img tag. With that new improvement in the component we can use the picture tag and the image component as normal.
Plus, Web.dev explains the way the picture element works really well: https://web.dev/learn/design/picture-element/
In the same way that srcset builds upon the src attribute, the picture element builds upon the img element. The picture element wraps around an img element.
If there is no img element nested inside the picture element, the picture element won't work.
Like the srcset attribute, the picture element will update the value of the src attribute in that img element. The difference is that where the srcset attribute gives suggestions to the browser, the picture element gives commands. This gives you control.
So, understanding that the picture element is just a wrapper of the img element which the browser still requires, and using the new version of next/image (Nextjs v. 13), you can write it as:
import Image from "next/image";
<picture>
<source srcset=".." media="..."/>
<Image src="..." height="..." width="..." alt="..." />
</picture>
A better approach is to use vanilla HTML as the following example, tested in Next.js 13.
Pros:
Full control of what you're showing and when.
Cons:
Manual optimization of assets.
<picture>
<source srcSet="/portrait/my-dog.webp" media="(orientation: portrait)" />
<img src="/my-dog.webp" alt="A beautiful labrador" loading="lazy" />
</picture>
tl;dr: optimal placeholder image, tiny base64 code in HTML or 1x1 gif image?
I'm in the process of building a portfolio website with many high resolution images. Most are contained in slideshows or hidden divs. So I added a simple lazy loading function to the page.
It all works, but I was wondering what would be the fastest way of loading the placeholder images. Because I was told to never leave the src attribute blank.
I found a very tiny base64 image code on the internets and am using this. But the website contains many images, so the browser is decoding every single base64 image now. Doesn't seem very efficient either.
Would using a single very small 1x1 gif image be more efficient? Or would that add more network requests?
What is the most optimal solution?
Here's the code, almost irrelevant to my question:
<div class="slide">
<button> Click to load images </button>
<img class="lazy" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="http://lorempicsum.com/up/627/200/3" alt="" />
<img class="lazy" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="http://lorempicsum.com/nemo/627/300/4" alt="" />
<img class="lazy" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="http://lorempicsum.com/up/627/300/4" alt="" />
</div>
jQuery:
$.fn.lazyLoad = function(){
var lazy = $(this).find('img[data-src]');
$(lazy).each(function(index){
$(this).attr('src', $(this).attr("data-src"));
});
};
$('.slide').click(function(){
$(this).lazyLoad();
});
And a jsfiddle:
jsfiddle
Use <div> and background-image they load faster (at least perceived faster), but if you are concerned about accessibility and/or SEO, go with what you have already. I optimized the jQuery a little:
Use .lazy instead of [data-src] class selectors are faster than attribute selectors.
When getting or setting data-* attributes, it's better to use the newer way by using .data() instead of .attr().
The background-image property can be manipulated by the .css() method.
SNIPPET
$.fn.lazyLoad = function() {
var lazy = $(this).find('.lazy');
lazy.each(function(index) {
var data = $(this).data('src');
$(this).css({
'background-image': 'url(' + data + ')'
});
});
}
$('.slide').on('click', function() {
$(this).lazyLoad();
});
.lazy {
width: 627px;
min-height: 200px;
background-repeat: no-repeat;
background-size: contain;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="slide">
<button>Click to load images</button>
<div class="lazy" data-src="http://lorempicsum.com/up/627/300/3"></div>
<div class="lazy" data-src="http://lorempicsum.com/nemo/627/300/4"></div>
<div class="lazy" data-src="http://lorempicsum.com/up/627/300/4"></div>
</div>
Why would you use base64 encoding for that? Encoded images are larger and so have a longer load time however say you are sending an email from a to b then you have to embed the image in the email. That is why it is possible to embed images in html. Emails have to be encoded to standards one of which is base64.
I was wondering what exactly would happen if you output <img src="#"/>? Does the browser essentially try to submit the same URI twice?
It attempts to load the current page (#) as an image. This will almost always fail, as the current page is HTML, not an image.
The same thing will happen for all of the following HTML tags as well:
<img src="?"> (more or less)
<img src="">
<img> (under some browsers!)
I have a page in the cms part of my website (javascript is enabled and can force a browser choice), it is a calendar with lots of images:
<img src='1.gif' />
<img src='1.gif' />
<img src='1.gif' />
<img src='1.gif' />
<img src='2.gif' />
<img src='2.gif' />
<img src='2.gif' />
<img src='2.gif' />
the same image can be used over 250 times, with about 1000-1500 images on the page.
Is the browser smart enough to figure out that these are all the same image, or is there some JavaScript/jQuery trickery that I can use to improve performance?
I think there is a subtlety to the question that has not been addressed. It's the same image on the same page. #Alex's answer is more appropriate for case of the same image across multiple pages.
When you are loading multiple copies of the same image within one page, the browser shouldn't care about cache/expiry headers. It should just re-use the image it loaded.
For this DOM fragment:
<img src='1.gif' />
<img src='1.gif' />
Looking at the network tab in Chrome, Firefox or IE9, you can see that there is only one call to the server by the browser. If the image has expired then the image is returned otherwise you'll get a 304 Not modified.
In short there should be no overhead from having a hundred copies of the same image on the same page, and the expiry headers don't matter.
If they have the same real path, then the browser will cache them, unless you have aggressive anti cache headers, such as expiry headers in the past.