I have been using the Google Webfont loader to display parts of my website with nice fonts. I have this part work fine, all of my <p> show with the font I want. However, I would like only some classes of <p> (i.e. <p class="someclass">) to show with the webfonts, and then the rest with regular font (i.e. not Google Webfonts).
What is the best way for me to achieve this? At the moment, I am using this
<script type="text/javascript">
WebFontConfig = {
google: { families: [ 'McLaren' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
'://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})();
</script>
<style type="text/css">
.wf-loading p.someclass {
font-family: serif
}
.wf-inactive p.someclass {
font-family: cursive
}
.wf-active p.someclass {
font-family: 'McLaren', cursive
}
</style>
and all <p> throughout the page display with the 'McLaren' font. I'm sure I am doing something dumb with the CSS selector but I'm not quite sure what.
Any help would be greatly appreciated. Thanks
First off you don’t necessarily need the js version of Google fonts I have just linked them through css and I have had no loading issues. Secondly, someone would need to see your body of your actual html BUT you don’t need the p prefix just add the fonts to your class .someclass{font-family:cursizve;} also like I said using css pseudo classes work better and a lot lighter on the client
Related
I've using xhtml,jsf and primefaces. I've mentioned my styles in css file. I want to add roboto font in my project. So i tried for adding font and got some solution, like adding below line in XHTML
<link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
But i don't want to add this line http://fonts.googleapis.com/cssto my code.
I want to add it through .CSS and XHTML file except web link.
Google Fonts offers three distinct ways to embed fonts, all of which are clearly described on their Quick Use page:
Standard
<link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
#import
#import url(http://fonts.googleapis.com/css?family=Roboto);
JavaScript
<script type="text/javascript">
WebFontConfig = {
google: { families: [ 'Roboto::latin' ] }
};
(function() {
var wf = document.createElement('script');
wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
'://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
wf.type = 'text/javascript';
wf.async = 'true';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(wf, s);
})(); </script>
These are the only ways to include them — or any web font for that matter.
You could go the route of using a Data URI for the font files
#font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(data:application/octet-stream;charset=utf-8;base64,<YOUR_BASE_64_ENCODED_FILES_SOURCE>) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
but that's highly discouraged as it would add unnecessary bloat to your page. Also, I'm not sure what the expected benefits of this approach would be in your case. It's usually only useful for very small binary files (~1-2k).
I am trying to make a semi-resuseable widget but I am running into a problem. I am trying to encapsulate a some CSS code inside a shadow root so that it does not affect the rest of the webpage but this CSS is used across multiple widgets so I am trying to include a remote stylesheet. None of the examples I have found use a remote style sheet and I was wondering if this was possible.
EX:
<template id="templateContent">
<head>
<link rel="stylesheet" href="css/generalStyle1.css">
</head>
<body>
<div class="affectedByGeneralStyle1"></div>
</body>
</template>
script to include template:
<div id="host"></div>
<script>
var importedData = (html_import_element).import.getElementById("templateContent");
var shadow = document.querySelector('#host').createShadowRoot();
var clone = document.importNode(importedData.content, true);
shadow.appendChild(clone);
</script>
I came across the same problem recently. What I ended up doing was using:
<template id="templateContent">
<style> #import "css/generalStyle.css"; </style>
</template>
Additional info: This worked just fine except that now I'm having some cache issues as Chrome does not seem to reload those resources after a hard reload.
Let add to the answer . Now direct tag is supported in shadow dom.
You can directly use
<link rel="stylesheet" href="yourcss1.css">
<link href="yourcss2.css" rel="stylesheet" type="text/css">
Check they has been update by whatwg and W3C
Useful link for using css in shadow dom.
https://w3c.github.io/webcomponents/spec/shadow/#inertness-of-html-elements-in-a-shadow-tree https://github.com/whatwg/html/commit/43c57866c2bbc20dc0deb15a721a28cbaad2140c
https://github.com/w3c/webcomponents/issues/628
Direct css link can be use in shadow dom
Thanks.
I added the stylesheet's link element directly to the shadow root this way:
let link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', 'whatever.css');
this.shadowRoot.appendChild(link);
It seems to work fine. (I called this from the constructor of the component.)
actually polymer has an internal utility to load css links, i have implemented a javascript function that is using polymer internal css processor,so if you want to add css links at runtime you can use it:
Polymer('my-element', {
ready: function () {
this.importCss("path/myfile.css");
},
importCss: function (path) {
var $shadow = $(this.shadowRoot);
var $head = $("<div></div>");
var $link = $("<link rel='stylesheet' type='text/css'>");
$link.attr("href", path);
$head.append($link);
var head = $head[0];
this.copySheetAttributes = Polymer.api.declaration.styles.copySheetAttributes;
Polymer.api.declaration.styles.convertSheetsToStyles.call(this, head);
var styles = Polymer.api.declaration.styles.findLoadableStyles(head);
if (styles.length) {
var templateUrl = this.baseURI;
Polymer.styleResolver.loadStyles(styles, templateUrl, function () {
var $style = $shadow.find("style");
if ($style.length > 0){
$shadow.find("style").append($head.find("style").html());
}else{
$shadow.append($head.html());
}
});
}
}
});
Note: this code needs jquery to run
I want to insert a css stylesheet with bookmarklet
javascript:(function(){var%20s=document.createElement('link');s.setAttribute('href','http://localhost/~simha/new.css');s.setAttribute('rel','stylesheet');s.setAttribute('type','text/css');document.getElementsByTagName('head')[0].appendChild(s);alert('Stylesheet%20injected!');})();
when deminified
javascript: (function () {
var s = document.createElement('link');
s.setAttribute('href', 'http://localhost/~simha/new.css');
s.setAttribute('rel', 'stylesheet');
s.setAttribute('type', 'text/css');
document.getElementsByTagName('head')[0].appendChild(s);
alert('Stylesheet injected!');
})();
I made this bookmarklet and ran, it added the link element in the head of the html, with the css href also. BUt the css rules in the new.css didnt apply. There are not changes made to the web page.
Nowadays the CSP rules are common on websites, it is better to just write the style in the bookmarklet itself. See a live example here
(function () {
var s = document.createElement('style')
s.innerText = "body { background-color: red }"
document.head.appendChild(s)
})();
I'm using v1.3.1 of PlayN. This issue is discussed in the following google groups thread but I'm not sure how to implement the suggestions proposed:
https://groups.google.com/forum/?fromgroups#!topic/playn/kiE2iEYJqM0
Perhaps someone can offer some sample code. Currently I'm following the technique referenced in the HTML link in this answer:
https://stackoverflow.com/a/9116829/1093087
My problem: on the home screen of my game, I display some text using loaded fonts. Works fine in Java version. However, in HTML version, the text doesn't display initially. On the next screen, or if I later return to the home screen, text is properly displayed. So I concluded that it was due to the asynchronous loading of fonts as discussed in the google groups thread.
My remedy was to add a splash screen that displays an image for a few seconds, giving the fonts a chance to load, before redirecting to screen with the text on it. But no matter how long I set the delay, the text is still not displayed.
Here's my HTML file which loads my game and the fonts:
<!DOCTYPE html>
<html>
<head>
<title>mygamePlayn</title>
<!-- fonts -->
<style>
#font-face {
font-family: "DroidSans-Bold";
src: url(mygame/fonts/DroidSans-Bold.ttf);
}
#font-face {
font-family: "UbuntuMono";
src: url(mygame/fonts/UbuntuMono-Bold.ttf);
}
</style>
</head>
<body bgcolor="black">
<script src="mygame/mygame.nocache.js"></script>
</body>
</html>
Here's my core Java code that generates the text that's not initially displaying (but works otherwise):
public static CanvasImage generateTextImage(String text, String fontName,
Integer fontSize, Integer fontColor, Style fontStyle, Integer padding) {
Font font = graphics().createFont(fontName, fontStyle, fontSize);
TextFormat fontFormat = new TextFormat().withFont(font).withTextColor(fontColor);
TextLayout layout = graphics().layoutText(text, fontFormat);
Integer width = (int) layout.width() + padding * 2;
Integer height = (int) layout.height() + padding * 2;
CanvasImage textImage = graphics().createImage(width, height);
textImage.canvas().drawText(layout, padding, padding);
return textImage;
}
I think I've finally figured out a solution to my problem. It required using Google WebFont Loader in the following somewhat roundabout fashion:
1) I saved the fonts -- in this case, DroidSans-Bold, Inconsolata, and UbuntuMono-Bold -- in my PlayN project's resources/fonts directory.
2) In resources/css, I add a fonts.css stylesheet where I add the #font-face definitions for my locally saved fonts. My fonts.css file:
#font-face {
font-family: DroidSans;
src: url('../fonts/DroidSans-Bold.ttf');
}
#font-face {
font-family: Inconsolata;
src: url('../fonts/Inconsolata.ttf');
}
#font-face {
font-family: UbuntuMono;
src: url('../fonts/UbuntuMono-Bold.ttf');
}
#font-face {
font-family: UbuntuMono;
font-weight: bold;
src: url('../fonts/UbuntuMono-Bold.ttf');
}
Note: I use the same value for my font-family name as that which I used for the font names in my PlayN code. For example, I load the DroidSans font in my PlayN code like this:
Font font = graphics().createFont("DroidSans", fontStyle, fontSize);
3) I then use Google WebFont Loader in my game's html file (MyGame.html) to load the fonts before the game loads. My MyGame.html file:
<!DOCTYPE html>
<html>
<head>
<title>MyGame</title>
<style>
body {
background-color:black;
color:white;
}
</style>
<!-- Google AJAX Libraries API -->
<script src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1.4.2");
google.load("webfont", "1");
WebFontConfig = {
custom: { families: ['DroidSans', 'UbuntuMono'],
urls: [ 'mygame/css/fonts.css' ]
},
loading: function() {
console.log("loading fonts");
},
fontloading: function(fontFamily, fontDescription) {
console.log("loading font: " + fontFamily + "-" + fontDescription);
},
fontactive: function(fontFamily, fontDescription) {
console.log(fontFamily + "-" + fontDescription + " is active");
},
fontinactive: function(fontFamily, fontDescription) {
console.log(fontFamily + "-" + fontDescription + " is INACTIVE");
},
active: function() {
console.log("font-loading complete");
},
};
google.setOnLoadCallback(function() {
console.log("Google onLoad callback");
WebFont.load(WebFontConfig);
});
</script>
</head>
<body>
<div id="playn-root">
<script src="mygame/mygame.nocache.js"></script>
</div>
</body>
</html>
The console logging in the WebFont.load callbacks helped verify that the fonts were successfully loaded before the PlayN game code.
I would have preferred to use WebFont Loader with the fonts served through googleapis.com, but I couldn't figure out how to sync up the references between my PlayN code and the stylesheet. (Now that I look at it, if I didn't want to host the fonts myself, I suppose I could have just used the same url listed in the googleapi.com stylesheets.) Whatever the case, this pattern seems to solve the problem.*
*For Google Chrome. I haven't tested any other browsers.
I'm using #font-face to embed fonts in my website. First the text renders as the system default, and then (once the font file has loaded presumably) the correct font renders a fraction of a second later. Is there a way to minimise/get rid of this delay, by delaying the page rendering until after fonts have loaded or similar.
Since nobody mentioned that, I believe this question needs an update. The way I managed to solve the problem was using the "preload" option supported by modern browsers.
In case someone does not need to support old browsers.
<link rel="preload" href="assets/fonts/xxx.woff" as="font" type="font/woff" crossorigin>
some useful links with more details:
https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content
http://www.bramstein.com/writing/preload-hints-for-web-fonts.html
Edit: The best approach is probably to base64 encode your fonts. This means your font will have to be loaded fully by the time your HTML is parsed and displayed. You can do this with font squirrel's webfont generator https://www.fontsquirrel.com/tools/webfont-generator by clicking "Expert" and then "base64 encode". This is how services like TypeKit work.
Original answer:
Another way to detect if fonts are loaded would be using FontLoader https://github.com/smnh/FontLoader or by copying their strategy.
They bind to the scroll event in the browser, because when the font loads it will resize the text. It uses two containing divs (that will scroll when the height changes) and a separate fallback for IE.
An alternative is to check the DOM periodically with setInterval, but using javascript events is far faster and superior.
Obviously, you might do something like set the opacity of body to 0 and then display it in once the font loads.
This is down to how the browser behaves.
First off where is your #font declared? Is it inline to your HTML, declared in a CSS sheet on the page, or (hopefully) declared in an external CSS sheet?
If it is not in an external sheet, try moving it to one (this is better practice anyway usually).
If this doesn't help, you need to ask yourself is the fraction of a second difference really significantly detrimental to the user experience? If it is, then consider JavaScript, there are a few things you might be able to do, redirects, pauses etc, but these might actually be worse than the original problem. Worse for users, and worse to maintain.
This link might help:
http://paulirish.com/2009/fighting-the-font-face-fout/
Joni Korpi has a nice article on loading fonts before the rest of the page.
http://jonikorpi.com/a-smoother-page-load/
He also uses a loading.gif to alleviate the delay so users won't get frustrated.
This code works very well for me. It uses the Font Loading API which has good support among modern browsers.
<style>
#font-face {
font-family: 'DemoFont';
font-style: normal;
font-weight: 400;
src: url("./fonts/DemoFont.eot");
src: url("./fonts/DemoFont.woff2") format("woff2"),
url("./fonts/DemoFont.woff") format("woff"),
url("./fonts/DemoFont.ttf") format("truetype");
}
.font {
font-family: 'DemoFont';
color: transparent;
}
html.font-loaded .font {
color: inherit; // Override `transparent` from .font
}
</style>
<script>
// Check if API exists
if (document && document.fonts) {
// Do not block page loading
setTimeout(function () {
document.fonts.load('16px "DemoFont"').then(() => {
// Make font using elements visible
document.documentElement.classList.add('font-loaded')
})
}, 0)
} else {
// Fallback if API does not exist
document.documentElement.classList.add('font-loaded')
}
</script>
The trick is to set the CSS color to transparent for elements using the font. Once loaded this is reset by adding font-loaded class to <html> element.
Please replace DemoFont with something meaningful for your project to get it work.
I had a similar problem while rendering to an HTML canvas, and this was my solution. It's based on the FontFace API, and similar to Holtwicks approach. The key differences are that this is a generic approach and that it will work out-of-the-box for external fonts/stylesheets (e.g. google fonts).
A couple of notes;
fonts.load( ... ) will happily resolve with an empty set of fonts if the font isn't known yet. Presumably, this happens if this code is called before the stylesheet declaring the font was added. I added a fonts.check(...) to overcome that.
This will let you await javascript execution until a font is available, so it won't work out of the box for 'normal' HTML content. You can combine this with Holtwicks answer above.
export async function waitForFontLoad(
font: string,
timeout = 1000,
interval = 10
) {
return new Promise((resolve, reject) => {
// repeatedly poll check
const poller = setInterval(async () => {
try {
await document.fonts.load(font);
} catch (err) {
reject(err);
}
if (document.fonts.check(font)) {
clearInterval(poller);
resolve(true);
}
}, interval);
setTimeout(() => clearInterval(poller), timeout);
});
}
Only IE loads first the font and then the rest of the page.
The other browsers load things concurrently for a reason. Imagine that there's a problem with the server hosting the font or with the font downloading.
You will hang your entire site until the font is loaded. On my opinion a flash of unstyled text is better than not seeing the site at all
You can use CSS font-display inside your #font-face.
The keywords for all the available values are:
auto
block
swap
fallback
optional
Giulio Mainardi has written a nice article about all of them, and which you should use where on sitepoint.
You can read it here: https://www.sitepoint.com/css-font-display-future-font-rendering-web/?utm_source=frontendfocus&utm_medium=email
Use https://github.com/typekit/webfontloader
and check the events in the configuration
https://github.com/typekit/webfontloader#configuration
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"></script>
<script>
WebFont.load({
custom: {
families: [ "CustomFont1", "CustomFont2" ]
},
active: function() {
//Render your page
}
});
</script>
while the answer posted by #fluffy works. But the interval function runs after every interval and doesn't wait for fonts.load promise to resolve, better solution would be to use recursive function
function waitForFontLoad(font: string, timeout = 1000, interval = 10) {
const startTime = Date.now();
return new Promise((resolve, reject) => {
const recursiveFn = () => {
const currTime = Date.now();
if (currTime - startTime >= timeout) {
reject("font listener timeout " + font);
} else {
document.fonts
.load(font)
.then((fonts) => {
if (fonts.length >= 1) {
resolve(true);
} else {
setTimeout(recursiveFn, interval);
}
})
.catch((err) => {
reject(err);
});
}
};
recursiveFn();
});
}
reference - webfontloader
Simplest solution
// Single font
FontLoad( ['Font name one'])
// Multiple fonts
FontLoad( ['Font name one','Another font name'])
you can use without CallBack funtion too, callback function is optional incase you want invoked inside when FontLoad function completed.
const FontLoad = async ( fonts=[] , callback=()=>{} ) => {
await fonts;
for (const font of fonts) {
document.fonts.check(`80px ${font}`)
? document.fonts.load(`80px ${font}`).then( () => { console.log( `Font: ${font} loaded ✔️` ) } )
: console.log( `Font: ${font} not founded ❌` )
}
document.fonts.ready.then(() => { console.log("Ready"); callback() })
}
FontLoad( ['Arial','FONT_NOT_FOUNDED'], ()=> console.log("External function") )
(function() {
document.getElementsByTagName("html")[0].setAttribute("class","wf-loading")
document.getElementsByTagName("html")[0].setAttribute("className","wf-loading")
})();
use this method.. use with Webfont.js
Maybe something like this:
$("body").html("<img src='ajax-loader.gif' />");
Then when the page loads, replace body's content with the actual content and hopefully, fully rendered fonts, you may have to play around with this though...