Different font weight for different fonts - css

I use Bold, Medium and Normal font weights on my website, that's 700, 500 and 400 respectively.
I use Helvetica Neue font and as a fallback for systems that doesn't have it installed I want to use Open Sans. The problem is Open Sans doesn't have Medium style.
I want my elements that I used to define as font-weight: 500 have font-weight: 600 if the browser uses Open Sans. Is it possible somehow?
There's a similar question at Stack Overflow: How to set different font-weight for fallback font? but I'cant get the result I need using techniqe described in an accepted answer.
I need something like
#font-face {
font-family: 'semibold';
src: 'Helvetica Neue':500, 'Open Sans':600;
}
Not sure how to do it though.

You can't really define weight in a font-face declaration. Instead, font-weight is used there as a gatekeeper to match the font and not to pass styles to the element.
It seems like overkill, but you could use this JavaScript function by Sam Clarke as a starting point to see if the font is available, and then conditionally modify the font-weight following the logic that works best for your specific requirements.
For a simplified example with just these two fonts, you might set up the CSS like this:
#font-face {
font-family: h-semibold;
src: local('Helvetica Neue');
}
#font-face {
font-family: os-semibold;
src: local('Open Sans');
}
.semibold {
font-family: h-semibold, os-semibold;
}
.w5 {
font-weight: 500;
}
.w6 {
font-weight: 600;
}
Then, using the function linked above, you put something like this in your JS to conditionally load the weight classes depending on font support:
var semibold = document.querySelectorAll('.semibold');
if (isFontAvailable('h-semibold')) {
semibold.forEach(result => {
result.className += ' ' + 'w5';
});
} else {
semibold.forEach(result => {
result.className += ' ' + 'w6';
});
}
You'll doubtless work out a more elegant solution if you really need to carry it through.

Related

How to find css classes (in e.g. chrome dev tools) that use a specific font-family?

