I want to create a Chrome/Firefox extension that allows users to change the font of webpages. Additionally, there will be other features that we are not discussing here. I have spent weeks researching this topic and have read almost every post on Stack Overflow related to it, but none of the solutions could satisfy my particular needs.
I am looking for a general solution that can be used on all websites and languages in the world. It is crucial to avoid issues that could affect the user interface. For example, changing the font of the whole screen with the "*"
selector could cause problems with icons that are in the form of fonts. Also, if there are multiple languages on a page, changing the font for one language should not affect the other languages.
I have explored several solutions, but none of them seem to meet my needs properly. Some have performance problems or are too slow, while others cannot be used because Chrome does not allow certain functions.
My general idea is to identify which elements on the page have the font family specified and update only those elements. For example, if only the body
of a page has a specific font family, we can update only that element without affecting others.
One solution I have considered is using getComputedStyle
to extract the elements of the page and add the new font family to their current font family. However, this approach has two problems. Firstly, getComputedStyle outputs all the elements affected by the font family, causing a performance problem. Secondly, if elements are loaded later (as may happen with SPA or social network pages such as LinkedIn and Twitter), MutationObserver
must be used to check if the DOM is being updated. This approach also causes performance issues.
See the code snippet below: In this piece of code, we checked all the elements of the page and categorized them based on the font. With a little change, we can solve our need and reach our goal, which is to change the page fonts to something new, but we have the problems I mentioned above.
var fonts = {};
document.querySelectorAll('*').forEach(function(element) {
var fontFamily = window.getComputedStyle(element).getPropertyValue('font-family');
fonts[fontFamily] = fonts[fontFamily] || [];
fonts[fontFamily].push(element);
});
console.log(fonts);
Another solution involves using cssRule
to identify the elements with the applied font family and update their font. However, Chrome does not allow access to cssRule due to security considerations (link1-link2). Since we are changing the font on other sites, this is a significant issue.
var proto = Element.prototype;
var slice = Function.call.bind(Array.prototype.slice);
var matches = Function.call.bind(
proto.matchesSelector ||
proto.mozMatchesSelector ||
proto.webkitMatchesSelector ||
proto.msMatchesSelector ||
proto.oMatchesSelector
);
// Returns true if a DOM Element matches a cssRule
var elementMatchCSSRule = function (element, cssRule) {
return matches(element, cssRule.selectorText);
};
// Returns true if a property is defined in a cssRule
var propertyInCSSRule = function (prop, cssRule) {
return prop in cssRule.style && cssRule.style[prop] !== '';
};
// Here we get the cssRules across all the stylesheets in one array
var cssRules = slice(document.styleSheets).reduce(function (rules, styleSheet) {
return rules.concat(slice(styleSheet.cssRules));
}, []);
// return element has font-family property
document.querySelectorAll('*').forEach(function (element) {
if (
cssRules
.filter(elementMatchCSSRule.bind(null, element))
.some(propertyInCSSRule.bind(null, 'font-family'))
) {
console.log(element);
}
});
As a beginner programmer, I am open to other solutions that could make this task easier. I have explained my problem in detail, and I appreciate any help and advice you can provide. Thank you!