How to set CSS style property in JavaScript with fallback? - javascript

In CSS, I have e.g. the following:
background-image: url("IMAGE_URL"); /* fallback */
background-image: url("IMAGE_URL"), linear-gradient(#eb01a5, #d13531); /* W3C */
I want to achieve the same effect in JavaScript. I.e. I want to set the backgroundImage property, but I also want to set a fallback. But element.style.backgroundImage does not accept a string array.
element.style.backgroundImage = 'url("IMAGE_URL"), linear-gradient(#eb01a5, #d13531)'; // How to include the fallback here?
I don't want to use hacks to check which browser the user is using. If it's not possible, I would also like to know.

Just append a <style> element using JavaScript, and insert the CSS you would have used that way:
document.head.innerHTML += `
<style>
element {
background-image: url("IMAGE_URL"); /* fallback */
background-image: url("IMAGE_URL"), linear-gradient(#eb01a5, #d13531); /* W3C */
}
</style>
`

You can probably use CSS.supports and find the first item in an array of values that returns true. Then apply that to style.
Note: not all properties can be detected - notably whether flex gap is supported. Flex box gap is recent but grid gap has been there a while so testing for ‘gap’ is ambiguous.
https://developer.mozilla.org/en-US/docs/Web/API/CSS/supports
This is effectively what the browser is doing when you provide a list.

Related

Best way to apply Style to every other div when an outside style sheet that I have no access to is coming into play?

I'm using BXSlider and attempting to change the background of every even iteration of the slider. The problem is that a css sheet that I do not have access to is affecting all sliders on the page.
Context-
<div class="bx-wrapper">
<div class="bx-viewport">
<div class="bx-slider">
</div>
</div>
</div>
Bx-wrapper and Bx-viewport are added automatically via the bxslider library.
The css sheet (that I have no access to) has the background set to #fff-
.bx-wrapper .bx-viewport {
background: #fff;
}
I am changing the background of the slider with -
.bx-wrapper .bx-viewport:nth-child(even){
background-color: rgb(245,245,245);
}
My main problem is that the original #fff takes precedence and I can only see the above css working when I un-check that style in dev tools. What do you all think the best way to ensure that the above css takes precedence?
It sounds like your style is just being overridden by the existing stylesheet, correct?
To give your style priority over the existing stylesheet, your CSS scoping should be as specific as possible and, if necessary, contain the !important property.
For example, instead of having...
.bx-wrapper .bx-viewport:nth-child(even){
background-color: rgb(245,245,245);
}
... you might want to try...
html body .bx-wrapper .bx-viewport:nth-child(even){ /*or whatever the full scope path to your elements would be*/
background-color: rgb(245,245,245) !important;
}
I hope that's what you're looking for.

How to change the background position of an element as a new CSS attribute?

I have the following code:
$(".element").css("background-position","center");
For some reason, it does not create a new attribute in CSS called background-position: center and just adds it to the background property like so:
background: center center rgb(251, 251, 251);
How do I make it so that changing the background-position will result in (like you can do in inspect element or pure css) in Javascript/jQuery:
background-position: center;
That's why sometimes we face compatibility issue among different browsers. Before, they used to be more strict of displaying non valid HTML or CSS. Nowdays, they have more tolerance to non-standard coding but they could also provide unexpected code to force their standards.
What you see is simply the way your browser is rendering your code. I think center center is the default value that the browser uses to distinguish from
center top
center bottom
Besides, Chrome inspector could be the one playing smart sometimes. This is an example of what's been "computed" after clicking the button in the following snippet :
$('#styler').on('click',function(){
$("#element").css({"background-position":"center","background-color": "transparent","background-repeat": "no-repeat","custom":"nonvalid"});
var posTxt = $('#element').css('background-position');
var pos = $('#element').css('backgroundPosition');
console.log('Text: '+posTxt);
console.log('Like Javascript: '+pos);
//It's the same value displayed using pure Javascript
var elem = document.getElementById('element');
var tab = window.getComputedStyle(elem,null).backgroundPosition.trim();
console.log('Javascript: '+tab);
});
/*already used style */
#element{
background-color: rgba(201,76,76);
width:500px;
height:500px;
padding:10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="styler">Change Style</button>
<div id="element">...</div>
[UPDATE] I added a line to this code to show how is jQuery reading the new background position value after setting it to "center". It's being displayed "50% 50%" which is the same value displayed by window.getComputedStyle().
Just to show you that with different methods even jQuery is not displaying the same property name but prefers to retrieve the computed numerical value.
which could be useful for animations, translations...
jQuery also validates those Css Properties before applying them. The code checks for any available custom jQuery.cssHooks (like these), if not it will get ignored.
To conclude, we can't control how these different programs display these properties. I think what matters is how we Set them properly.
Using jQuery to define each Background property could help you get them separated in the Inspector or override existing properties being mixed up with the one you are creating.
You can do it with css variables https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties
sample code
const Root = document.documentElement;
var h_Pos = ['center','right','left'] , nPH = 0
, v_Pos = ['center','bottom','top'] , nPV = 0
btH.onclick=_=> { nPH = ++nPH %3; Root.style.setProperty('--PosH', h_Pos[nPH]) }
btV.onclick=_=> { nPV = ++nPV %3; Root.style.setProperty('--PosV', v_Pos[nPV]) }
:root {
--PosH : center;
--PosV : center;
}
html {
height: 100%;
background: orange no-repeat var(--PosH) var(--PosV) url(https://i.picsum.photos/id/926/200/200.jpg);
}
<button id="btH"> change horizontal Position</button>
<button id="btV"> change vertical Position</button>

How can I hide browser broken default image added on empty src <img /> with css? [duplicate]

I'd like to give broken/errored images some extra CSS:
img:error {
max-width: 20px;
max-height: 20px;
}
but that doesn't work. Is there a way with pure CSS to do this? Is there an img pseudo selector for this? Or even better: a dirty hack that works?
I've looked around, but nobody seems to be wondering =)
(Yes, I know JS can do it and I know how; no need to mention it.)
There is no way in CSS specs or drafts, but Firefox has a proprietary selector (pseudo-class) :-moz-broken. Its documentation is very concise and it says “intended for use mainly by theme developers”, but it can be used e.g. as follows:
:-moz-broken { outline: solid red }
:-moz-broken:after { content: " (broken image)" }
Although the documentation says that it “matches elements representing broken image links”, it actually matches broken images (an img element where the src attribute does not refer to an image), whether they are links or not. Presumably, “links” really means “references” here.
CSS 2.1 says: “This specification does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML). This will be defined in more detail in a future specification.” But Selectors Level 3 (CSS3 Selectors) just says about them: “They are explained in CSS 2.1.” In practice, browsers handle them differently. Oddly enough, Firefox supports :-moz-broken:after but ignores :-moz-broken:before. It does not support either of these pseudo-elements for normal images, but img:after, too, is supported for a broken image (i.e., the specified content appears after the alt attribute value).
For this, you should use the alt attribute, wich shows up if link is broken and you can as well style background of image :
example:
img {
display:inline-block;
vertical-align:top;
min-height:50px;
min-width:300px;
line-height:50px;
text-align:center;
background:
linear-gradient(to bottom,
blue,
orange,
green);
font-size:2em;
box-shadow:inset 0 0 0 3px;
}
These style will be hidden when image is shown.
http://codepen.io/anon/pen/Kxipq
As you can see, we do not check for broken links, but offer alternative , usefull for blind people , searchengines, whatever , and some extra styles finishes it :)
some extra Image alt attribute best practices
<img src="not_found_image.png" onerror='this.style.display = "none"' />
from:
https://www.geeksforgeeks.org/how-to-hide-image-not-found-icon-when-source-image-is-not-found/
NO there is no :error pseudo class. This is a good site for a comprehensive list of what is available:
http://reference.sitepoint.com/css/css3psuedoclasses
July, 2015 EDIT/ADDITION:
(Thank you Rudie)
https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
No. There is nothing in CSS selectors level 2.1 or level 3 that allows targeting an image like that.
This is close:
<style>
img[data-broken="true"] {
visibility: hidden;
}
</style>
<img src="none.webp" onerror="this.setAttribute('data-broken', 'true')">
Strictly speaking, it sill uses JavaScript. But the JS is self contained in the image HTML code.

