-
Star
(129)
You must be signed in to star a gist -
Fork
(13)
You must be signed in to fork a gist
-
-
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 imgs 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.