fix: html2canvas oklch/oklab 색상 파싱 에러 수정
Tailwind CSS 4의 oklch()/color-mix(in oklab) 함수를 html2canvas가 파싱하지 못하는 문제 해결 — 캡처 전 모든 요소의 색상을 브라우저 computed RGB 값으로 강제 인라인 적용 후 캡처, 완료 후 원복 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
부모
b20510599c
커밋
d3e43654e9
@ -1,5 +1,45 @@
|
|||||||
import html2canvas from 'html2canvas'
|
import html2canvas from 'html2canvas'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* html2canvas가 oklch()/oklab()/color-mix() 등 최신 CSS 색상 함수를 지원하지 않으므로
|
||||||
|
* 캡처 전 모든 요소의 색상을 브라우저 computed RGB 값으로 강제 인라인 적용.
|
||||||
|
* 캡처 후 원래 스타일로 복원하는 클린업 함수를 반환한다.
|
||||||
|
*/
|
||||||
|
const COLOR_PROPS = [
|
||||||
|
'color', 'background-color',
|
||||||
|
'border-color', 'border-top-color', 'border-right-color',
|
||||||
|
'border-bottom-color', 'border-left-color',
|
||||||
|
'outline-color', 'text-decoration-color',
|
||||||
|
]
|
||||||
|
|
||||||
|
function forceResolvedColors(root: HTMLElement): () => void {
|
||||||
|
const saved: { el: HTMLElement; cssText: string }[] = []
|
||||||
|
const allElements = [root, ...Array.from(root.querySelectorAll('*'))] as HTMLElement[]
|
||||||
|
|
||||||
|
for (const el of allElements) {
|
||||||
|
saved.push({ el, cssText: el.style.cssText })
|
||||||
|
const cs = getComputedStyle(el)
|
||||||
|
|
||||||
|
for (const prop of COLOR_PROPS) {
|
||||||
|
const val = cs.getPropertyValue(prop)
|
||||||
|
if (val && val !== 'transparent' && val !== 'rgba(0, 0, 0, 0)') {
|
||||||
|
el.style.setProperty(prop, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const shadow = cs.getPropertyValue('box-shadow')
|
||||||
|
if (shadow && shadow !== 'none') {
|
||||||
|
el.style.setProperty('box-shadow', shadow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
for (const { el, cssText } of saved) {
|
||||||
|
el.style.cssText = cssText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOM 요소를 PNG로 캡처 후 다운로드
|
* DOM 요소를 PNG로 캡처 후 다운로드
|
||||||
* @param contentEl 캡처할 콘텐츠 영역 (헤더 제외)
|
* @param contentEl 캡처할 콘텐츠 영역 (헤더 제외)
|
||||||
@ -23,6 +63,9 @@ export async function captureAndDownload(
|
|||||||
modal.style.maxHeight = 'none'
|
modal.style.maxHeight = 'none'
|
||||||
modal.style.overflow = 'visible'
|
modal.style.overflow = 'visible'
|
||||||
|
|
||||||
|
// oklch/oklab → RGB 강제 변환 (html2canvas 호환)
|
||||||
|
const restoreColors = forceResolvedColors(contentEl)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const canvas = await html2canvas(contentEl, {
|
const canvas = await html2canvas(contentEl, {
|
||||||
backgroundColor: isDark ? '#141820' : '#ffffff',
|
backgroundColor: isDark ? '#141820' : '#ffffff',
|
||||||
@ -41,6 +84,7 @@ export async function captureAndDownload(
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[captureAndDownload] 이미지 저장 실패:', err)
|
console.error('[captureAndDownload] 이미지 저장 실패:', err)
|
||||||
} finally {
|
} finally {
|
||||||
|
restoreColors()
|
||||||
contentEl.style.overflow = saved.elOverflow
|
contentEl.style.overflow = saved.elOverflow
|
||||||
modal.style.maxHeight = saved.modalMaxHeight
|
modal.style.maxHeight = saved.modalMaxHeight
|
||||||
modal.style.overflow = saved.modalOverflow
|
modal.style.overflow = saved.modalOverflow
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user