Strapi CKEditor插件搭配Next.js时图片缩放功能不生效问题
问题根因
这个现象不是配置遗漏,是CKEditor图片缩放功能的默认行为和浏览器响应式图片渲染逻辑冲突导致的:
- CKEditor在执行缩放操作时,仅给外层
<figure>标签写入了对应缩放比例的内联宽度和image image_resized类名 - 内层
<img>标签默认生成的sizes="100vw"属性会告知浏览器:这张图始终占满100%视口宽度,浏览器会按这个规则选图、渲染,自然会溢出固定宽度的父级<figure>容器
解决方案
你可以从Strapi侧源头修正或者前端侧兼容处理两个方向解决,优先选第一个方案,历史存量内容用第二个方案兼容即可。
方案1:Strapi侧CKEditor配置修正(推荐)
- 打开Strapi项目中CKEditor的配置入口,通常为
src/admin/app.js中的自定义editor配置段,或者CKEditor插件的可视化配置页 - 新增图片元素的属性同步逻辑,在图片插入、缩放时自动把img标签的
sizes属性同步为父figure的宽度值,参考配置:
// src/admin/app.js 内的CKEditor配置示例 export default { ckeditor: { config: { image: { // 保留你原有的缩放尺寸、工具栏配置 resizeUnit: '%', resizeOptions: [ { name: 'resizeImage:original', value: null, label: '原始尺寸' }, { name: 'resizeImage:25', value: '25', label: '25%宽度' }, { name: 'resizeImage:50', value: '50', label: '50%宽度' }, { name: 'resizeImage:75', value: '75', label: '75%宽度' }, ], toolbar: ['resizeImage'] }, // 新增元素插入/更新时的属性处理 on: { change: (evt) => { const editor = evt.source; editor.model.document.on('change:data', () => { const figures = editor.editing.view.document.getRoot().getChildren(); for (const figure of figures) { if (figure.is('element', 'figure') && figure.hasClass('image_resized')) { const figureWidth = figure.getStyle('width'); const img = figure.getChild(0); if (img?.is('element', 'img') && figureWidth) { img.setAttribute('sizes', figureWidth); } } } }) } } } } }
- 重启Strapi服务、重建admin面板后,新生成的缩放图片会自动写入匹配的sizes属性,不会再出现溢出问题。
如果你使用的是版本号低于4.0的
@ckeditor/strapi-plugin-ckeditor插件,直接升级到最新稳定版即可原生修复这个sizes不同步的已知问题,不需要额外写自定义逻辑。
方案2:Next.js前端侧兼容处理
适合不想调整Strapi配置、需要兼容历史已生成富文本内容的场景,根据你的渲染方式选对应处理即可:
- 如果你用
dangerouslySetInnerHTML直接渲染富文本HTML,直接在全局CSS中加入以下样式即可修复,不需要修改HTML解析逻辑:
/* 富文本容器样式 */ .rich-content figure.image.image_resized { display: inline-block; width: fit-content; margin: 1rem 0; } .rich-content figure.image.image_resized img { max-width: 100%; width: 100%; height: auto; object-fit: contain; }
- 如果你用
html-react-parser/react-html-parser类库把富文本解析为React节点渲染,可以在解析规则中直接修正img标签的sizes属性,示例:
import parse from 'html-react-parser'; import Image from 'next/image'; export default function RichContent({ html }) { const parseOptions = { replace: (domNode) => { // 匹配缩放后的figure标签 if ( domNode.type === 'tag' && domNode.name === 'figure' && domNode.attribs.class?.includes('image_resized') ) { // 提取figure的宽度值 const widthMatch = domNode.attribs.style?.match(/width:\s*(\d+)px/); const resizedWidth = widthMatch ? Number(widthMatch[1]) : undefined; // 找到内部的img节点 const imgNode = domNode.children?.find(child => child.name === 'img'); if (imgNode && resizedWidth) { // 覆写sizes属性 imgNode.attribs.sizes = `(max-width: ${resizedWidth}px) 100vw, ${resizedWidth}px`; // 如果你要替换为next/image组件,可以在这里返回自定义节点 } } } } return <div className="rich-content">{parse(html, parseOptions)}</div> }
内容的提问来源于stack exchange,提问作者altho
相关产品推荐
相关产品推荐

