Remove specific inline CSS with pure JavaScript - javascript

I want to remove following inline CSS:
<style type="text/css">.gm-style .gm-style-cc span, .gm-style .gm-style-cc a,.gm-style .gm-style-mtc div{font-size:10px}
</style>
...
With following script i try to remove the CSS, which contains '.gm':
var inline_css = document.querySelectorAll('style[innerText*=".gm"]');
if (inline_css) {
for (var i = 0; i < inline_css.length; i++) {
inline_css[i].parentNode.removeChild(inline_css[i]);
}
}
But it don't work.

querySelectorAll returns a list of elements. From those elements you can match the inner text. And if it matches your style (at all), you may remove it. Like so:
var ar = document.querySelectorAll('style');
console.log("found styles: " + ar.length)
for(i = 0; i < ar.length; i++){
if(ar[i].innerText.match('.gm')){
ar[i].remove()
}
}
// to check it worked
var ar = document.querySelectorAll('style');
console.log("remaining syltes: " + ar.length)
<style type="text/css">.gm-style .gm-style-cc span, .gm-style .gm-style-cc a,.gm-style .gm-style-mtc div{font-size:10px}
</style>
<style type="text/css">.other .style{}
</style>
In case you have a few tags, you can pinpoint the exact one you need.

Give your <style> tag an ID, and then you'll be able to select that <style> tag with Javascript and use the remove() method to make it magically disappear. The associated styling will also be removed.
HTML:
<style type="text/css" id="style>.gm-style .gm-style-cc span, .gm-style .gm-style-cc a,.gm-style .gm-style-mtc div{font-size:10px}
</style>
JS:
var style= document.getElementById("style");
style.remove();

