Open cxq opened 7 years ago
@cxq
Not 100% sure about this. Because this is a use case of the srcset
attribute itself. Which means the browser should handle this case automatically. Maybe file a bug report here: https://crbug.com/wizard
In case you want to try it out, you can use the optimumx plugin and use the following configuration as a start (Please let me know if you come up with a better getOptimumX
function).:
(function () {
'use strict';
function getNetInfo(){
var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection || {};
return {
saveData: connection.saveData || false,
download: connection.download || 10,
};
}
function getOptimumX(/*element*/){
var netinfo = getNetInfo();
var dpr = window.devicePixelRatio || 1;
var maxDpr = netinfo.saveData ?
dpr > 1.4 ?
1.2 :
dpr - 0.05 :
2;
if(netinfo.download < 20 || netinfo.saveData){
if(dpr > 2.6){
dpr *= 0.6; // returns 1.8 for 3
} else if(dpr > 1.9){
dpr *= 0.8; // returns 1.6 for 2
} else {
dpr -= 0.01; // returns 0.99 for 1
}
if(netinfo.download < 2 || netinfo.saveData){
dpr *= dpr > 1.5 ? 0.8 : 0.9;
} else if(netinfo.download < 5 && dpr > 1.5){
dpr *= 0.9;
}
}
return Math.min(Math.round(dpr * 100) / 100, maxDpr);
}
window.lazySizesConfig = window.lazySizesConfig || {};
window.lazySizesConfig.getOptimumX = getOptimumX;
window.lazySizesConfig.constrainPixelDensity = true;
})();
I'm playing with this since there still doesn't seem to be any support from browsers coming anytime soon.
Note: It should be connection.downlink
, connection.download
does not exist in the spec.
Here's my stab at it:
/* global arguments */
/* eslint no-restricted-modules: ["error", { "patterns": ["*"] }] */
/* eslint no-restricted-imports: ["error", { "patterns": ["*"] }] */
/**
* This file will be included by lazysizes. It is the first file loaded
* and must execute really fast. This is why we dissalow imports here.
**/
const memoizeOnce = fn => {
let value;
let lastArgs;
return () => {
if (!value || !lastArgs || lastArgs[0] !== arguments[0]) {
lastArgs = [...arguments];
value = fn(...lastArgs);
}
return value;
};
};
const EFFECTIVE_TYPES = {
'slow-2g': 0,
'2g': 1,
'3g': 2,
'4g': 3,
};
// Use this for debugging/testing.
const getItem = k => JSON.parse(localStorage.getItem(k));
const getConnection = () =>
navigator.connection || navigator.mozConnection || navigator.webkitConnection || {};
export function getNetInfo() {
const connection = getConnection();
const localSaveData = getItem('lazySizes.saveData');
const localEffectiveType = getItem('lazySizes.effectiveType');
const effectiveTypeId =
localEffectiveType || // For QA/Testing
connection.effectiveType || // For browsers that support it (Chrome, FirefoxForAndroid, Lighthouse)
'4g'; // Other browsers not supported :( fallback to default
return {
saveData: localSaveData || connection.saveData || false, // if user asked for less data usage on the user agent.
effectiveType: EFFECTIVE_TYPES[effectiveTypeId],
};
}
const getMaxDpr = (saveData, dpr) => {
if (saveData && dpr > 1.4) {
return 1.2;
} else if (saveData) {
return dpr - 0.05;
}
return dpr;
};
function getOptimumX() {
const netinfo = getNetInfo();
let dpr = window.devicePixelRatio || 1;
const ABSOLUTE_MAX_DPR = 2; // bit.ly/retina-capping
const maxDpr = getMaxDpr(netinfo.saveData, Math.min(dpr, ABSOLUTE_MAX_DPR));
// OK, I agree this looks like a bunch of magic numbers. I got those from
// https://github.com/aFarkas/lazysizes/issues/445#issuecomment-342803941
// The idea is to always have > 1 for higher dpi displays but still bring
// it down a bit if the user exhibits slow download speed or if the user
// asked for reduced data usage.
if (netinfo.effectiveType < EFFECTIVE_TYPES['4g'] || netinfo.saveData) {
if (dpr > 2.6) {
dpr *= 0.6; // returns 1.8 for 3
} else if (dpr > 1.9) {
dpr *= 0.8; // returns 1.6 for 2
} else {
dpr -= 0.01; // returns 0.99 for 1
}
// If speed is really slow, kick it down a bit more.
if (netinfo.effectiveType < EFFECTIVE_TYPES['3g']) {
dpr *= dpr > 1.5 ? 0.8 : 0.9;
}
}
return Math.min(Math.round(dpr * 100) / 100, maxDpr);
}
export default memoizeOnce(getOptimumX);
This is interesting, but the use of localStorage etc makes thing over-complicated in my opinion, is it really that expensive to retrieve that information once per page load?
@aFarkas I think you meant connection.downlink, because there is no download property.
Also, check it against any number more than 10 can be useless, MDN states that
Note that Chrome-based browsers do not conform to the specification, and arbitrarily cap the reported downlink at a maximum of 10 Mbps as an anti-fingerprinting measure. Similar caps exist for the reported latency.
That said, I think a number greater than 2 is acceptable for a normal website load? Perhaps I'm so used to the terrible internet connection here?
Hello, A new browser API is available since few time: http://wicg.github.io/netinfo/
We could be able to load a different quality of images depending on the user connection speed. If user is having 3G, we could serve a lighter image and vice-versa.
What do you think?
Thanks, Xiu