1

I want to add the following CSS to an element -

{min-height: calc(100% - 291px);
    min-height: -webkit-calc(100% - 291px);}

I would like to add this CSS to my element using Javascript. My question is, how do I add both the values without any overwrite.

element.style.minHeight= "calc(100% - 291px)";
element.style.minHeight= "-webkit-calc(100% - 291px)"; // This should NOT overwrite the previous property.

How do I achieve this? Thanks!

Archit Arora
  • 2,508
  • 7
  • 43
  • 69
  • I think your question is an intermediary to a certain goal. Can you explain? Because you're asking a vexing question and maybe there's a much easier way to implement it. – Andrew Jan 10 '18 at 02:24
  • @Andrew - I am just trying to solve a cross browser issue. One way I can achieve this is by detecting the browser using javascript and then insert only the required CSS property. But I would like to know if two properties with the same name but different values can be applied using Javascript – Archit Arora Jan 10 '18 at 02:26

4 Answers4

5

You can add styles with the classes.

.class1 {
   min-height: calc(100% - 291px);
   -webkit-min-height: calc(100% - 291px)
}

element.classList.add('class1')
Cecil
  • 351
  • 1
  • 5
  • 1
    If changing the *property name* this could also be done inline via `style`, no? The OP asked for something a little bit different originally [which is an (ab)use](https://github.com/CSSLint/csslint/wiki/Disallow-duplicate-properties) of *duplicate properties* and browser-ignored values - not trying to say that this *isn't* a good/better approach. – user2864740 Jan 10 '18 at 02:35
  • sorry, i dont know what dou you want ? – Cecil Jan 10 '18 at 02:47
2

The other answers - while providing various work-abouts - are lacking in details about "why" the original works or how to "replicate" the behavior in JavaScript. As such, this is a direct answer that avoids recommendations for non-forward compatible code.


First off, the 'duplicate CSS properties' trick works because a modern CSS engine will ignore properties with values that it does not understand.

Thus the original code can be semantically written as the following (note that the order is reversed as CSS is last-valid-and-assigned-property-values wins):

// assigns style property if value (-moz-calc..) is understood
element.style.minHeight = "-moz-calc(100% - 291px)";
if (element.style.minHeight === "") {
    // assigns style property if value (calc..) is understood
    element.style.minHeight = "calc(100% - 291px)";
}

That is, the CSS min-height property only ever has one value for the inline style.

More directly, the code could even be written without condition check. That is, the following "works" as invalid / non-understood property values should not result in an update:

element.style.minHeight = "calc(100% - 291px)";
element.style.minHeight = "foo"; // min-height NOT updated

Thus we can write the original following normal (note that "-webkit-" is first) CSS property assignment shadowing where the 'CSS standard' value will be applied if/once it is supported by a browser:

// min-height set in webkit browser only
element.style.minHeight = "-webkit-calc(100% - 291px);";
// min-height set (reset in webkit) IF AND ONLY IF browser supports calc
element.style.minHeight = "calc(100% - 291px)";

If the desire was to get "exact" browser reproduction, that can be done by assigning the style attribute directly. (In this case I've left the original CSS property order the same.)

element.setAttribute("style",
  "min-height: calc(100% - 291px); min-height: -webkit-calc(100% - 291px);");

// Only *one* of these values was assigned to the CSS style element!
console.log(element.style.minHeight)

However, using a stylesheet, even an inline one, would be my first preference.

user2864740
  • 60,010
  • 15
  • 145
  • 220
1

Seems you looking cross-browser solution from JavaScript. It is a good idea to add class from stylesheet class answered by @Cecil. But if you no way without javascript then try following approach.

var isIE = /*@cc_on!@*/false || !!document.documentMode;
var isMozilla = typeof InstallTrigger !== 'undefined';  
var isChrome = !!window.chrome && !!window.chrome.webstore;

if(isIE) {
    element.style.minHeight= "calc(100% - 291px)";
}
if(isMozilla) {
    element.style.minHeight= "calc(100% - 291px)";
}
if(isChrome) {
    element.style.minHeight= "-webkit-calc(100% - 291px)";
}

If you need more browser detect then go here: How to detect Safari, Chrome, IE, Firefox and Opera browser?

Hanif
  • 3,739
  • 1
  • 12
  • 18
  • Please no *no* **no** :} This is was only a 'good' way to handle different browsers when IE6 was a relevant thing. IE6 has been dead. – user2864740 Jan 10 '18 at 18:26
0

What you are asking for is to set the styles from the JavaScript side, such that these styles will be cross platform.

First of all, for your question, setting the same css property twice; no, this is not possible. Simply a dom element's style is an object that has some keys, each of which is assigned some value. There is no way to have the same key repeated many times in an object, similarly to what you are looking for; i.e. two values for minHeight.

The motivation behind your question is to make sure that style values set from JavaScript will work fine on different browsers. In fact, I do not think that you will need to worry about. For instance, in Firefox versions after 53, the -moz-calc() has been removed.

Assumingly that you still want to be sure and support that check when assigning some value, then you will need to check for the browser prefix; i.e. moz- for firefox, o- for opera, webkit- for chrome, and so on.
Below is an example. The check for prefix is from that link.

I know that you are aware of how to set cross-browser styles for your elements from css, which is an ideal way. However, you are more interested in doing that from JavaScript as I can see.

var prefix = (function () {
  var styles = window.getComputedStyle(document.documentElement, ''),
    pre = (Array.prototype.slice
      .call(styles)
      .join('') 
      .match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o'])
    )[1];

  return ('WebKit|Moz|MS|O').match(new RegExp('(' + pre + ')', 'i'))[1];
})();

Then you can set your element properties as follows

element.style.minHeight= previx + "-calc(100% - 291px)"
orabis
  • 2,749
  • 2
  • 13
  • 29
  • This might be usable with a *fallback* assignment of the base mode, but as per above simply setting the prefix-version is "wrong". Here is a secondary assignment example, that attempts to rely on the fact if a browser *doesn't support a CSS value* (this is how the "setting duplicate CSS property approach" works) then it won't apply/accept it: `element.style.minHeight = prefix + "-calc(100% - 291px)"; if (element.style.minHeight === "") { element.style.minHeight = "calc(100% - 291px)"; }`. YMMV, but the point is that the answer - as currently posted - is *not forward-compatible*. – user2864740 Jan 10 '18 at 18:34
  • From my end, I always try to use css. I do not use specific calc functions per browsers, and even if I did, I will do it from css. I am merely trying here to help based on the question direction; otherwise, I would have suggested using css and avoid JS. You do not like the comment that I said that Firefox removed -moz-cal. Regardless. Firefox removed it in favor of using calc directly. This does not make my comment invalid. – orabis Jan 10 '18 at 19:08