diff --git a/src/linter/images/missingFittingSrc.js b/src/linter/images/missingFittingSrc.js
index a6e1273..e6713ed 100644
--- a/src/linter/images/missingFittingSrc.js
+++ b/src/linter/images/missingFittingSrc.js
@@ -140,7 +140,12 @@ export default function(image) {
viewportRanges = viewportRanges.filter(Boolean);
- const imageSrc = item.srcset[0] ? item.srcset[0].src : item.src;
+ const srcPaths = [...(item.srcset || [])];
+ if (item.src && !srcPaths.includes(item.src)) {
+ srcPaths.push(item.src);
+ }
+
+ const srcSizes = srcPaths.filter(src => !!image.images[src]).map(src => image.images[src].size);
error(__filename, item, {
viewport: firstItem.viewport.replace(/x/g, '×'),
@@ -149,7 +154,7 @@ export default function(image) {
distance: firstItem.distance,
megapixelDistance: firstItem.megapixelDistance,
viewportRanges: viewportRanges.map(range => range[0] === range[1] ? range[0] : range.join('–')).join(', ').replace(/x/g, '×'),
- recommendation: '
' + buildRecommendation(dimensionsBySource[itemIndex], image.images[imageSrc] ? image.images[imageSrc].size : {}, Object.keys(viewportWidths).length),
+ recommendation: '
' + buildRecommendation(dimensionsBySource[itemIndex], srcSizes, Object.keys(viewportWidths).length),
recommendationContext: image.data.img === item ? '<img srcset="…">
' : 'the ' + humanReadableIndex(itemIndex) + ' <source srcset="…">
',
});
@@ -170,9 +175,9 @@ function humanReadableIndex(index) {
return index + suffixes[ordinal];
}
-function buildRecommendation(dimensions, size, viewportsCount) {
- const ratio = (size.width && size.height) ? size.height / size.width : 1;
- return computeSrcsetWidths(dimensions, ratio, viewportsCount, {
+function buildRecommendation(dimensions, sizes, viewportsCount) {
+ const ratio = (sizes[0] && sizes[0].width && sizes[0].height) ? sizes[0].height / sizes[0].width : 1;
+ return computeSrcsetWidths(dimensions, ratio, viewportsCount, sizes.map(size => size.width).filter(Boolean), {
recommendedMinWidth,
recommendedMaxWidth,
megapixelThreshold,
diff --git a/src/util/computeSrcsetWidths.js b/src/util/computeSrcsetWidths.js
index 46c4c30..fd2a7a7 100644
--- a/src/util/computeSrcsetWidths.js
+++ b/src/util/computeSrcsetWidths.js
@@ -1,6 +1,6 @@
import roundWidth from './roundWidth';
-export default function computeSrcsetWidths(dimensions, ratio, viewportsCount, {
+export default function computeSrcsetWidths(dimensions, ratio, viewportsCount, existingWidths, {
recommendedMinWidth = 0,
recommendedMaxWidth = 16384,
megapixelThreshold = 0.25,
@@ -31,12 +31,11 @@ export default function computeSrcsetWidths(dimensions, ratio, viewportsCount, {
}
});
+ fixedWidths.push(...existingWidths.filter(width => width >= minWidth && width <= maxWidth * 2));
+
fixedWidths.sort((a, b) => a < b ? -1 : 1);
if (!fixedWidths[0] || getMegapixels(minWidth) < getMegapixels(fixedWidths[0]) - megapixelThreshold) {
- if (fixedWidths[0] && getMegapixels(minWidth) + megapixelThreshold < getMegapixels(fixedWidths[0])) {
- fixedWidths.unshift(getWidth(getMegapixels(minWidth) + megapixelThreshold));
- }
fixedWidths.unshift(roundWidth(minWidth));
}
diff --git a/tests/util/computeSrcsetWidths.js b/tests/util/computeSrcsetWidths.js
index c006134..b4d0fab 100644
--- a/tests/util/computeSrcsetWidths.js
+++ b/tests/util/computeSrcsetWidths.js
@@ -9,7 +9,7 @@ var config = {
};
test('Basic srcset with single viewport', () => {
- expect(computeSrcsetWidths({'800x600': 400}, 1, 1)).toStrictEqual([400, 800]);
+ expect(computeSrcsetWidths({'800x600': 400}, 1, 1, [])).toStrictEqual([400, 800]);
});
test('Fluid 100vw square image', () => {
@@ -18,18 +18,29 @@ test('Fluid 100vw square image', () => {
dimensions[viewport+'x'+viewport] = viewport;
}
- const widths = computeSrcsetWidths(dimensions, 1, Object.keys(dimensions).length, config);
+ const widths = computeSrcsetWidths(dimensions, 1, Object.keys(dimensions).length, [], config);
expect(widths).toStrictEqual([300, 880, 1210, 1470, 1680, 1870, 2048]);
});
+test('Fluid 100vw square image with existing widths', () => {
+ const dimensions = {};
+ for (let viewport = 300; viewport < 3000; viewport+=10) {
+ dimensions[viewport+'x'+viewport] = viewport;
+ }
+
+ const widths = computeSrcsetWidths(dimensions, 1, Object.keys(dimensions).length, [10, 1200, 1999, 9999], config);
+
+ expect(widths).toStrictEqual([300, 880, 1200, 1440, 1650, 1830, 1999]);
+});
+
test('Fluid 50vw square image', () => {
const dimensions = {};
for (let viewport = 300; viewport < 3000; viewport+=10) {
dimensions[viewport+'x'+viewport] = viewport / 2;
}
- const widths = computeSrcsetWidths(dimensions, 1, Object.keys(dimensions).length, config);
+ const widths = computeSrcsetWidths(dimensions, 1, Object.keys(dimensions).length, [], config);
expect(widths).toStrictEqual([256, 890, 1230, 1500, 1700, 1880, 2048]);
});
@@ -40,7 +51,7 @@ test('Fluid 100vw 4/1 image', () => {
dimensions[viewport+'x'+viewport] = viewport;
}
- const widths = computeSrcsetWidths(dimensions, 1 / 4, Object.keys(dimensions).length, config);
+ const widths = computeSrcsetWidths(dimensions, 1 / 4, Object.keys(dimensions).length, [], config);
expect(widths).toStrictEqual([300, 1460, 2048]);
});
@@ -51,7 +62,7 @@ test('Fluid 50vw 4/1 image', () => {
dimensions[viewport+'x'+viewport] = viewport / 2;
}
- const widths = computeSrcsetWidths(dimensions, 1 / 4, Object.keys(dimensions).length, config);
+ const widths = computeSrcsetWidths(dimensions, 1 / 4, Object.keys(dimensions).length, [], config);
expect(widths).toStrictEqual([256, 1500, 2048]);
});
@@ -62,7 +73,7 @@ test('Fluid 100vw square image max-width 600', () => {
dimensions[viewport+'x'+viewport] = Math.min(600, viewport);
}
- const widths = computeSrcsetWidths(dimensions, 1, Object.keys(dimensions).length, config);
+ const widths = computeSrcsetWidths(dimensions, 1, Object.keys(dimensions).length, [], config);
expect(widths).toStrictEqual([300, 600, 950, 1200]);
});
@@ -73,7 +84,7 @@ test('Static 500/1000/1500 square image', () => {
dimensions[viewport+'x'+viewport] = Math.max(500, Math.min(1500, Math.floor(viewport / 500) * 500));
}
- const widths = computeSrcsetWidths(dimensions, 1, Object.keys(dimensions).length, config);
+ const widths = computeSrcsetWidths(dimensions, 1, Object.keys(dimensions).length, [], config);
// TODO: 1280, 1700 and 1880 should be removed for this case
expect(widths).toStrictEqual([500, 1000, 1280, 1500, 1700, 1880, 2048]);