I'm currently in the process of updating all my websites from using webfonts to hosting the fonts locally by myself. This process is a little bit frustrating, because I often can't find the css classes of the webfonts. At the moment, it's more a "try and error" kind of thing, where I'm just klicking trough the google chrome dev tools and looking for the corresponding css classes. So I was wondering if there is a simple way to look in a published website via browser for the css classes of a specific font family? (I cannot search for the classes in the IDE, because in this use case the websites where developed with webflow)
EDIT: The websites in question were created with a "building block" system called "Webflow". There, the fonts are selected via graphical interfaces. Now the problem is that somewhere in these old and huge web pages there are CSS classes that use the "Lato webfont". I want to replace this font, but I can't search for used fonts in this graphical interface. What I can search for are the CSS classes. So my idea was to use the Chrome Dev Tools to find out which CSS classes used the Lato font to ultimately replace it.
Find css rules by properties
If you can't edit you site's css files globally you might at least get some sort of "cheat sheet" containing all selectors matching certain property values.
let cssRules = getCssRules();
let filterLato400 = findRulesByProperties(cssRules, {
"font-family": "Lato",
});
console.log(filterLato400);
let filterLato400Italic = findRulesByProperties(cssRules, {
"font-family": "Lato",
"font-weight": 400,
"font-style": "italic"
});
console.log(filterLato400Italic);
//get all css rules in document
function getCssRules() {
let cssText = "";
let rules = [
...(document.styleSheets[0].rules || document.styleSheets[0].cssRules)
];
let cssArr = [];
rules.forEach(function(rule) {
let selector = rule.selectorText;
let cssText = rule.cssText;
if (selector && cssText) {
let properties = cssText
.replace(selector, "")
.replace(/[{}]/g, "")
.split(";")
.map((val) => {
return val.trim();
})
.filter(Boolean)
.map((vals) => {
return vals.split(":");
});
cssArr.push({
selector: selector,
properties: properties
});
}
});
return cssArr;
}
//filter css rules by properties
function findRulesByProperties(css, filters) {
let classList = [];
css.forEach(function(rule) {
let selector = rule.selector;
let props = rule.properties;
let vals = [];
let valsFilter = [];
for (let key in filters) {
let filterName = key;
let filterValue = filters[key];
valsFilter.push(filterValue.toString());
}
for (let i = 0; i < props.length; i++) {
let prop = props[i];
let propName = prop[0];
let propValue = prop[1].trim();
if (valsFilter.indexOf(propValue) != -1) {
vals.push(propValue);
}
}
if (vals.length == valsFilter.length) {
classList.push(selector)
}
});
return `results ${classList.length}: ${classList.join(", ")} || match: ${JSON.stringify(filters)}`;
}
body {
font-family: Georgia;
}
h1 {
font-family: "Lato";
font-weight: 700;
}
h2 {
font-family: "Lato";
font-weight: 400;
}
.classLato400 {
font-family: "Lato";
font-weight: 400;
}
.classLato400italic {
font-family: "Lato";
font-weight: 400;
font-style: italic;
}
.classLato700 {
font-family: "Lato";
font-weight: 700;
}
.classRoboto400 {
font-family: "Roboto";
font-weight: 400;
}
In the above example we're searching for all rules containing font-family:Lato (and other filters like font-weight or font-style).
You could paste your main css file in the snippet to get a list of selectors matching all criteria.
Replace external #font-face rules
If I got you right and your ultimate goal is to replace externally hosted font files with local ones (e.g. to improve GDPR compliance), you don't need to get every css font-family class reference.
The most important part are the #font-face rules that are actually responsive for downloading font files.
OK that's not perfectly correct since a font file won't be downloaded unless some DOM element uses this particular font-family.
In other words, your css might actually contain a plethora of unused font-families – on the other hand if they aren't used anywhere they won't be downloaded (so browsers have a default lazyloading method for fonts).
Example: you need to replace google webfonts with locally hosted fonts
Open your devTools and switch to the "Font" tab
Now you can see a list of all downloaded font files as well as their origin (URL) and their "Initiator" – the source file, that initiated the file download. Usually this would be a <link> stylesheet reference or an #import rule within your css, but it can also be a javaScript font loader method.
By inspecting the "URL" column, we can clearly see if a font is loaded from an external host.
Clicking the "Initiator" row/entry will open the file triggering the download – this will either be a file (like a .css) you want to completely remove or just a portion of a css file (take a closer look at #font-face rules, especially the src properties).
Following the google webfonts use case/example
(actually pretty similar to other font delivery services)
obviously we need to get local copies of my previously externally hosted font files –
google web font helper might be helpful to get a ready-to-go #font-face css and a download package including all needed font files.
we need to delete all css files or #font-face or #import rules that are still referring to external file sources and replace them with custom local font file urls.
Possible shortcuts to remove external font file references:
Check your HTML/template head for undesired elements like these
(so containing an external URL like "fonts.googleapis.com"):
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght#400;700" rel="stylesheet">
or within inline <style> tags for #import rules like #import url('https://fonts.googleapis.com/css2?family=Roboto:wght#400;700')
or similar #import rules within your main css file – they should usually be found at the top of your css code.
Delete these references and replace with custom #font-face rules like so (example is based on google web font helper output using "Roboto" font-family and font-weights 400+700 ... regular and bold).
/* roboto-regular - latin */
#font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url('fonts/roboto-v30-latin-regular.woff2') format('woff2');
}
/* roboto-700 - latin */
#font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url('fonts/roboto-v30-latin-700.woff2') format('woff2');
}
Inspect the network tab once again
If everthing is working fine we should see the locally retrieved font files for each style (e.g. regular, bold, italic, bold italic etc.)
If not: double check your file paths!
Seriously, this is probably the most common source of errors. (e.g "../fonts/" or "./fonts/" or just "fonts/").

Mixin for using variable fonts

Possibly insoluble Sass/CSS problem: I am using a variable font but Chrome currently only supports font-variation-settings rather than being able to use font-weight, font-style etc I still want to use font-weight etc for old browsers that don’t support variable fonts.
I don't want to have to type out two properties everytime I set a font-style or font-weight! So I came up with some mixins:
#mixin font-weight($weight) {
font-variation-settings: "wght" $weight;
font-weight: $weight;
}
#mixin oblique($angle) {
font-variation-settings: "slnt" $angle;
font-style: oblique #{$angle + deg};
}
Obviously I will sometimes want to use both font-weight and oblique and you can’t set the same CSS property twice - it will just get overridden. So I came up with this
#mixin font-weight($weight) {
--weight: #{$weight};
font-variation-settings: "wght" var(--weight), "slnt" var(--angle, 0);
font-weight: $weight;
}
#mixin oblique($angle) {
--angle: #{$angle};
font-variation-settings: "slnt" var(--angle), "wght" var(--weight, 400);
font-style: oblique #{$angle + deg};
}
which kinda works except that defaulting to font-weight 400 isn’t ok - that is the default normal weight of browsers, but it doesn’t account for the fact that I will have probably set the font-weight somewhere else. I could just half give-up and make it a single mixin #mixin weight-and-oblique($weight, $oblique) but that is a horrible API to work with imo. Is there a solution?