(() => {
'use-strict';
let needle = '.gm-style';
if ( needle === '' || needle === '{{1}}' ) {
needle = '.?';
} else if ( needle.slice(0,1) === '/' && needle.slice(-1) === '/' ) {
needle = needle.slice(1,-1);
} else {
needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
needle = new RegExp(needle);
let cssnode = () => {
let css = document.querySelectorAll('style');
for (let cs of css) {
if (cs.outerHTML.match(needle)) {
cs.remove();
}
}
};
if (document.readyState === 'interactive' || document.readyState === 'complete') {
cssnode();
} else {
addEventListener('DOMContentLoaded', cssnode);
}
})();
Has regex support too, if you need to remove multiple <style> tags.

Related

How to target divs with other content using DOM

I have a bunch of divs with some text in them.
I am trying to create a simple function that targets divs with a specific text and gives them a class. I also want to give the divs with other text a common class.
I have managed to target the divs with the specific texts, but I cant figure out how to target the divs with other texts.
This is the HTML
<h1>The divs</h1>
<div>High</div>
<div>Low</div>
<div>Medium</div>
<div>Hit 'em high</div>
<div>Medium rare</div>
<div>A funky name</div>
and this is the function
const divs = document.querySelectorAll('div');
function classChanger () {
for (let i = 0; i < divs.length; i++) {
if (divs[i].textContent === 'High') {
divs[i].classList.add('high');
} if (divs[i].textContent === 'Medium') {
divs[i].classList.add('medium');
} if (divs[i].textContent === 'Low') {
divs[i].classList.add('low');
} if (divs[i].textContent === 'anything') {
divs[i].classList.add('none');
}
}
};
classChanger();
I have tried to use several more if statemets with !== 'High' and so on, but they just overwrite the previous code.
So I am just wondering, how do I target the last three divs and give them the class none?
I have tried googling but I dont think im googling the right question, thats why I am asking here.
You can add High, Medium, and Low to an array. As you loop over the elements check to see if array includes the text (and set the class to the lowercase version of the text), otherwise add a none class.
const divs = document.querySelectorAll('div');
const range = ['High', 'Medium', 'Low'];
function classChanger() {
for (let i = 0; i < divs.length; i++) {
const text = divs[i].textContent;
if (range.includes(text)) {
divs[i].classList.add(text.toLowerCase());
} else {
divs[i].classList.add('none');
}
}
}
classChanger();
.high { color: red; }
.medium { color: orange; }
.low { color: yellow; }
.none { color: darkgray; }
<div>High</div>
<div>Low</div>
<div>Medium</div>
<div>Hit 'em high</div>
<div>Medium rare</div>
<div>A funky name</div>
You Can use an else if statement like this:
const divs = document.querySelectorAll("div");
function classChanger() {
for (let i = 0; i < divs.length; i++) {
if (divs[i].textContent === "High") {
divs[i].classList.add("high");
} else if (divs[i].textContent === "Medium") {
divs[i].classList.add("medium");
} else if (divs[i].textContent === "Low") {
divs[i].classList.add("low");
} else {
divs[i].classList.add("none");
}
}
}
classChanger();
If you want to target elements based on content, you first need to create a function for such purpose like:
function queryElementsWithFilter(selector, filterCallback) {
if (typeof selector !== 'string') throw new TypeError('param 1 must be a string')
if (typeof filterCallback !== 'function') throw new TypeError('param 2 must be a function')
const nodes = [...document.querySelectorAll(selector)]
return nodes.filter(filterCallback)
}
Now you can get the elements you want and do anything with them.
const textTokens = ['High', 'Medium', 'Low']
textTokens.forEach(textToken => {
const divCollection = queryElementsWithFilter(
'div',
node => node.textContent === textToken
)
divCollection.forEach(div => div.classList.add(textToken.toLowerCase()))
})
const unmatchedNodes = queryElementsWithFilter(
'div',
node => !textTokens.includes(node.textContent)
)
unmatchedNodes.forEach(div => div.classList.add('none'))

Highlight a text from html document

I am new to web development. Here, I want to highlight the text from the html document. I am using text-angular for showing the html document. Let's say this is a document:
<!DOCTYPE html>
<html>
<head>
<title>Example of Text Highlight</title>
<style type="text/css" media="screen">
.highlight{ background: #D3E18A;}
.light{ background-color: yellow;}
</style>
</head>
<body>
<div id="testDocument">
<p style="padding:0;color:#000000;font-size:12pt;line-height:1.0;margin-right:0;margin-left:72pt;text-indent:-72pt;font-family:"Times New Roman";margin-top:0;orphans:2;margin-bottom:0;widows:2;text-align:justify"><span style="vertical-align:baseline;font-size:11pt;font-family:"Calibri";font-weight:700">Description: </span><span style="color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Calibri";font-style:normal">Developed web app for add management.</span></p>
<span style="vertical-align:baseline;font-size:11pt;font-family:"Calibri";font-weight:700">Contribution: </span><span style="vertical-align:baseline;font-size:11pt;font-family:"Calibri";font-weight:400">It was the internal use web app for the <br>we developed the app for the add management for the. </span>
</div>
</body>
</html>
This whole document is having a div with id ="textcontent".
This is a Html document, which represents it
Description: Developed web app for add management.
Contribution: It was the internal use web app for the
we developed the app for the add management for the
Here, I am able to highlight a single word from this text. what I want is to highlight a whole text like from Description to the word, which I am getting as an input. I tried Different options like,
Currently, I have the following code with which it highlights the text which is in one span. But if the half of highlighting text is in one span and half is in another span it it is not working.
Code is like:
var InstantSearch = {
"highlight": function (container, highlightText)
{
var internalHighlighter = function (options)
{
var id = {
container: "container",
tokens: "tokens",
all: "all",
token: "token",
className: "className",
sensitiveSearch: "sensitiveSearch"
},
tokens = options[id.tokens],
allClassName = options[id.all][id.className],
allSensitiveSearch = options[id.all][id.sensitiveSearch];
function checkAndReplace(node, tokenArr, classNameAll, sensitiveSearchAll)
{
var nodeVal = node.nodeValue, parentNode = node.parentNode,
i, j, curToken, myToken, myClassName, mySensitiveSearch,
finalClassName, finalSensitiveSearch,
foundIndex, begin, matched, end,
textNode, span, isFirst;
for (i = 0, j = tokenArr.length; i < j; i++)
{
curToken = tokenArr[i];
myToken = curToken[id.token];
myClassName = curToken[id.className];
mySensitiveSearch = curToken[id.sensitiveSearch];
finalClassName = (classNameAll ? myClassName + " " + classNameAll : myClassName);
finalSensitiveSearch = (typeof sensitiveSearchAll !== "undefined" ? sensitiveSearchAll : mySensitiveSearch);
isFirst = true;
while (true)
{
if (finalSensitiveSearch)
foundIndex = nodeVal.indexOf(myToken);
else
foundIndex = nodeVal.toLowerCase().indexOf(myToken.toLowerCase());
if (foundIndex < 0)
{
if (isFirst)
break;
if (nodeVal)
{
textNode = document.createTextNode(nodeVal);
parentNode.insertBefore(textNode, node);
} // End if (nodeVal)
parentNode.removeChild(node);
break;
} // End if (foundIndex < 0)
isFirst = false;
begin = nodeVal.substring(0, foundIndex);
matched = nodeVal.substr(foundIndex, myToken.length);
if (begin)
{
textNode = document.createTextNode(begin);
parentNode.insertBefore(textNode, node);
} // End if (begin)
span = document.createElement("span");
span.className += finalClassName;
span.appendChild(document.createTextNode(matched));
parentNode.insertBefore(span, node);
nodeVal = nodeVal.substring(foundIndex + myToken.length);
} // Whend
} // Next i
}; // End Function checkAndReplace
function iterator(p)
{
if (p === null) return;
var children = Array.prototype.slice.call(p.childNodes), i, cur;
if (children.length)
{
for (i = 0; i < children.length; i++)
{
cur = children[i];
if (cur.nodeType === 3)
{
checkAndReplace(cur, tokens, allClassName, allSensitiveSearch);
}
else if (cur.nodeType === 1)
{
iterator(cur);
}
}
}
}; // End Function iterator
iterator(options[id.container]);
} // End Function highlighter
;
internalHighlighter(
{
container: container
, all:
{
className: "highlighter"
}
, tokens: [
{
token: highlightText
, className: "highlight"
, sensitiveSearch: false
}
]
}
); // End Call internalHighlighter
} // End Function highlight
};
function TestTextHighlighting(highlightText)
{
var container = document.getElementById("textcontent");
InstantSearch.highlight(container, highlightText);
}
How can I handle this?
Indeed i have catched little bit about your question, but the core of your question is about how to highlight some text that called paragraph. Like this ?
Maybe you can try this answer , this is using jquery.mark and you able to highlights the text that you want by the keywords. i hope it will helpful for you.
Here for the simple usage:
$(".context").mark("keyword");

recursively get CSS from an element and all the childs

So I would like to be able to do something like this:
getRecursiveCSS(document.getElementById('#menubar'))
And I would like it to return a string of CSS, for the main element and all the childs.
This is what I have tried: (does not work)
function fullPath(el){
var names = [];
while (el.parentNode){
if (el.id){
names.unshift('#'+el.id);
break;
}else{
if (el==el.ownerDocument.documentElement) names.unshift(el.tagName);
else{
for (var c=1,e=el;e.previousElementSibling;e=e.previousElementSibling,c++);
names.unshift(el.tagName+":nth-child("+c+")");
}
el=el.parentNode;
}
}
return names.join(" > ");
}
function styleRecursive(elements, css) {
elements = Object.prototype.toString.call(elements) === '[object Array]' ? elements: [elements];
if (elements.length == 0 || typeof elements[0] == 'undefined')
return css;
if (typeof elements[0].querySelector == 'undefined')
return css
if (typeof css == 'undefined')
css = fullPath(elements[0]) + '{' + getComputedStyle(elements[0]).cssText + '}';
else
css += fullPath(elements[0]) + '{' + getComputedStyle(elements[0]).cssText + '}';
_elements = [];
for (var i = 0; i < elements.length; i++) {
for (var ii = 0; ii < elements[i].childNodes.length; ii++)
_elements.push(elements[i].childNodes[ii]);
}
return styleRecursive(_elements, css);
};
i came up with a solution that maybe give you idea about how improve your code. In order to test driving this code I've made an element that have some children in different depths and this code traverse all children by their depth in recursive way to find/get their css. After that, all founded css plus the element name will storage in an object (JSON like) for later use.
Please Note:
1) This code is not bullet proof so you need to add a lot of conditions/checker to make it work for all kind of situations.
2) Tested in chrome.
3) Limited to classes for finding element and its children (easy to upgrade for ids and tags support)
Output:
one : {
display: "block",
position: "relative"
}
two : {
display: "inline-block",
font-family: "Montserrat"
}
three_1 : {
display: "table",
position: "absolute",
left: "0px"
}
four_1 : {
display: "table-cell",
position: "relative"
}
three_2 : {
display: "table",
position: "absolute",
right: "0px"
}
four_2 : {
display: "table-cell",
position: "relative"
}
HTML(Sample):
<div class="one">
<div class="two">
<div class="three_1">
<div class="four_1"></div>
</div>
<div class="three_2">
<div class="four_2"></div>
</div>
</div>
</div>
CSS(Sample):
.one {display:block;position:relative;}
.two {display:inline-block;font-family:'Montserrat';}
.three_1 {display:table;position:absolute;left:0;}
.three_2 {display:table;position:absolute;right:0;}
.four_1 {display:table-cell;position:relative;}
.four_2 {display:table-cell;position:relative;}
JS:
function convertObjlike(css) {
var s = {};
if (!css) return s;
css = css.split("; ");
for (var i in css) {
var l = css[i].split(": ");
s[l[0].toLowerCase()] = (l[1]);
}
return s;
}
function getCss(a) {
var sheets = document.styleSheets, o = {};
for (var i in sheets) {
var rules = sheets[i].rules || sheets[i].cssRules;
for (var r in rules) {
if (a === rules[r].selectorText) {
o = convertObjlike(rules[r].style.cssText);
}
}
}
return o;
}
var anObject = {};
function styleRecursive(element){
anObject[element.className] = (getCss('.'+element.className));
var children = element.children;
for (var i = 0; i < children.length; i++) {
styleRecursive(children[i])
}
}
styleRecursive( document.querySelector('.one') );
console.log(anObject);
Jsfiddle
EDIT: note that this solution returns the HTML copy, and not the CSS 'file'.
Here is my attempt. It gets every computed style of the element and stores it in the style attribute. It also removes the class attribute since in most cases it is used only for setting those styles (you can remove the removeAttribute call if you want). And it iterate over its children to compute recursively the resulting HTML.
The resulting HTML is huge, as a lot of styles are just the default value, and it isn't optimized for inherit styles, so every child gets all its styles again. Font faces must be imported/registred separately.
Hover effects and media queries does not get copied, since the getComputedStyle captures only the current state of the node. Relative units like vw, vh, %, etc, also gets fixed to the current absolute value. For the same reason, variables are lost and its values are used instead.
function getElemHtml(elem) {
let style = [], computed = window.getComputedStyle(elem)
for (const attr of computed) style.push(`${attr}:${computed[attr]}`)
let clone = elem.cloneNode()
clone.setAttribute('style', style.join(";"))
clone.removeAttribute('class')
let childrenHTML = ''
for (const child of elem.childNodes) childrenHTML += child.nodeType === Element.ELEMENT_NODE ? getElemHtml(child) : child.nodeType === Element.TEXT_NODE ? child.nodeValue : ''
clone.innerHTML = childrenHTML
return clone.outerHTML
}
const elem = document.querySelector("p")
const elemHtml = getElemHtml(elem)
document.querySelector("code").innerText = elemHtml
p {
width: 400px;
margin: 0 auto;
padding: 20px;
font: 2rem/2 sans-serif;
text-align: center;
background: purple;
color: white;
}
pre, code {
width: 90vw;
white-space: pre-wrap;
}
<p>Hello</p>
<pre><code></code></pre>