Use Javascript to Change Display Styles (CSS) Without Affecting Print Styles

I have a web application that utilizes a separate print stylesheet to control how the page looks when it comes out of the printer. That was working wonderfully until I recently made some Javascript enhancements to the site. One of these enhancements allows the user to freeze the page header and navigation, as well as table headers. The Javascript behind this does some CSS trickery to freeze the elements on the screen. Unfortunately, applying position: fixed to my header (for example) causes it to print on every page, and this is not a desired effect. How can I use Javascript to tweak element styles on the client-side without affecting the print style?
#media print { #foo { color: blue; } } /* Print definition */
#media screen { #foo { color: green; } } /* Display definition */
document.getElementById('foo').style.color = 'red'; /* Overrides both! */
Instead of changing properties on your elements with this:
document.getElementById('foo').style.color = 'red';
append a new <style> element, for example:
$('<style>#media screen { #foo { color: green; } }</style>').appendTo('head');
It would be better to concatenate all your required changes into one <style> element, if possible.
Add !important to your print rules.
You can try this
#media print { #foo { color: blue !important; } }
The problem is that javascript .style.something, edits the inline css of the element, therefore it will override the normal css class/id rules.
Or you can, work with classes.
document.getElementById('foo').className = 'redText';
and keep the .redText in your regular css file (not the print one), much much better than filling your print css with !important rules.
No good solution! What I ended up doing is utilizing the onbeforeprint and onafterprint functions in IE (I am in the position here that we only have IE users) to "unfreeze" and "refreeze" the elements...
window.onbeforeprint = function() {
document.getElementById('foo').style.position = 'static';
}
window.onload = window.onafterprint = function() {
var el = document.getElementById('foo');
// Get element position and size
// Set left/top/width/height properties
// Set position to fixed
el.style.position = 'fixed';
}
The proper solution is not to poke styles onto nodes, but to instead tie your screen-specific style tweaks to css classes that only affect your screen rendition of things:
#media screen { .freeze { position: fixed; } } /* Display-only definition */
+
document.getElementById('foo').className = "freeze";
As a bonus, this also makes it easy to change tons of styles with just one line of js, which makes things faster and easier to maintain, too.

