How google fonts loads fonts dynamically - javascript

In Google fonts website (https://fonts.google.com/) they add <li> elements dynamically on scroll. Those <li> elements has <a> tag with href attribute (screenshot bellow) with url value that points to the font page. Then deeper inside <li> there is <gf-content-editable> element which sets font-family CSS value to the actual font family.
Could someone explain how do they do that? Looking for a way to load fonts dynamically, but CSS Font Loading API is still experimental.
Thanks for any insights.

One way to do this would be to create an object using data from a database or any other source, and iterating over it to dynamically create cards. A bare-bones example of this could be:
const data = [
{
fontFamily: 'Open Sans',
href: 'Open+Sans+Condensed',
// Other attributes
},
// Other fonts
]
for(const font of data) {
let li, gridItemTemplate, gfFontPreview, a, section, gfContentEditable /*other elements*/;
li = document.createElement('li')
li.setAttribute('class', 'grid-list-tile is-in-last-column');
// Other attributes
gridItemTemplate = document.createElement('grid-item-template');
gfFontPreview = document.createElement('gf-font-preview')
gfFontPreview.setAttribute('class', 'grid-list-font-preview');
// Other attributes
a = document.createElement('a')
a.setAttribute('class', 'https://fonts.google.com/specimen' + font.href);
// Other attributes
section = document.createElement('section');
section.setAttribute('class', 'font-preview-card-static ...');
gfContentEditable = document.createElement('gf-content-editable')
gfContentEditable.setAttribute('class', 'preview-text-font-card static-font...')
gfContentEditable.setAttribute('style', `font-size: 40px; line-height: 1.10909; font-family: "${font.fontFamily} script=latin rev=1"; weight: 300; font-style: normal;`);
gfContentEditable.innerText = 'Almost before we knew it, we had left the ground.';
document
.body
.appendChild(li)
.appendChild(gridItemTemplate)
.appendChild(gfFontPreview)
.appendChild(a)
.appendChild(section)
.appendChild(gfContentEditable);
}
This is a pretty verbose way of writing this out. If you actually wish to create this as a function for your website, you can abstract a lot of this code out into separate functions, or use a templating engine or library to achieve this. I'm just sharing this to show how I could achieve this with just the information I have from the question.

Related

Javascript .replace method doesn't override CSS style

I've read here that when both CSS and JavaScript target the same element, then the JavaScript changes are applied over CSS.
However, I've encountered a different behaviour.
Here, we have legal case name: Johnson V United Care.
I want to convert all words to uppercase, except the "V", which I want to convert to lowercase.
This is what I want: JOHNSON v UNITED CARE.
However, in the below code, CSS uppercase style seems to override the Javascript code.
I've referred the CSS file in the <head> and the JS file just before the closing </body> tag.
What I am doing wrong?
Note: After I've posted the question, I've thought that the JS code only changes the innerHTML, and subsequently CSS style is applied to this new HTML. So, this does not seem like a priority issue. But I still can't figure how to apply JS code after CSS in order to get the correct result.
(function() {
let title = document.querySelector("h1.title>a");
let a = title.innerHTML;
let b = a.match(/\b[v]\b/i);
title.innerHTML = a.replace(b, b.toString().toLowerCase());
})();
h1.title>a {
text-transform: uppercase;
}
<h1 class="title">Johnson V United Care</h1>
I've read here that when both CSS and JavaScript target the same element, then the JavaScript changes are applied over CSS.
That article is very wrong.
Inline style has precedence over rule-sets. It doesn't matter how the two styles are added to the document. It just looks like JS has precedence because JS is used to add inline style.
What I am doing wrong?
CSS changes how the content is presented.
The CSS says it should be presented in uppercase.
It doesn't matter if, in the actual content, a particular character is lower-case because it was written that way in HTML or changed to be that way with JS.
You are changing the content with JS, and then CSS is presenting that content in uppercase.
I'd approach the problem by writing extra markup and styling that.
h1.title>a .name {
text-transform: uppercase;
}
<h1 class="title"><span class="name">Johnson</span> v <span class="name">United Care</a>
</h1>
Actually, it will not be possible to override the CSS property this way, because they are not working on the same property. You're setting the text-transform property in the CSS and in JS code you are just changing the HTML content of the element but not overriding the text-transform property. This way the precedence order will have not effect.
To solve the problem, you should do all text transformations in JS and remove the text-transform property in CSS.
Here is an example:
const title = document.querySelector('h1.title > a');
const polifyText = (str, char) =>
str
.split(' ')
.map(part => (part.includes(char) ? part.toLowerCase() : part.toUpperCase()))
.join(' ');
let newTitle = title.textContent;
let char = newTitle.match(/\b[v]\b/i);
title.textContent = polifyText(newTitle, char);
h1.title > a {
/* Comment this out */
// text-transform: uppercase;
}
<h1 class="title">Johnson v United Care
</h1>

Why can't I retrieve a CSS style property for an element using JS? [duplicate]

This question already has answers here:
Get a CSS value with JavaScript
(8 answers)
Closed 4 years ago.
So I am trying to retrieve a CSS property from the DOM and the only thing being returned is ""...
e.g. if my CSS code is
nav {
color: red;
}
and my javascript is
var nav = document.querySelector("nav");
var navColor = nav.style.color;
console.log(navColor);
All that is returned to console is "". I am new to JS.
If I try to manually make a var and find it's property in the console, it also outputs "", until I change the value of the style property, then it successfully returns the properties value - yes I have definitely set a property I am trying to retrieve and I have checked spelling hundreds of times.
Check this link: https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
const nav = document.querySelector("nav");
const { color: classStyle } = getComputedStyle(nav);
const { color: inlineStyle } = nav.style;
console.log(inlineStyle)
console.log(classStyle)
nav {
color: red;
}
<nav>this is nav</nav>
You will need to use getComputedStyle() for that:
var navColor = getComputedStyle(nav).color;
You can query the applied css rule by calling getComputedStyle(document.querySelector("nav")).color
var nav = document.querySelector("nav");
console.log(getComputedStyle(nav).color)
nav {
color: red;
}
<nav>Menu</nav>
With .style property You can't access elements css styles if the styles is not inline.
You need to use getComputedStyle function.
Usage:
var nav = document.querySelector("nav");
var navColor = getComputedStyle(nav).color;
console.log(navColor);
For more information please refer to this link
As mentioned in the comments, the style property only returns inline styles, as in:
<div style="color: red;"></div>
would return...
"color: red;"
What you're looking for is the window.getComputedStyle function, which can be used to retrieve final style values. Like so:
// HTML
<div class="some-element"></div>
// CSS
.some-element {
color: red;
}
// JS
const someElement = document.querySelector('.some-element');
console.log(window.getComputedStyle(someElement).getPropertyValue('color'));
This should log out red.
EDIT
Per comment, the output would actually be rgb(255, 0, 0), the RGB equivalent of red. As the function name suggests, it's computing styles, not retrieving their actual values. For example, if you styled with CSS a width to be 10%, getComputedStyle would calculate the pixel value of whatever the final width is rendered as. Not the best solution, but JavaScript generally doesn't need to directly interact with raw CSS files -- that should be up to the CSS and (JavaScript-controlled) classes to manage.
EDIT 2
Just an FYI, you can use .getPropertyValue('color') or just .color, I'm unaware of any preference in the dev community.

Ignore/override surrounding / inherited CSS

I have this call to add HTML/CSS to an existing page:
let div = document.createElement('div');
div.style.zIndex = 9999999;
div.innerHTML = str; // some pre-defined HTML string
document.body.insertBefore(div, document.body.firstChild);
I am creating a Chrome Extension that helps developers. What's happening is that the above HTML is inheriting the existing CSS from developer's pages. I want the styling of the above HTML to be independent from the CSS/styling on the developer's page.
Is there a way to ignore all existing CSS on page? I'd like to basically create a "CSS sandbox".
I think one way to create such a sandbox, would be an iframe, but I am looking for a simpler way to do that.
Add a class to elements which you want to reset..and then apply all:unset to that class
The all CSS shorthand property sets all of an element's properties (apart from unicode-bidi and direction) to their initial or inherited values, or to the values specified in another style sheet origin.
...all:unset
Specifies that all the element's properties should be changed to their inherited values if they inherit by default, or to their initial values if not.(It will ignore all the user agent style too.)
Stack Snippet
let p = document.createElement('p');
p.style.color = "red";
p.innerHTML = "Hello"; // some pre-defined HTML string
p.classList.add("reset");
document.body.insertBefore(p, document.body.firstChild);
p {
background: black;
}
.reset {
all: unset;
}

How to count number of lines in javascript html string variable

I have javascript variable with html string data like below format
var html_string = '<p class="MsoListParagraph" style="margin-left:28.5pt;mso-add-space:auto;text-indent:-28.5pt;mso-list:l0 level2 lfo1;tab-stops:list 28.5pt"><!--[if !supportLists]--><b><span lang="EN-US">1.1<span style="font-weight: normal; font-stretch: normal; font-size: 7pt; line-height:normal; font-family: Times New Roman;"></span></span></b><!--[endif]--><b><span lang="EN-US">Purpose of the Document<o:p></o:p></span></b></p><p class="MsoNormal" style="margin-left:28.5pt;tab-stops:80.25pt"><span lang="EN-US">This document helps to understand the design aspects of the ASSMail web based project. This document details the technical specification for the project.</span></p>';
I tried to count based on the break statement but it not work.
I want to count number of lines found in this html string for browser view. Any one please help how to do this process?
Based on your follow-up comment you can parse the content with a DOMParser, and by that get to know the number of paragraphs :
var parser = new DOMParser(),
doc = parser.parseFromString(html_string, "text/html"),
paragraphs = doc.querySelectorAll('p').length;
alert('there is '+paragraphs+' paragraphs');
demo -> http://jsfiddle.net/nfwy006u/1/
If interpret Question correctly , try creating jQuery object from html_string , using .filter() to select p elements , .length property of returned jQuery object for number of p elements in original string
$(html_string).filter("p").length
var html_string = '<p class="MsoListParagraph" style="margin-left:28.5pt;mso-add-space:auto;text-indent:-28.5pt;mso-list:l0 level2 lfo1;tab-stops:list 28.5pt"><!--[if !supportLists]--><b><span lang="EN-US">1.1<span style="font-weight: normal; font-stretch: normal; font-size: 7pt; line-height:normal; font-family: Times New Roman;"></span></span></b><!--[endif]--><b><span lang="EN-US">Purpose of the Document<o:p></o:p></span></b></p><p class="MsoNormal" style="margin-left:28.5pt;tab-stops:80.25pt"><span lang="EN-US">This document helps to understand the design aspects of the ASSMail web based project. This document details the technical specification for the project.</span></p>';
var html = $(html_string);
html.appendTo("body");
console.log(html.filter("p").length)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Find the height of the element the text is displayed in MDN dimensions of element then divide by the font height.
You can get height of div
jQuery("#id-of-your-div").height()
And then devide it to the height of one line, and it will by number of lines
For example:
jQuery("#id-of-your-div").height()/20
I think it will be hard to get how many lines are there, if your html in the variable is going to change, as some tags are inline, some tags are block. Block elements also start a new line (or can be inline css that set an inline element to be block), not just <br> tag.
So I assume you are getting the height of the div. Here is an idea:
You can insert your html on the page with display none, and get the height of it with some code like:
jQuery("#id-of-your-div").height()

Dynamically add css to page via javascript

I'm making a widget that will be added to external websites, and I have made a page that generates css for them to style it (text color, background color, font size, etc). I end up with a textarea filled with css for them to copy/paste to their website.
Is there a way to add this css to the current page in order to have a live preview?
If you want to add CSS as text
var style = document.createElement('style');
style.innerHTML = 'content';
document.head.appendChild(style);
If you want to add a CSS file
var link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', 'css/my.css');
document.head.appendChild(link);
I have traditionally appended a <style> block when doing elements.
var style_rules = [];
style_rules.push("#" + myElemId + " { /* Rules */ } ");
/* ... */
var style = '<style type="text/css">' + style_rules.join("\n") + "</style>";
$("head").append(style);
An important thing to note is that because you don't know what any of the existing styles is, or what id's might conflict on the page, it's very useful to keep track of your id's inside your JavaScript application, then using those to populate the injected <style> block. I also tend to run my names through a prefix function to ensure that the generic names of wrapper, and unit do not conflict (they are turned into something like myunique_wrapper and myunique_unit.
Incorporating a basic CSS reset like #myWrapper {margin: 0; padding: 0} can be a decent starting platform for building your own custom styles.
Addressing your unique case, a live preview so to speak, I would designate a div with standard elements. Then when they click "update" read in the rules and append them to the head. If you want to negate any residual effects from past rules you can remove the last <style> element or better yet give your <style> element an id. I'm not sure if that kind of selection would work, but it should.
var element = document.createElement('style');
element.setAttribute('type', 'text/css');
if ('textContent' in element) {
element.textContent = css;
} else {
element.styleSheet.cssText = css;
}
document.getElementsByTagName('head')[0].appendChild(element);
Can you add a style tag to the DOM, with the contents of the text-area in it? You may want to give it an id so you can change it later.
I recommend you start using a decent framework for your web/JavaScript development, personally I'd go with jQuery.
http://api.jquery.com/css/
There are some code snippets here that show you how to quickly set css properties for elements.

Categories