Mixin for using variable fonts - css

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?

Related

Is there a css selector for punctuation or character?

Given the element :
<span>一、對話 Dialogues</span>
One of my font is really unelegant on that side, adding an overly wide space :
Is there a css rule to style only the punctuation 、 ?
NB: I searched the web and found nothing. Currently assume only HTML elements can receive styles. So I have to use JS to get the string, then str.replace('、','<span class="punt">、</span>'), then put back the string with the dedicated html element and class. But I would like to ask the community and create this question, even if dumb, so other users may find this question/answer in the future.
You could use #Font-face and Unicode range to style your punctuation with an other font.
First, identify your characters' code :
var charcode = '、'.codePointAt(0).toString(16); // "3001"
alert(charcode) // "3001"
Then, load your default font and your support font with unicode range
/* For general characters *********************************** */
#font-face {
font-family: 'MyFont';
font-style: normal;
font-weight: 400;
src: local('Font1onPC'), /* tries to load local font file */
url('https://fonts.gstatic.com/font.woff2') format('woff2'),
url('https://fonts.gstatic.com/font.woff') format('woff');
}
/* For special characters ********************************** */
#font-face {
font-family: 'MyFont'; /* IMPORTANT: same name*/
src: local('Font2onPC'), /* tries to load local font file */
url('https://fonts.gstatic.com/anotherFont.woff2') format('woff2'),
url('https://fonts.gstatic.com/anotherFont.woff') format('woff');
unicode-range: U+3001; /* IMPORTANT */
}
Should work.
Source : https://jakearchibald.com/2017/combining-fonts/
Alternatively, you could edit that font on this character.

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?

Different font weight for different fonts

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.

Safari font rendering issues

As you can see below, the Texta-Light font in Chrome appears completely different with Safari. Chrome displays the font as I like but Safari's rendering on OS X and iOS looks too thin. The Safari image below is taken on iOS and as you can see for some reason the font appears as if there is two bits of text present.
I've looked for a solution but found nothing which works. I tried using -webkit-font-smoothing: subpixel-antialiased; but according to this question, the code isn't working anymore.
Chrome:
Safari on iOS:
Here is the code for the images above:
h2 {
font-family: 'Texta-Light', sans-serif;
font-size: 3.5em;
line-height: 1.2em;
}
Is there any solution to this?
There is a CSS property, text-rendering, which in Safari is by default set to optimizeSpeed. What you want to change is:
text-rendering:optimizeLegibility;
From https://css-tricks.com/almanac/properties/t/text-rendering/
There are four possible values:
• auto (default) - The browser makes educated guesses about when to optimize for speed, legibility, and geometric precision while drawing text. Be aware that different browsers interpret this value differently.
• optimizeSpeed - The browser emphasizes rendering speed over legibility and geometric precision when drawing text. It disables kerning and ligatures.
• optimizeLegibility - The browser emphasizes legibility over rendering speed and geometric precision. This enables the use of special kerning and optional ligature information that may be contained in the font file for certain fonts.
• geometricPrecision - The browser emphasizes geometric precision over rendering speed and legibility. Certain aspects of fonts—such as kerning—don't scale linearly, so geometricPrecision can make text using those fonts look good. When SVG font is scaled, the browser calculates pixel size, then rounds to the nearest integer. The geometricPrecision property allows for more fluid scaling. Note: Only WebKit browsers apply this fluid value, Gecko treats the value just like optimizeLegibility.
There is an additional setting -webkit-font-feature-settings, of which one of them is kerning:
-webkit-font-feature-settings
h2 {
-webkit-font-feature-settings: "kern" 1;
}
If, as per your comment, you are only serving .otf, you will need to serve the other file types too.
This could be causing an issue to do with iOs as until iOs 4.2, SVG was the only format to use custom fonts on the ipad or iphone.
#font-face {
font-family: 'MyWebFont';
src: url('webfont.eot'); /* IE9 Compat Modes */
src: url('webfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('webfont.woff2') format('woff2'), /* Super Modern Browsers */
url('webfont.woff') format('woff'), /* Pretty Modern Browsers */
url('webfont.ttf') format('truetype'), /* Safari, Android, iOS */
url('webfont.svg#svgFontName') format('svg'); /* Legacy iOS */
}
A great tool to use is Font Squirrel's Webfont Generator
Edit:
Also as mentioned in the comments the font-weight is set to bold by default and you are loading a light font.
Safari has an issue with fonts. The easiest fix for the duplicate text issue is clarifying the font-weight:
font-weight: 400;
Using Lucho's Javascript's text stroke solution along with specifying font-weight will make your text the same as it is on Chrome.
I found a post which uses JS to adjust the text-stroke property. Here is the actual code:
$(document).ready(function(){
is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
is_explorer = navigator.userAgent.indexOf('MSIE') > -1;
is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
is_safari = navigator.userAgent.indexOf("Safari") > -1;
is_opera = navigator.userAgent.indexOf("Presto") > -1;
is_mac = (navigator.userAgent.indexOf('Mac OS') != -1);
is_windows = !is_mac;
if (is_chrome && is_safari){
is_safari=false;
}
if (is_safari || is_windows){
$('body').css('-webkit-text-stroke', '0.5px');
}
});
You can modify the text-stroke of some other element.
Hope it helps.
Try this:
html, body {
text-rendering: optimizeLegibility;
}
or if like that it doesn't work,
html, body {
text-rendering: geometricPrecision;
}
I had the same issue with font rendering on Safari, the browser couldn't cant find a bold version for the web font so it was trying to copy it which may vary in the bad rendering result.
You can try to disable it by adding: this CSS:
font-synthesis: none
Otherwise you can try setting the font-weight manually to one which is available ie.
font-weight: 400
Based on #lucho's answer, I used same approach but I'm applying the fix as soon as <body> tag loads. This fixes the issue with too thin Open Sans font in iOS Safari.
<body>
<script>
(function () {
var ua = navigator.userAgent
var isIOSSafari = /iPhone|iPad|iPod/.test(ua) && /AppleWebKit.*Safari\//i.test(ua) && ua.indexOf('Chrome') === -1
if (isIOSSafari) {
document.body.style.webkitTextStroke = '.5px'
}
})()
</script>
ALTERNATIVE APPROACH:
Alternatively you can add a class like ios-safari to <html> tag and then apply CSS to it normally:
<script>
(function () {
const ua = navigator.userAgent
const isIOSSafari = /iPhone|iPad|iPod/.test(ua) && /AppleWebKit.*Safari\//i.test(ua) && !ua.includes('Chrome')
if (isIOSSafari) document.documentElement.classList.add('ios-safari')
})()
</script>
</head>
CSS:
.ios-safari {
-webkit-text-stroke: .5px;
}
Work for me!!!
.text{
font-weight: unset;
-webkit-text-stroke: thin;
}
Try it...!
A potential tested solution is to increase font-weight by a 100 iOS-wide, using a feature-query (assuming your default font weight is 400):
#supports (-webkit-touch-callout: none) {
body {
font-weight: 500;
}
}
I used this approach, which kept he font on Chromium based browsers the same as before and changes only for safari browser.
$(document).ready(function(){
if (navigator.userAgent.indexOf("Safari") == 125) {
$('body').css('-webkit-text-stroke', 'thin');
}
});

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;}

Resources