Previously: Browser Grading, Historical Browser Detection, Requirements and Loaders, Detection and Fallback, The Complete Solution, Goldplating, Dijon Mustard.
Remember when we talked about browser grading, Yahoo said:
C-grade is the base level of support, providing core content and functionality. It is sometimes called core support. Delivered via nothing more than semantic HTML, the content and experience is highly accessible, unenhanced by decoration or advanced functionality, and forward and backward compatible. Layers of style and behavior are omitted.
What does that look like in 2025?
Assumptions
Start by building your site mobile-first. The most important part of this is having a sensible order to your HTML, so that someone reading it from top to bottom can have a reasonable experience. You should also be setting your image sizes using CSS. In 2025, you probably are already doing both of these things, but if not, fix them.
What about my site navigation?
The first hurdle you’re going to hit is your site navigation. Almost all sites have navigation in their headers, and maybe they tuck it off to the side on mobile under a hamburger menu toggle, but it’s still there in the HTML, where people will have to scroll past it to get to the content. Luckily, there’s a pure HTML solution that handles this and improves your site too.
Put a “skip navigation” link as the first thing in your page, right after the opening body tag. With the appropriate styles it will be invisible to most users, while still appearing if anyone is trying to navigate the page with their keyboard or a screen reader. For people in the fallback experience, they can skip the large nested lists that have links to every page on your site and go right to the content. Just make sure you put id=main on the tag where your content actually starts.
<div class="skip-navigation">
<a href="#main" class="button">Skip to main content</a>
</div>
.skip-navigation {
a {
position: absolute;
top: 0;
transform: translateY(-100%);
transition: transform .2s ease-out;
&:focus {
z-index: 100000;
transform: translateY(0);
}
}
}
The image problem
At this point you’ll look at your pages and see that you’re actually shipping arbitrarily sized images which don’t really flow right with your content. And if you check the fallback experience on mobile, they probably are wider than the phone screen.
The answer is: set a width of 320 in the HTML.
Why 320? That’s the pixel width of the original iPhone, so any smartphone will be able to display it without horizontally scrolling. If you don’t set the height, it will scale while maintaining the aspect ratio. If you’re setting image sizes with CSS in your normal presentation, it will override the size set in the HTML attribute.
When I built this, we were using WordPress. This code got us most of the way there. (We had some custom Gutenberg Blocks that also needed to be updated to generate the right widths.)
class Image_Utils
{
public static function get_image_fallback_sizes($id)
{
// Default to empty strings so fallback sizes are ignored if unset.
$width = '';
$height = '';
$meta = wp_get_attachment_metadata($id);
if ($meta) {
$width = $meta['width'];
$height = $meta['height'];
}
if (empty($width)) {
// SVG files do not get size metadata.
$width = 320;
}
if ($width > 320) {
$scale = 320 / $width;
$width = (int) ($width * $scale);
$height = (int) ($height * $scale);
}
return array($width, $height);
}
public static function rewrite_image_tag($id, $html)
{
list($width, $height) = self::get_image_fallback_sizes($id);
$html = preg_replace(
'/width=[\'"]?\d*[\'"]?/',
'width="' . $width . '"',
$html
);
$html = preg_replace(
'/height=[\'"]?\d*[\'"]?/',
'height="' . $height . '"',
$html
);
return $html;
}
}
function post_thumbnail_html($html)
{
$id = get_post_thumbnail_id();
return Image_Utils::rewrite_image_tag($id, $html);
}
add_filter(
'post_thumbnail_html',
'post_thumbnail_html'
);
Browse happy
Since we’re here, we might as well tell them to update their browser. Put this right after the skip link.
<p class="browserupgrade">
You are using an <strong>outdated</strong> browser. Please
<a href="https://browsehappy.com/">upgrade your browser</a> to
improve your experience and security.
</p>
Fallback styles and scripts?
I don’t think you should use fallback styles or scripts. Doing so means you now have three versions of your site to test. But you can. If you do, here are some hints:
For CSS, imagine you’re targetting IE6, or Netscape 4. No CSS3 Selectors. No Grids. No Web Fonts. SCSS Features are okay though; That’s build-time
For JavaScript, dig out the old addEvent fallback that registered events appropriately in IE. Don’t forget to specify the third parameter as false when you call addEventListener; Opera doesn’t like it if it’s omitted. Always check for the existence of any API you call. You probably won’t have QuerySelectorAll and will have to stick with getElementsByClassName. Remember to register events for load, as not all browsers have DOMContentLoaded. And Test, test, test.