Dealing with Safari and .webp images in 2022 - css

I've been waiting to use .webp images for a very long time.
It's 2022, so, given:
the image format has existed for a decade
Chrome started supporting .webp in Jan 2014
Firefox started supporting .webp in Jan 2019
I decided the day before yesterday to take the plunge and convert a bunch of .png images on a website to .webp images.
Rookie error. Because, of course, I should have checked: https://caniuse.com/webp first and that would have told me that Safari on anything earlier than macOS 11.0 Big Sur (Nov 2020) does not support .webp images.
But I'm tired of waiting. So... Safari can carry on using .png images I suppose.
Because I absolutely do want to serve .webp images to Firefox, Brave, Chrome, Edge, Opera etc. users.
If I were using marked up images, declaring one or more fallback images is elementary:
<picture>
<source srcset="a-webp-for-most-browsers.webp" type="image/webp">
<source srcset="a-png-for-safari.png" type="image/png">
<img src="a-png-for-safari.png" alt="My Image">
</picture>
But (sigh) in this instance, the images are CSS background images, so options for creating fallbacks are more limited:
CSS image-set still has pretty low support at present
CSS feature queries using #supports do not extend to image formats.
Am I limited to browser-sniffing via PHP, like this:
if (preg_match('/Mac OS X/', $_SERVER['HTTP_USER_AGENT'])) {
$Body_Element_CSS_Class_List .= ' oh-no-here-comes-safari';
}
Is there a better / more reliable approach I can adopt than browser-detection?

I'm having the same issue, but I believe one good way to solve it for CSS background images today would be to use Modernizr.
In that link you can make a Modernizr script build that specifically verifies for webp support in the browser. Then you just have to add the script to the <head> and it'll add classes to the <html> based on the features you're verifying. So, for instance, to load different image formats for a CSS background image you would do:
.webp .image {
background-image: url('/image.webp');
}
.no-webp .image {
background-image: url('/image.png');
}

Yes, it's hard to provide fallbacks for CSS background-images
In my question I wrote:
If I were using marked-up images, declaring one or more fallback images is elementary [...]
But (sigh) in this instance, the images are CSS background-images, so options for creating fallbacks are more limited
And for now, at least, - ie. while we're still waiting (in 2022) for widespread cross-browser support for the CSS image-set() function - that's true.
But a marked-up <img> can replace each CSS background-image
While I was hunting around for alternative approaches, I unexpectedly came across this July 2021 comment by Quentin Albert:
For what most people use background images for you can nowadays easily use object-fit + object-position.
Source: https://css-tricks.com/using-performant-next-gen-images-in-css-with-image-set/
This was news to me. I was dimly aware of the object-fit CSS property, but I'd never come across the object-position CSS property at all.
But it absolutely works!!
The CSS I would have used if image-set() had support
If image-set() had extensive cross-browser support, this was my intended CSS, which would enable a fallback image for Safari:
.my-image-1 {
background-image: url(image-set('my-sprited-images.webp', 'my-sprited-images.png'));
background-position: 0, 0;
}
.my-image-2 {
background-image: url(image-set('my-sprited-images.webp', 'my-sprited-images.png'));
background-position: -100px, 0;
}
The HTML + CSS I can use instead (thanks to object-position)
Since the above isn't close to reliable, I can declare the fallback image in HTML instead and position it using object-position:
HTML:
<picture>
<source srcset="my-sprited-images.webp" type="image/webp">
<source srcset="my-sprited-images.png" type="image/png">
<img class="my-image-1" src="/my-sprited-images.png" alt="My Image 1">
</picture>
<picture>
<source srcset="my-sprited-images.webp" type="image/webp">
<source srcset="my-sprited-images.png" type="image/png">
<img class="my-image-2" src="/my-sprited-images.png" alt="My Image 2">
</picture>
CSS:
.my-image-1 {
object-position: 0 0;
}
.my-image-2 {
object-position: -100px 0;
}

Related

Using SVG identifier in Safari causes problem