Changing CSS pseudo-element styles via JavaScript [duplicate]

This question already has answers here:
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using javascript (or jQuery)
(26 answers)
How to update placeholder color using Javascript?
(5 answers)
Closed 2 years ago.
Is it possible to change a CSS pseudo-element style via JavaScript?
For example, I want to dynamically set the color of the scrollbar like so:
document.querySelector("#editor::-webkit-scrollbar-thumb:vertical").style.background = localStorage.getItem("Color");
and I also want to be able to tell the scrollbar to hide like so:
document.querySelector("#editor::-webkit-scrollbar").style.visibility = "hidden";
Both of these scripts, however, return:
Uncaught TypeError: Cannot read property 'style' of null
Is there some other way of going about this?
Cross-browser interoperability is not important, I just need it to work in webkit browsers.
If you're comfortable with some graceful degradation in older browsers you can use CSS Vars. Definitely the easiest of the methods I've seen here and elsewhere.
So in your CSS you can write:
#editor {
--scrollbar-background: #ccc;
}
#editor::-webkit-scrollbar-thumb:vertical {
/* Fallback */
background-color: #ccc;
/* Dynamic value */
background-color: var(--scrollbar-background);
}
Then in your JS you can manipulate that value on the #editor element:
document.getElementById("#editor").style.setProperty('--scrollbar-background', localStorage.getItem("Color"));
Lots of other examples of manipulating CSS vars with JS here: https://eager.io/blog/communicating-between-javascript-and-css-with-css-variables/
To edit an existing one which you don't have a direct reference to requires iterating all style sheets on the page and then iterating all rules in each and then string matching the selector.
Here's a reference to a method I posted for adding new CSS for pseudo-elements, the easy version where you're setting from js
Javascript set CSS :after styles
var addRule = (function (style) {
var sheet = document.head.appendChild(style).sheet;
return function (selector, css) {
var propText = typeof css === "string" ? css : Object.keys(css).map(function (p) {
return p + ":" + (p === "content" ? "'" + css[p] + "'" : css[p]);
}).join(";");
sheet.insertRule(selector + "{" + propText + "}", sheet.cssRules.length);
};
})(document.createElement("style"));
addRule("p:before", {
display: "block",
width: "100px",
height: "100px",
background: "red",
"border-radius": "50%",
content: "''"
});
sheet.insertRule returns the index of the new rule which you can use to get a reference to it for it which can be used later to edit it.
EDIT: There is technically a way of directly changing CSS pseudo-element styles via JavaScript, as this answer describes, but the method provided here is preferable.
The closest to changing the style of a pseudo-element in JavaScript is adding and removing classes, then using the pseudo-element with those classes. An example to hide the scrollbar:
CSS
.hidden-scrollbar::-webkit-scrollbar {
visibility: hidden;
}
JavaScript
document.getElementById("editor").classList.add('hidden-scrollbar');
To later remove the same class, you could use:
document.getElementById("editor").classList.remove('hidden-scrollbar');
I changed the background of the ::selection pseudo-element by using CSS custom properties doing the following:
/*CSS Part*/
:root {
--selection-background: #000000;
}
#editor::selection {
background: var(--selection-background);
}
//JavaScript Part
document.documentElement.style.setProperty("--selection-background", "#A4CDFF");
You can't apply styles to psuedo-elements in JavaScript.
You can, however, append a <style> tag to the head of your document (or have a placeholding <style id='mystyles'> and change its content), which adjusts the styles. (This would work better than loading in another stylesheet, because embedded <style> tags have higher precedence than <link>'d ones, making sure you don't get cascading problems.
Alternatively, you could use different class names and have them defined with different psuedo-element styles in the original stylesheet.
I posted a question similar to, but not completely like, this question.
I found a way to retrieve and change styles for pseudo elements and asked what people thought of the method.
My question is at Retrieving or changing css rules for pseudo elements
Basically, you can get a style via a statement such as:
document.styleSheets[0].cssRules[0].style.backgroundColor
And change one with:
document.styleSheets[0].cssRules[0].style.backgroundColor = newColor;
You, of course, have to change the stylesheet and cssRules index. Read my question and the comments it drew.
I've found this works for pseudo elements as well as "regular" element/styles.
An old question, but one I came across when try to dynamically change the colour of the content of an element's :before selector.
The simplest solution I can think of is to use CSS variables, a solution not applicable when the question was asked:
"#editor::-webkit-scrollbar-thumb:vertical {
background: --editorScrollbarClr
}
Change the value in JavaScript:
document.body.style.setProperty(
'--editorScrollbarClr',
localStorage.getItem("Color")
);
The same can be done for other properties.
Looks like querySelector won't work with pseudo-classes/pseudo-elements, at least not those. The only thing I can think of is to dynamically add a stylesheet (or change an existing one) to do what you need.
Lots of good examples here:
How do I load css rules dynamically in Webkit (Safari/Chrome)?

Categories

Resources