CSS font-variation-settings not working

I'm currently experimenting with variable fonts. My first test was to experiment with the font-variation-settings directive, but it seems that is not working. Both on Codepen:
https://codepen.io/DailyMatters/pen/LrBvmz
This is my current CSS (it seems like the font is being loaded correctly from dropbox):
#font-face {
font-family: 'SourceSans';
src: url('https://www.dropbox.com/s/fmonith639cs931/SourceSansVariable-Roman.ttf') format('truetype');
}
html {
font-family: 'SourceSans', sans-serif;
}
p {
font-variation-settings: "wght" 999, "wdth" 125;
}
But also on Chrome.
As much as I change the "wght" axis, nothing happens. I did same tests with this same font using #font-face, and it worked on Chrome. Any reason this is not working with font-variation-settings?

Is there a way to make italic text within italic text non-italic?

Typically, the way to emphasize text within italic text is to make it non-italic. For example:
The publication of James Joyce's Ulysses was met with great controversy.
I know I can do this:
em em {
font-style: normal;
}
But that won't work if my parent italicized phrase doesn't use <em>. For instance, it won't work if I have
<p class="photo-caption">The publication of James Joyce's <em>Ulysses</em> was met with great controversy.</p>
Of course, I can do this:
.photo-caption em {
font-style: normal;
}
but this has potential maintainability problems, since every change to the parent element now also requires a change to the child element.
Is there a way to tell CSS to globally unitalicize nested italics?
The capabilities of CSS are necessarily limited so that browsers can process the rules quickly.
I think your original approach is correct, but you can address your concerns about maintainability with a CSS preprocessor, like LESS. These tools support much more advanced logic while still compiling down to lean and mean CSS.
With LESS, specifically, you could create a rule like this:
#PhotoCaptionFontStyle: italic;
/* Reverses the font style of child EM's if the parent value is italic */
.reverse-em(#parentFontStyle) when (#parentFontStyle = italic){
EM {
font-style: normal;
}
}
.photo-caption {
font-style: #PhotoCaptionFontStyle;
/* make child EMs normal if #PhotoCaptionFontStyle is "italic" */
.reverse-em(#PhotoCaptionFontStyle)
}
(for inspiration. not tested. see variables and guarded mixins)
If #PhotoCaptionFontStyle is italic, then the compiled result would look something like this:
.photo-caption {
font-style: italic;
}
.photo-caption EM {
font-style: normal;
}
If you switched #PhotoCaptionFontStyle back to normal, you'd end up with something like this:
.photo-caption {
font-style: normal;
}
/* ".photo-caption EM" is never generated
because of the guard condition */
I think the best solution is something like this:
<p class="photo-caption italic">Lorem <em>ipsum</em></p>
.italic em {font-style: normal;}

Css Font won't import online

i have a imported css font with the following code:
#font-face
{
font-family: font;
src: url('myriad pro/myriad pro/MyriadWebPro.ttf'),
url('myriad pro/myriad pro/MyriadWebPro.ttf');
}
The problem is that online doesn't work but locally works.What is causeing the problem
Try renaming the file path, for example ---> "myriad-pro/myriad-pro/MyriadWebPro.ttf". Is your css file in the folder with the font. Check if your path is right.
P.S: Remove the bottom url (that on the third line.). When I use font-face I use only two. Example: font-family: Consolas;
src: url('Consolas.ttf');
#font-face
{
font-family: MyriadPro; /* just declares a font in your stylesheet */
src: url('myriad pro/myriad pro/MyriadWebPro.ttf'),
url('myriad pro/myriad pro/MyriadWebPro.ttf');
}
body
{
/* now you need to use it */
font-family: MyriadPro, sans-serif;
/* so name it something useful, instead of just "font" */
}
answering old questions
for those who come looking after

Resources