I'm using SVG for my footer background. Here's my code:
#footer-bg {
background-image: url("/assets/main-bg.svg#svgView(viewBox(2,0,590,700))");
background-size: 100% 100%;
background-repeat: no-repeat;
}
This is working in all browsers except Safari, and the culprit is the SVG identifier #svgView(viewBox(2,0,590,700)). When I tried to put the viewbox inside SVG file, it is working in Safari.
Is there a way to fix this?
Absolutely you can use a hack to use a media query to target only Safari browser and then modify that background-image value with the correct one for that browser. In this StackOverflow post you can have more info about those media queries.
Besides that, if you want to have that viewbox set for the SVG, why you don't just edit the svg file, setting that viewbox directly in there and removing it from the css?

SVG mask not working in Firefox

I should apply SVG masks to few of images, but since this is the first time i am doing this, i ran into some problems.
From the PSD, i exported the shape as PNG and then converted it to SVG using some online converter.
Using CSS, i applied the mask to the image, like bellow, and in Chrome and Safari it works properly, but on Firefox it doesnt (i am guessing on IE too).
<style>
.mask {
-webkit-mask-box-image: url('http://imgh.us/mask_1.svg');
mask-border: url('http://imgh.us/mask_1.svg');
}
</style>
<img src="http://www.record-lrc.co.uk/Downloads/Cinnabar%20-%20Tyria%20jacobaeae[18042011].jpg" class="mask">
You can see the Fiddle here https://jsfiddle.net/f5tzv9Lr/2/ (be sure to use Chrome).
Can anybody suggest something or let me know what am i doing wrong?
UPDATE: From what i see, Mozilla has its own attribute, mask (https://developer.mozilla.org/en-US/docs/Web/CSS/mask), but it isnt working, at least in my case

How can I have different CSS code for browsers that do not support border-radius`

I would like to make use of border-radius and the different variations on my web pages. I'd also like to have alternate CSS for the browsers that don't support this. I am using MVC3.
Is there a simple way that I could have different CSS presented depending on if the browser does or does not support border-radius and just have ONE CSS file. In other words I would prefer to not have to have an additional CSS file to manage different variations of browser.
I read about BrowserCaps. Is anyone using this with MVC3 for CSS switching?
Use the excellent jQuery round corner plugin.
http://jquery.malsup.com/corner/
It's supported in all browsers including IE. It draws corners in IE using nested divs (no images). It also has native border-radius rounding in browsers that support it (Opera 10.5+, Firefox, Safari, and Chrome). So in those browsers the plugin simply sets a css property instead.
Here's How to use it
You need to include the jQuery and the Corner js script before </body>. Then write your jQuery like $('div, p').corner('10px'); and place before ''. So your html will look like the below code. Here i'm making round corners for all div and p tags. If you want to do it for specific id or class then you can do something like $('#myid').corner();
<body>
<div class="x"></div>
<p class="y"></p>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://github.com/malsup/corner/raw/master/jquery.corner.js?v2.11"></script>
<script>$('div, p').corner();</script>
</body>
Check working example at http://jsfiddle.net/VLPpk/1
UPDATE
If you want a cross browser Solution using only CSS, then use the following
.curved {
behavior: url("border-radius.htc");
-moz-border-radius: 20px; /* Firefox */
-webkit-border-radius: 20px; /* Safari and Chrome */
-khtml-border-radius: 20px; /* Linux browsers */
border-radius: 20px; /* Opera 10.50, IE and CSS3 */
}
Download the htc file from http://code.google.com/p/curved-corner to make this work in IE browsers. jQuery plugin mentioned above remains the easiest way to do this where you don't have to modify so many CSS properties everytime you want to issue a radius.
Modernizr might be helpful for you. It would add either borderradius or no-borderradius to your markup using javascript and you can then style based on that:
http://www.modernizr.com/docs/#borderradius

SVG for images in browsers with PNG fallback

I'm looking to use SVG versions of a company logo on a website. At present, all current versions of major browsers (IE, Safari, Chrome, Firefox, Opera) support SVG, so this doesn't seem crazy. However, old browsers are still out there, so I need to fall back to PNG support.
The obvious solution is to put the SVG content in an object tag like so (forgive the inline styles...):
<object data='logo.svg' style='height:3em' >
<img src='logo.png' style='height:3em' />
</object>
Which in theory should render the object if possible, or else render the img. However, Chrome doesn't like this and applies the height style to the object itself but not the SVG, so I end up with a little iframe-like box with scrollbars, showing a huge logo.
Another solution would be to use the PNG as the img source, and then swap it out at render time with the SVG source with javascript, if I think I'm running on a SVG-capable browser. This is not ideal because the PNG will still get downloaded, and I'm not confidant I can properly detect SVG support. Unfortunately, jQuery doesn't seem to have a SVG-detect feature.
Finally, since my website is deployed with ASP.NET, I could inspect the user agent string before serving the page, and specify the img source depending on whether I think it will support SVG. But this also has the potential problem that I am not confidant I can make the right call.
What is the preferred way of doing SVG for images?
This is an old question, but here is another solution:
Download a version of Modernizr that is trimmed down to just testing SVG (assuming that’s the only test you need).
Run the test. If it passes, put in the SVG. If it fails, put in the bitmap. Essentially:
if (!Modernizr.svg) {
$("#logo").css("background-image", "url(fallback.png)");
}
SVG is a perfect use case for Modernizr, because there is no simple native way to provide a fallback.
Note: The browser don't load both (png and svg) versions.
For the record: the only reason you would need a fallback for SVG these days if you have to support IE 8 and down, or older Android.
I wouldn't call it the preferred way, but if you want to pursue your second option this should detect SVG support (from Raphaël 1.5.2):
if(window.SVGAngle ||
document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") {
// supports SVG
else {
// no SVG
}
Raphaël uses this to determine if it should render using VML (IE) or SVG (everyone else).
Out of curiosity, why SVG for your logo? If you already have a PNG version, this seems like a lot of work.
To solve your problem w/resizing SVGs in the object tag:
Add "preserveAspectRatio" and "viewBox" attributes to the svg tag. Open the file in a text editor and find the tag. in that tag, add the following attributes:
preserveAspectRatio="xMinYMin meet" viewBox="0 0 {width} {height}"
Replace {width} and {height} with some defaults for the viewBox. I use the values from the "width" and "height" attributes of the SVG tag. Save the SVG and it should now scale as expected.
See: How do I scale a stubborn SVG embedded with the <object> tag?
The problem w/SVGs in the object tag, though is that they swallow the clicks.
SVG as background-image w/PNG fallback: http://www.broken-links.com/2010/06/14/using-svg-in-backgrounds-with-png-fallback/
My favorite is using the img tag and an onerror handler to change the src tag to a PNG.
Another good resource: http://www.schepers.cc/svg/blendups/embedding.html
The only thing you need is CSS. First you declare the fallback image as a background-image. Then you can use multiple backgrounds to add the SVG.
IE8 and below will ignore the second background-image-declaration, because the lacking support of multiple backgrounds.
By the way, I'm using the img element here, because a logo is content, not layout. Using background-images might appear to be wrong in this context, but I disagree. You get the best of the worlds: SVG logo, fallback for
HTML:
<a href="/" class="site-logo">
<!-- base64 encoded 1x1 px big transparent gif -->
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="company logo">
</a>
CSS (using multiple background images):
caniuse: multiple backgrounds
PNG for IE <9, FF <3.6, Opera <10.5
SVG for all the others supporting SVG
Android 2.x won't have a PNG or SVG, due to these versions actually supporting multiple backgrounds, but not SVG
There is only one HTTP request made for browsers supporting SVG
.site-logo > img {
/* Dimensions of your image need to be set */
width: 32px;
height: 32px;
/* Fallback for <IE9 */
background-image: url(logo.png);
/* multiple backgrounds are ignored by <IE9 */
background-image: url(logo.svg), none;
}
CSS (using linear gradients):
caniuse: CSS gradients
PNG for IE <10, FF <3.6, Safari <4.0, Opera <11.1, Opera Mini, Opera Mobile <11.1
SVG for all the others supporting SVG (if vendor-prefixes are specified)
Ignoring the old gradient syntax for webkit makes Android 2.x use the PNG fallback
.site-logo > img {
/* Dimensions of your image need to be set */
width: 32px;
height: 32px;
background: transparent url(logo.png) center center no-repeat;
background-image: -webkit-linear-gradient(transparent, transparent), url(logo.svg);
background-image: linear-gradient(transparent, transparent), url(logo.svg);
}
Try svg-web they have a number of different ways of displaying svg images including flash with automatic fallback.
The best method I have found including SVG as an HTML element (with fallback) is this one:
<svg preserveAspectRatio="xMidYMid meet" viewBox="0 0 100 100" style="width: 100px; height: 100px; vertical-align: top;">
<image xlink:href="image.svg" src="fallback.png" width="100%" height="100%"/>
</svg>
Pros:
Provides fallback in every device/browser I have tested (IE6-IE11, Android 2.0+, IOS3-7)
Only one image is loaded for each tested browser (except IE9-IE11)
Externally loaded images allows image to be cached
Cons:
Unable to use as scaleable (responsive) image in IE9-IE11 (see this question)
IE9-IE11 loads both images
IOS3-4 (Mobile Safari) has SVG support but displays the PNG (since it lacks inline SVG support)
SVG file must not have height / width attributes (unsure about this, but have read about it somewhere and in my tests my SVG did not have them anyway)
Does not validate
Please provide comments with additional pros / cons you can think of. I know for one SVG's can appear pixeled in some browsers, but I was unable to test zooming in since using browserstack for emulation.
Source: http://lynn.ru/examples/svg/en.html

Is there any way other than javascript to fix IE 6 bugs?

For IE 6 we have plenty of bugs to bug us as a designer.
incorrect box model etc etc.
i have searched for fixes via JavaScript and found
[link text][1]
IE7.js
IE7 is a JavaScript library to make Microsoft Internet Explorer behave like a standards-compliant browser. It fixes many HTML and CSS issues and makes transparent PNG work correctly under IE5 and IE6.
but do we have real life saver other than javascript via css.
Ways to deal with IE6 bugs with CSS? Sure.
See: http://www.quirksmode.org/css/condcom.html
for conditional comments
There are other ways, such as adding some specific characters in some CSS properties that get ignored in some browsers but not in others.
However, in some cases, web designers should be very cautious when using these.
The alternative is to live within the IE 6 world of bugs and design your pages to look right despite them. You can serve up different css for your IE6 clients, or even different html if necessary, depending on your design. In some cases, you can use one CSS file that will mean different things to IE6 clients, but that technique is problematic with respect to IE7 and 8.
this link is also handy one
How do you deal with Internet Explorer?
I never knew this - thanks svinto
"IE6 doesn't have the incorrect box model unless you have the wrong doctype. – svinto"
There are some simple stylesheet hacks that can modify the presentation in various internet explorer versions to solve your CSS problems. For example these three:
Simplified box model hack for IE4, IE5, IE5.5:
div.values { margin: 10px; m\argin: 20px; }
star html hack for IE4, IE5, IE5.5 and IE6:
* html div.values { margin: 5px; }
star first-child+html hack for IE7:
*:first-child+html div.values { margin: 5px; }
PNG transparancy issues could be solved with solutions like this:
<div style="width:50px;height:50px;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/logo/logo.png');">
<img src="/images/logo/logo.png" height="50" width="50" alt="" style="filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" />
</div>
Great info so far but one thing to note is that IE7.js doesn't fix pngs in all cases (at least last I looked). For instance, you won't be able to tile a background image with transparency.
In the case of DXImageTransform you may find that when this is applied to elements that contain links, those links are no longer 'clickable'. You can sometimes fix this by giving the parent element that has the transform applied to it static positioning and to position the child anchor element e.g.,
h2{
position:static;
zoom:1;
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/images/mypng.png", sizingMethod="scale");
}
h2 a{
position:relative;
}
<h2><a href="" >a link!</a></h2>
If you have to do this sort of garbage put it in a separate stylesheet and control loading with conditional comments. If the design is of any complexity try you best not to support ie6 or <. If you can't avoid doing it, charge more ;). Sometimes that is enough to persuade someone that supporting ie6 isn't "worth their while".
why don't you try FireBug Light for IE? It's not as powerful as FireFox FireBug but can be helpful
Many bugs can be worked around in CSS using conditional comments or CSS selector hacks. But there are some bugs that CSS hacks alone cannot handle such as IE6's .multiple.class.selector.bug
There's another quick and dirty hack for IE6 styles
for e.g.
You can define the CSS as;
.divTitle
{
padding: 5px;
width: 600px;
_width: 590px;
}
All the other browsers picks up 600px as the width value & IE6 overwrites it & take 590px;
I've tested this in IE7 & FF as well.
Also you may want to check this link;
link text

Resources