How to add CSS styles via JavaScript at runtime? [duplicate]

I need to create a CSS stylesheet class dynamically in JavaScript and assign it to some HTML elements like - div, table, span, tr, etc and to some controls like asp:Textbox, Dropdownlist and datalist.
Is it possible?
It would be nice with a sample.
Here is an option:
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.cssClass { color: #f00; }';
document.getElementsByTagName('head')[0].appendChild(style);
document.getElementById('someElementId').className = 'cssClass';
<div id="someElementId">test text</div>
Found a better solution, which works across all browsers.
Uses document.styleSheet to add or replace rules. Accepted answer is short and handy but this works across IE8 and less too.
function createCSSSelector (selector, style) {
if (!document.styleSheets) return;
if (document.getElementsByTagName('head').length == 0) return;
var styleSheet,mediaType;
if (document.styleSheets.length > 0) {
for (var i = 0, l = document.styleSheets.length; i < l; i++) {
if (document.styleSheets[i].disabled)
continue;
var media = document.styleSheets[i].media;
mediaType = typeof media;
if (mediaType === 'string') {
if (media === '' || (media.indexOf('screen') !== -1)) {
styleSheet = document.styleSheets[i];
}
}
else if (mediaType=='object') {
if (media.mediaText === '' || (media.mediaText.indexOf('screen') !== -1)) {
styleSheet = document.styleSheets[i];
}
}
if (typeof styleSheet !== 'undefined')
break;
}
}
if (typeof styleSheet === 'undefined') {
var styleSheetElement = document.createElement('style');
styleSheetElement.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(styleSheetElement);
for (i = 0; i < document.styleSheets.length; i++) {
if (document.styleSheets[i].disabled) {
continue;
}
styleSheet = document.styleSheets[i];
}
mediaType = typeof styleSheet.media;
}
if (mediaType === 'string') {
for (var i = 0, l = styleSheet.rules.length; i < l; i++) {
if(styleSheet.rules[i].selectorText && styleSheet.rules[i].selectorText.toLowerCase()==selector.toLowerCase()) {
styleSheet.rules[i].style.cssText = style;
return;
}
}
styleSheet.addRule(selector,style);
}
else if (mediaType === 'object') {
var styleSheetLength = (styleSheet.cssRules) ? styleSheet.cssRules.length : 0;
for (var i = 0; i < styleSheetLength; i++) {
if (styleSheet.cssRules[i].selectorText && styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase()) {
styleSheet.cssRules[i].style.cssText = style;
return;
}
}
styleSheet.insertRule(selector + '{' + style + '}', styleSheetLength);
}
}
Function is used as follows.
createCSSSelector('.mycssclass', 'display:none');
Short answer, this is compatible "on all browsers" (specifically, IE8/7):
function createClass(name,rules){
var style = document.createElement('style');
style.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(style);
if(!(style.sheet||{}).insertRule)
(style.styleSheet || style.sheet).addRule(name, rules);
else
style.sheet.insertRule(name+"{"+rules+"}",0);
}
createClass('.whatever',"background-color: green;");
And this final bit applies the class to an element:
function applyClass(name,element,doRemove){
if(typeof element.valueOf() == "string"){
element = document.getElementById(element);
}
if(!element) return;
if(doRemove){
element.className = element.className.replace(new RegExp("\\b" + name + "\\b","g"));
}else{
element.className = element.className + " " + name;
}
}
Here's a little test page as well: https://gist.github.com/shadybones/9816763
The key little bit is the fact that style elements have a "styleSheet"/"sheet" property which you can use to to add/remove rules on.
There is a light jQuery plugin which allows to generate CSS declarations: jQuery-injectCSS
In fact, it uses JSS (CSS described by JSON), but it's quite easy to handle in order to generate dynamic css stylesheets.
$.injectCSS({
"#test": {
height: 123
}
});
YUI has by far the best stylesheet utility I have seen out there. I encourage you to check it out, but here's a taste:
// style element or locally sourced link element
var sheet = YAHOO.util.StyleSheet(YAHOO.util.Selector.query('style',null,true));
sheet = YAHOO.util.StyleSheet(YAHOO.util.Dom.get('local'));
// OR the id of a style element or locally sourced link element
sheet = YAHOO.util.StyleSheet('local');
// OR string of css text
var css = ".moduleX .alert { background: #fcc; font-weight: bold; } " +
".moduleX .warn { background: #eec; } " +
".hide_messages .moduleX .alert, " +
".hide_messages .moduleX .warn { display: none; }";
sheet = new YAHOO.util.StyleSheet(css);
There are obviously other much simpler ways of changing styles on the fly such as those suggested here. If they make sense for your problem, they might be best, but there are definitely reasons why modifying CSS is a better solution. The most obvious case is when you need to modify a large number of elements. The other major case is if you need your style changes to involve the cascade. Using the DOM to modify an element will always have a higher priority. It's the sledgehammer approach and is equivalent to using the style attribute directly on the HTML element. That is not always the desired effect.
As of IE 9. You can now load a text file and set a style.innerHTML property. So essentially you can now load a css file through ajax (and get the callback) and then just set the text inside of a style tag like this.
This works in other browsers, not sure how far back. But as long as you don't need to support IE8 then it would work.
// RESULT: doesn't work in IE8 and below. Works in IE9 and other browsers.
$(document).ready(function() {
// we want to load the css as a text file and append it with a style.
$.ajax({
url:'myCss.css',
success: function(result) {
var s = document.createElement('style');
s.setAttribute('type', 'text/css');
s.innerHTML = result;
document.getElementsByTagName("head")[0].appendChild(s);
},
fail: function() {
alert('fail');
}
})
});
and then you can have it pull an external file like the myCss.css
.myClass { background:#F00; }
Using google closure:
you can just use the ccsom module:
goog.require('goog.cssom');
var css_node = goog.cssom.addCssText('.cssClass { color: #F00; }');
The javascript code attempts to be cross browser when putting the css node into the document head.
Here is Vishwanath's solution slightly rewritten with comments :
function setStyle(cssRules, aSelector, aStyle){
for(var i = 0; i < cssRules.length; i++) {
if(cssRules[i].selectorText && cssRules[i].selectorText.toLowerCase() == aSelector.toLowerCase()) {
cssRules[i].style.cssText = aStyle;
return true;
}
}
return false;
}
function createCSSSelector(selector, style) {
var doc = document;
var allSS = doc.styleSheets;
if(!allSS) return;
var headElts = doc.getElementsByTagName("head");
if(!headElts.length) return;
var styleSheet, media, iSS = allSS.length; // scope is global in a function
/* 1. search for media == "screen" */
while(iSS){ --iSS;
if(allSS[iSS].disabled) continue; /* dont take into account the disabled stylesheets */
media = allSS[iSS].media;
if(typeof media == "object")
media = media.mediaText;
if(media == "" || media=='all' || media.indexOf("screen") != -1){
styleSheet = allSS[iSS];
iSS = -1; // indication that media=="screen" was found (if not, then iSS==0)
break;
}
}
/* 2. if not found, create one */
if(iSS != -1) {
var styleSheetElement = doc.createElement("style");
styleSheetElement.type = "text/css";
headElts[0].appendChild(styleSheetElement);
styleSheet = doc.styleSheets[allSS.length]; /* take the new stylesheet to add the selector and the style */
}
/* 3. add the selector and style */
switch (typeof styleSheet.media) {
case "string":
if(!setStyle(styleSheet.rules, selector, style));
styleSheet.addRule(selector, style);
break;
case "object":
if(!setStyle(styleSheet.cssRules, selector, style));
styleSheet.insertRule(selector + "{" + style + "}", styleSheet.cssRules.length);
break;
}
One liner, attach one or many new cascading rule(s) to the document.
This example attach a cursor:pointer to every button, input, select.
document.body.appendChild(Object.assign(document.createElement("style"), {textContent: "select, button, input {cursor:pointer}"}))
https://jsfiddle.net/xk6Ut/256/
One option to dynamically create and update CSS class in JavaScript:
Using Style Element to create a CSS section
Using an ID for the style element so that we can update the CSS
class
.....
function writeStyles(styleName, cssText) {
var styleElement = document.getElementById(styleName);
if (styleElement)
document.getElementsByTagName('head')[0].removeChild(
styleElement);
styleElement = document.createElement('style');
styleElement.type = 'text/css';
styleElement.id = styleName;
styleElement.innerHTML = cssText;
document.getElementsByTagName('head')[0].appendChild(styleElement);
}
...
var cssText = '.testDIV{ height:' + height + 'px !important; }';
writeStyles('styles_js', cssText)
An interesting project which could help you out in your task is JSS.
JSS is an authoring tool for CSS which allows you to use JavaScript to describe styles in a declarative, conflict-free and reusable way. It can compile in the browser, server-side or at build time in Node.
JSS library allows you to inject in the DOM/head section using the .attach() function.
Repl online version for evaluation.
Further information on JSS.
An example:
// Use plugins.
jss.use(camelCase())
// Create your style.
const style = {
myButton: {
color: 'green'
}
}
// Compile styles, apply plugins.
const sheet = jss.createStyleSheet(style)
// If you want to render on the client, insert it into DOM.
sheet.attach()
I was looking through some of the answers here, and I couldn't find anything that automatically adds a new stylesheet if there are none, and if not simply modifies an existing one that already contains the style needed, so I made a new function (should work accross all browsers, though not tested, uses addRule and besides that only basic native JavaScript, let me know if it works):
function myCSS(data) {
var head = document.head || document.getElementsByTagName("head")[0];
if(head) {
if(data && data.constructor == Object) {
for(var k in data) {
var selector = k;
var rules = data[k];
var allSheets = document.styleSheets;
var cur = null;
var indexOfPossibleRule = null,
indexOfSheet = null;
for(var i = 0; i < allSheets.length; i++) {
indexOfPossibleRule = findIndexOfObjPropInArray("selectorText",selector,allSheets[i].cssRules);
if(indexOfPossibleRule != null) {
indexOfSheet = i;
break;
}
}
var ruleToEdit = null;
if(indexOfSheet != null) {
ruleToEdit = allSheets[indexOfSheet].cssRules[indexOfPossibleRule];
} else {
cur = document.createElement("style");
cur.type = "text/css";
head.appendChild(cur);
cur.sheet.addRule(selector,"");
ruleToEdit = cur.sheet.cssRules[0];
console.log("NOPE, but here's a new one:", cur);
}
applyCustomCSSruleListToExistingCSSruleList(rules, ruleToEdit, (err) => {
if(err) {
console.log(err);
} else {
console.log("successfully added ", rules, " to ", ruleToEdit);
}
});
}
} else {
console.log("provide one paramter as an object containing the cssStyles, like: {\"#myID\":{position:\"absolute\"}, \".myClass\":{background:\"red\"}}, etc...");
}
} else {
console.log("run this after the page loads");
}
};
then just add these 2 helper functions either inside the above function, or anywhere else:
function applyCustomCSSruleListToExistingCSSruleList(customRuleList, existingRuleList, cb) {
var err = null;
console.log("trying to apply ", customRuleList, " to ", existingRuleList);
if(customRuleList && customRuleList.constructor == Object && existingRuleList && existingRuleList.constructor == CSSStyleRule) {
for(var k in customRuleList) {
existingRuleList["style"][k] = customRuleList[k];
}
} else {
err = ("provide first argument as an object containing the selectors for the keys, and the second argument is the CSSRuleList to modify");
}
if(cb) {
cb(err);
}
}
function findIndexOfObjPropInArray(objPropKey, objPropValue, arr) {
var index = null;
for(var i = 0; i < arr.length; i++) {
if(arr[i][objPropKey] == objPropValue) {
index = i;
break;
}
}
return index;
}
(notice that in both of them I use a for loop instead of .filter, since the CSS style / rule list classes only have a length property, and no .filter method.)
Then to call it:
myCSS({
"#coby": {
position:"absolute",
color:"blue"
},
".myError": {
padding:"4px",
background:"salmon"
}
})
Let me know if it works for your browser or gives an error.
Looked through the answers and the most obvious and straight forward is missing: use document.write() to write out a chunk of CSS you need.
Here is an example (view it on codepen: http://codepen.io/ssh33/pen/zGjWga):
<style>
#import url(http://fonts.googleapis.com/css?family=Open+Sans:800);
.d, body{ font: 3vw 'Open Sans'; padding-top: 1em; }
.d {
text-align: center; background: #aaf;
margin: auto; color: #fff; overflow: hidden;
width: 12em; height: 5em;
}
</style>
<script>
function w(s){document.write(s)}
w("<style>.long-shadow { text-shadow: ");
for(var i=0; i<449; i++) {
if(i!= 0) w(","); w(i+"px "+i+"px #444");
}
w(";}</style>");
</script>
<div class="d">
<div class="long-shadow">Long Shadow<br> Short Code</div>
</div>
For the benefit of searchers; if you are using jQuery, you can do the following:
var currentOverride = $('#customoverridestyles');
if (currentOverride) {
currentOverride.remove();
}
$('body').append("<style id=\"customoverridestyles\">body{background-color:pink;}</style>");
Obviously you can change the inner css to whatever you want.
Appreciate some people prefer pure JavaScript, but it works and has been pretty robust for writing/overwriting styles dynamically.
function createCSSClass(selector, style, hoverstyle)
{
if (!document.styleSheets)
{
return;
}
if (document.getElementsByTagName("head").length == 0)
{
return;
}
var stylesheet;
var mediaType;
if (document.styleSheets.length > 0)
{
for (i = 0; i < document.styleSheets.length; i++)
{
if (document.styleSheets[i].disabled)
{
continue;
}
var media = document.styleSheets[i].media;
mediaType = typeof media;
if (mediaType == "string")
{
if (media == "" || (media.indexOf("screen") != -1))
{
styleSheet = document.styleSheets[i];
}
}
else if (mediaType == "object")
{
if (media.mediaText == "" || (media.mediaText.indexOf("screen") != -1))
{
styleSheet = document.styleSheets[i];
}
}
if (typeof styleSheet != "undefined")
{
break;
}
}
}
if (typeof styleSheet == "undefined") {
var styleSheetElement = document.createElement("style");
styleSheetElement.type = "text/css";
document.getElementsByTagName("head")[0].appendChild(styleSheetElement);
for (i = 0; i < document.styleSheets.length; i++) {
if (document.styleSheets[i].disabled) {
continue;
}
styleSheet = document.styleSheets[i];
}
var media = styleSheet.media;
mediaType = typeof media;
}
if (mediaType == "string") {
for (i = 0; i < styleSheet.rules.length; i++)
{
if (styleSheet.rules[i].selectorText.toLowerCase() == selector.toLowerCase())
{
styleSheet.rules[i].style.cssText = style;
return;
}
}
styleSheet.addRule(selector, style);
}
else if (mediaType == "object")
{
for (i = 0; i < styleSheet.cssRules.length; i++)
{
if (styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase())
{
styleSheet.cssRules[i].style.cssText = style;
return;
}
}
if (hoverstyle != null)
{
styleSheet.insertRule(selector + "{" + style + "}", 0);
styleSheet.insertRule(selector + ":hover{" + hoverstyle + "}", 1);
}
else
{
styleSheet.insertRule(selector + "{" + style + "}", 0);
}
}
}
createCSSClass(".modalPopup .header",
" background-color: " + lightest + ";" +
"height: 10%;" +
"color: White;" +
"line-height: 30px;" +
"text-align: center;" +
" width: 100%;" +
"font-weight: bold; ", null);
Here is my modular solution:
var final_style = document.createElement('style');
final_style.type = 'text/css';
function addNewStyle(selector, style){
final_style.innerHTML += selector + '{ ' + style + ' } \n';
};
function submitNewStyle(){
document.getElementsByTagName('head')[0].appendChild(final_style);
final_style = document.createElement('style');
final_style.type = 'text/css';
};
function submitNewStyleWithMedia(mediaSelector){
final_style.innerHTML = '#media(' + mediaSelector + '){\n' + final_style.innerHTML + '\n};';
submitNewStyle();
};
You basically anywhere in your code do:
addNewStyle('body', 'color: ' + color1); , where color1 is defined variable.
When you want to "post" the current CSS file you simply do submitNewStyle(),
and then you can still add more CSS later.
If you want to add it with "media queries", you have the option.
After "addingNewStyles" you simply use submitNewStyleWithMedia('min-width: 1280px');.
It was pretty useful for my use-case, as I was changing CSS of public (not mine) website according to current time. I submit one CSS file before using "active" scripts, and the rest afterwards (makes the site look kinda-like it should before accessing elements through querySelector).
This is what worked for me in Angular:
In HTML I have button with programmatically created CSS with specific ID:
<button [id]="'hoverbutton1'+item.key" [ngClass]="getHoverButtonClass()">
<mat-icon class="icon">open_in_new</mat-icon>
</button>
In typescript I created CSS and assign it to specific element with given ID:
addClasses(){
var style1 = document.createElement('style');
style1.innerHTML = '.hoverbutton'+this.item.key+' { display: none; }';
document.getElementsByTagName('head')[0].appendChild(style1);
}
getHoverButtonClass() {
return "hoverbutton"+this.item.key
}
This way I can create as many CSS classes as I want and assign them to elements individually. :)

pure javascript to check if something has hover (without setting on mouseover/out)

I have seen this jQuery syntax:
if($(element).is(':hover')) { do something}
Since I am not using jQuery, I am looking for the best way to do this in pure javascript.
I know I could keep a global variable and set/unset it using mouseover and mouseout, but I'm wondering if there is some way to inspect the element's native properties via the DOM instead? Maybe something like this:
if(element.style.className.hovered === true) {do something}
Also, it must be cross browser compatible.
Simply using element.matches(':hover') seems to work well for me, you can use a comprehensive polyfill for older browsers too: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
You can use querySelector for IE>=8:
const isHover = e => e.parentElement.querySelector(':hover') === e;
const myDiv = document.getElementById('mydiv');
document.addEventListener('mousemove', function checkHover() {
const hovered = isHover(myDiv);
if (hovered !== checkHover.hovered) {
console.log(hovered ? 'hovered' : 'not hovered');
checkHover.hovered = hovered;
}
});
.whyToCheckMe {position: absolute;left: 100px;top: 50px;}
<div id="mydiv">HoverMe
<div class="whyToCheckMe">Do I need to be checked too?</div>
</div>
to fallback I think it is ok #Kolink answer.
First you need to keep track of which elements are being hovered on. Here's one way of doing it:
(function() {
var matchfunc = null, prefixes = ["","ms","moz","webkit","o"], i, m;
for(i=0; i<prefixes.length; i++) {
m = prefixes[i]+(prefixes[i] ? "Matches" : "matches");
if( document.documentElement[m]) {matchfunc = m; break;}
m += "Selector";
if( document.documentElement[m]) {matchfunc = m; break;}
}
if( matchfunc) window.isHover = function(elem) {return elem[matchfunc](":hover");};
else {
window.onmouseover = function(e) {
e = e || window.event;
var t = e.srcElement || e.target;
while(t) {
t.hovering = true;
t = t.parentNode;
}
};
window.onmouseout = function(e) {
e = e || window.event;
var t = e.srcElement || e.target;
while(t) {
t.hovering = false;
t = t.parentNode;
}
};
window.isHover = function(elem) {return elem.hovering;};
}
})();
it occurred to me that one way to check if an element is being hovered over is to set an unused property in css :hover and then check if that property exists in javascript. its not a proper solution to the problem since it is not making use of a dom-native hover property, but it is the closest and most minimal solution i can think of.
<html>
<head>
<style type="text/css">
#hover_el
{
border: 0px solid blue;
height: 100px;
width: 100px;
background-color: blue;
}
#hover_el:hover
{
border: 0px dashed blue;
}
</style>
<script type='text/javascript'>
window.onload = function() {check_for_hover()};
function check_for_hover() {
var hover_element = document.getElementById('hover_el');
var hover_status = (getStyle(hover_element, 'border-style') === 'dashed') ? true : false;
document.getElementById('display').innerHTML = 'you are' + (hover_status ? '' : ' not') + ' hovering';
setTimeout(check_for_hover, 1000);
};
function getStyle(oElm, strCssRule) {
var strValue = "";
if(document.defaultView && document.defaultView.getComputedStyle) {
strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
}
else if(oElm.currentStyle) {
strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1) {
return p1.toUpperCase();
});
strValue = oElm.currentStyle[strCssRule];
}
return strValue;
};
</script>
</head>
<body>
<div id='hover_el'>hover here</div>
<div id='display'></div>
</body>
</html>
(function getStyle thanks to JavaScript get Styles)
if anyone can think of a better css property to use as a flag than solid/dashed please let me know. preferably the property would be one which is rarely used and cannot be inherited.
EDIT: CSS variable are probably better to use to check this. E.g.
const fps = 60;
setInterval(function() {
if(getComputedStyle(document.getElementById('my-div')).getPropertyValue('--hovered') == 1) {
document.getElementById('result').innerHTML = 'Yes';
} else {
document.getElementById('result').innerHTML = 'No';
};
}, 1000 / fps);
#my-div {
--hovered:0;
color: black;
}
#my-div:hover {
--hovered:1;
color: red;
}
<!DOCTYPE html>
<html>
<head>
<title>Detect if div is hovered with JS, using CSS variables</title>
</head>
<body>
<div id="my-div">Am I hovered?</div>
<div id="result"></div>
</body>
</html>
You can use an if statement with a querySelector. If you add ":hover" to the end of the selector, it will only return the element if it is being hovered. This means you can test if it returns null. It is like the element.matches(":hover) solution above, but I have had more success with this version.
Here is an example:
if (document.querySelector("body > p:hover") != null) {
console.log("hovered");
}
You can put it in an interval to run the code every time you hover:
setInterval(() => {
if (document.querySelector("body > p:hover") != null) {
console.log("hovered");
}
}, 10);

Categories