🐛 Fixed feature images in emails appearing very wide in Outlook

closes https://github.com/TryGhost/Team/issues/675

Outlook will display images at their native resolution if no `width` attribute is supplied. Content images were fixed a while ago but feature images would still render very wide and cause horizontal scroll and text size/alignment issues.

- modify `post.feature_image` and add a `post.feature_image_width` property before passing it through to the email template
  - for Unsplash images we assume all images are larger than 600px so we change the URL to reference a 1200px image and set the image width to 600 (to keep images on retina displays crisp)
  - for other images we probe the image to fetch the original dimensions and give set an image width of 600 if needed, if it's a locally-hosted image we update the URL to point at a max 1200px version
- updated email template to output a `width` attribute on the feature image `<img>` tag if it's set
This commit is contained in:
Kevin Ansfield 2021-05-14 11:57:29 +01:00
parent 7070572e4f
commit 84724537be
2 changed files with 32 additions and 1 deletions

View File

@ -9,6 +9,8 @@ const api = require('../../api');
const {URL} = require('url');
const mobiledocLib = require('../../lib/mobiledoc');
const htmlToText = require('html-to-text');
const {isUnsplashImage, isLocalContentImage} = require('@tryghost/kg-default-cards/lib/utils');
const logging = require('../../../shared/logging');
const ALLOWED_REPLACEMENTS = ['first_name'];
@ -151,6 +153,35 @@ const serialize = async (postModel, options = {isBrowserPreview: false, apiVersi
uppercaseHeadings: false
});
// Outlook will render feature images at full-size breaking the layout.
// Content images fix this by rendering max 600px images - do the same for feature image here
if (isUnsplashImage(post.feature_image)) {
// Unsplash images have a minimum size so assuming 1200px is safe
const unsplashUrl = new URL(post.feature_image);
unsplashUrl.searchParams.set('w', 1200);
post.feature_image = unsplashUrl.href;
post.feature_image_width = 600;
} else {
const {imageSize} = require('../../lib/image');
try {
const size = await imageSize.getImageSizeFromUrl(post.feature_image);
if (size.width >= 600) {
// keep original image, just set a fixed width
post.feature_image_width = 600;
}
if (isLocalContentImage(post.feature_image, urlUtils.getSiteUrl())) {
// we can safely request a 1200px image - Ghost will serve the original if it's smaller
post.feature_image = post.feature_image.replace(/\/content\/images\//, '/content/images/size/w1200/');
}
} catch (err) {
// log and proceed. Using original feature_image without fixed width isn't fatal.
logging.error(err);
}
}
const templateSettings = {
showSiteHeader: settingsCache.get('newsletter_show_header'),
bodyFontCategory: settingsCache.get('newsletter_body_font_category'),

View File

@ -914,7 +914,7 @@ ${ templateSettings.showBadge ? `
</tr>
${post.feature_image ? `
<tr>
<td class="feature-image"><img src="${post.feature_image}"></td>
<td class="feature-image"><img src="${post.feature_image}"${post.feature_image_width ? ` width="${post.feature_image_width}"` : ''}></td>
</tr>
` : ``}
<tr>