所以我需要得到一個(gè)我無(wú)法控制的網(wǎng)頁(yè)使用的字體列表,包括字體的src/URL。
我所知道的獲取字體的最好方法是使用documents.fonts,但是我不知道如何從documents.fonts返回的FontFace對(duì)象中獲取src/URL。
需要支持從谷歌字體加載的字體和用戶(hù)CSS加載的字體。
我不能使用它,因?yàn)間oogle樣式表給出錯(cuò)誤,無(wú)法從“CSSStyleSheet”中讀取“cssRules”屬性:由于CORS問(wèn)題,無(wú)法訪(fǎng)問(wèn)規(guī)則。
const styleSheets = Array.from(document.styleSheets);
styleSheets.forEach(styleSheet => {
const cssRules = styleSheet.cssRules;
});
我在想這是否可能。非常感謝!
對(duì)于通過(guò)& ltlink & gt或者@import,您首先需要獲取這些樣式表。
btnOutput.addEventListener('click', (e) => {
outputFontReferences()
})
async function outputFontReferences() {
let fontRefs = await getFontReferences();
textareaCSS.value = JSON.stringify(fontRefs, null, 2);
}
/**
* check all styleSheets
* external link or imported stylesheets
* need to be fetched and inlined
* to create font Files object
*/
async function getFontReferences() {
let fontFiles = [];
// inline external css
let styleSheets = await inlineExternalCss(true, true);
styleSheets.forEach((styleSheet, s) => {
let cssRules = styleSheet.cssRules;
for (let i = 0; i < cssRules.length; i++) {
let rule = cssRules[i];
let typeRule = rule.type;
// type===5: is @font-face rule
if (typeRule === 5) {
let style = rule.style;
let fontFamily = style.getPropertyValue('font-family').replaceAll('"', "");
let fontWeight = parseFloat(style.getPropertyValue('font-weight'));
let fontStyle = style.getPropertyValue('font-style');
let unicodeRange = style.getPropertyValue('unicode-range');
let src = style.getPropertyValue('src')
.split(",")
.map((val) => {
return val.split(" ")[0];
})
.filter(Boolean);
let url = "";
// extract font file URLs/paths
src.forEach((fontSrc) => {
url = fontSrc.match(/\(([^)]+)\)/)[1].replaceAll('"', "");
});
// add to fontFiles object
fontFiles.push({
origin: origins[s],
fontFamily: fontFamily,
fontWeight: fontWeight,
fontStyle: fontStyle,
src: url,
unicodeRange: unicodeRange
});
}
}
});
console.log(fontFiles);
return fontFiles;
}
/**
* inline all external stylesheets
*/
// collect all css origins
let origins = [];
async function inlineExternalCss(removeExternalCss = true) {
let styleSheets = Array.from(document.styleSheets);
/**
* stylesheet helper
* fetch external css
*/
const fetchExternalStylesheet = async(href, ind = 0) => {
let fetched = await fetch(href);
let css = await fetched.text();
let newStyle = document.createElement("style");
newStyle.classList.add("externalCSS");
let externalCss = document.head.querySelectorAll(".externalCSS");
if (!externalCss.length) {
document.head.insertBefore(newStyle, document.head.children[0]);
} else {
document.head.insertBefore(
newStyle,
externalCss[externalCss.length - 1].nextElementSibling
);
}
newStyle.textContent = `/** origin: ${href} **/\n` + css;
origins.push(href);
};
for (let i = 0; i < styleSheets.length; i++) {
let stylesheet = styleSheets[i];
let href = stylesheet.href;
// fetch external stylesheet
if (href) {
await fetchExternalStylesheet(href, i);
} else {
let cssRules = stylesheet.cssRules;
let cssRulesL = cssRules.length;
for (let r = 0; r < cssRulesL; r++) {
let rule = cssRules[r];
let type = rule.type;
// is @import rule - fetch external stylesheet
if (type === 3) {
let href = rule.href;
if (href) {
if (removeExternalCss) {
stylesheet.deleteRule(r);
cssRulesL--;
r--;
}
await fetchExternalStylesheet(href, r);
}
} else if (type === 5) {
origins.push("local");
}
}
}
}
// remove external stylesheet
if (removeExternalCss) {
let styleSheetLinks = document.querySelectorAll(
'link[href$=".css"], link[rel="stylesheet"]'
);
for (let i = 0; i < styleSheetLinks.length; i++) {
let link = styleSheetLinks[i];
await link.remove();
}
}
let styleSheetsInlined = Array.from(document.styleSheets);
return styleSheetsInlined;
}
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css');
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,500;1,300&display=swap');
body {
font-family: "Fira Sans", sans-serif;
font-weight: 400;
font-style: normal;
}
textarea {
width: 100%;
min-height: 20em;
}
<link rel="stylesheet">
<h2>Log loaded fonts referenced in CSS</h2>
<p><button id="btnOutput">list all fonts</button></p>
<textarea id="textareaCSS"></textarea>
<script>
async function outputFontReferences() {
let fontRefs = await getFontReferences();
textareaCSS.value = JSON.stringify(fontRefs, null, 2)
}
</script>