-
-
Save tkadlec/683b26344cde774170b94c0fcf0088b4 to your computer and use it in GitHub Desktop.
:root { | |
--violation-color: red; /* used for clear issues */ | |
--warning-color: orange; /* used for potential issues we should look into */ | |
} | |
/* IMAGES */ | |
/* | |
* Lazy-Loaded Images Check | |
* ==== | |
* Highlight any lazy loaded images so we can see if any are inside the viewport | |
* | |
* Uses an outline so it can pair with Unsized Images and Legacy Format checks | |
* Credit: https://twitter.com/csswizardry/status/1346477682544951296 | |
*/ | |
img[loading=lazy] { | |
outline: 10px solid var(--warning-color) !important; | |
} | |
/* | |
* Unsized Images Check | |
* ==== | |
* Highlight images that don't have a height or width attribute set | |
* | |
* Uses a border so it can pair with Lazy-Loaded and Legacy Format checks | |
*/ | |
img:not([height]), img:not([width]) { | |
border: 10px solid var(--violation-color) !important; | |
} | |
/* | |
* Legacy Format Check | |
* ==== | |
* Highlight tiff's and bmp's because we can do better | |
* Also JPG's because maybe we can use something like webp or avif instead | |
* | |
* Use opacity so we don't conflict with Lazy-Loaded and Unsized Images checks | |
*/ | |
img[src*='.jpg'], | |
img[src*='.tiff'], | |
img[src*='.bmp']{ | |
opacity: .5 !important; | |
} | |
/* SCRIPTS */ | |
/* Synchronous Scripts Check | |
* ==== | |
* Display any blocking synchronous scripts | |
* | |
* Credit: https://twitter.com/csswizardry/status/1336007323337285633 | |
*/ | |
head, | |
script[src] { | |
display: block; | |
border: 10px solid var(--violation-color);; | |
} | |
/* | |
* Display the URL/filepath of external scripts | |
*/ | |
script[src]::before { | |
content: attr(src); | |
font-size: 1rem; | |
} | |
/** | |
* Hide other head content and non-blocking scripts | |
*/ | |
head *, | |
script[src][async], script[src][defer], script[src][type=module] { | |
display: none; | |
} |
@tpiros Yeah....very true and definitely a limitation of checking via CSS. Still handy for a quick "oh, I should double check that quick" kinda thing.
I was thinking of an alternative but nothing came to mind. Probably you can also add some minimal JS to achieve that.
I have an idea. I will post it here soon which may work nicely.
Took me a while, but here's an interesting solution. Probably longer than I wanted but gives nice, in-place detection for images. These are steps that are needed to make this work:
- Add the following to the stylesheet (OPTIONAL):
picture:after {
content: '⚠️';
margin: -1em;
font-size: xx-large;
}
- Add the following JS to the page:
document.addEventListener('DOMContentLoaded', async () => {
const isFirefox = navigator.userAgent.includes('Firefox');
const isChrome = navigator.userAgent.includes('Chrome');
const isSafari = navigator.userAgent.includes('Safari');
let accept = [];
let headers = {
'User-Agent': navigator.userAgent,
};
if (isFirefox) {
const firefoxVersion = navigator.userAgent
.split('/')
.pop()
.split('.')[0];
if (firefoxVersion >= 65) {
headers = {
...headers,
Accept: 'image/webp',
};
accept.push('image/webp');
} else {
accept.push('image/jpeg');
}
}
if (isChrome) {
headers = {
...headers,
Accept: 'image/webp',
};
accept.push('image/webp');
}
if (isSafari && !isChrome) {
accept.push('image/jp2');
}
const getImageData = async (image) => {
const response = await fetch(image.src, {
method: 'HEAD',
headers,
});
const contentType = (await response.headers
.get('content-type')
.includes(';'))
? await response.headers.get('content-type').split(';')[0]
: await response.headers.get('content-type');
const data = {
contentType,
};
return data;
};
const images = document.getElementsByTagName('img');
const wrap = (elementToWrap) => {
const wrappingElement = document.createElement('picture');
elementToWrap.parentNode.appendChild(wrappingElement);
return wrappingElement.appendChild(elementToWrap);
};
for (let image of images) {
if (!accept.includes((await getImageData(image)).contentType)) {
wrap(image);
image.style.opacity = 0.5;
}
}
});
The wrap
function is optional. Since there's no way to use the :after
pseudo-selector for an img
element, we need to wrap all img
s to a picture
element. This is only a convenient way to differentiate with the "default" opacity
behaviour specified in the original gist.
Attached is an example for an image that is served from Cloudinary:
<img
src="https://res.cloudinary.com/tamas-demo/image/upload/w_500/woman.jpg"
alt="photo of a woman"
/>
This renders the warning, since the image is viewed in Chrome but it has a JPG extension. Adding f_auto
to the URL, will render a WebP:
<img
src="https://res.cloudinary.com/tamas-demo/image/upload/w_500,f_auto/woman.jpg"
alt="photo of a woman"
/>
Please remember however that some Image CDNs do analyse the image and it may be more optimal to load a JPEG as opposed to a WebP image in Chrome as well.
This is amazing. One thing I'd like to add - there could be situations when you're using an Image CDN, in which case this check
could be a tad misleading due to the fact that some Image CDNs automagically provide you with a different content/type even though the extension is
jpg
. I know there's no way to check for the actual content-type for the image though in CSS.