Workaround for CSS variables in IE? - css

I'm currently developing a web application in Outsystems in which I have the need to customize the CSS, in which I'm using variables. I need to guarantee the app works cross-browser, including in Internet Explorer. IE doesn't support CSS variables, as you can see in the picture below from this source.
Since I have to use CSS variables, is there any workaround for the usage of variables in IE?

Yes there is a way, the same way you make any css compatible: use a specific css fallback that is supported by the browser.
body {
--text-color: red;
}
body {
color: red; /* default supported fallback style */
color: var(--text-color); /* will not be used by any browser that doesn't support it, and will default to the previous fallback */
}
This solution is incredibly redundant and 'almost' defeats the purpose of css variables....BUT it is necessary for browser compatibility. Doing this would essentially make the css variables useless but I implore you to still use them because it will serve as an important reminder to the fact that these values are referenced elsewhere and need to be updated in all cases, otherwise you forget to update every related occurrence of 'color' and then you have inconsistent styling because relevant css values are out of sync. The variable will serve more as a comment but a very important one.

There is a polyfill, which enables almost complete support for CSS variables in IE11:
https://github.com/nuxodin/ie11CustomProperties
(i am the author)
The script makes use of the fact that IE has minimal custom properties support where properties can be defined and read out with the cascade in mind.
.myEl {-ie-test:'aaa'} // only one dash allowed! "-"
then read it in javascript:
getComputedStyle( querySelector('.myEl') )['-ie-test']
From the README:
Features
handles dynamic added html-content
handles dynamic added , -elements
chaining --bar:var(--foo)
fallback var(--color, blue)
:focus, :target, :hover
js-integration:
style.setProperty('--x','y')
style.getPropertyValue('--x')
getComputedStyle(el).getPropertyValue('--inherited')
Inline styles: <div ie-style="--color:blue"...
cascade works
inheritance works
under 3k (min+gzip) and dependency-free
Demo:
https://rawcdn.githack.com/nuxodin/ie11CustomProperties/b851ec2b6b8e336a78857b570d9c12a8526c9a91/test.html

In case someone comes across this, has a similar issue where I had it set like this.
a {
background: var(--new-color);
border-radius: 50%;
}
I added the background colour before the variable so if that didn't load it fell back on the hex.
a {
background: #3279B8;
background: var(--new-color);
border-radius: 50%;
}

Yes, so long as you're processing root-level custom properties (IE9+).
GitHub: https://github.com/jhildenbiddle/css-vars-ponyfill
NPM: https://www.npmjs.com/package/css-vars-ponyfill
Demo: https://codepen.io/jhildenbiddle/pen/ZxYJrR
From the README:
Features
Client-side transformation of CSS custom properties to static values
Live updates of runtime values in both modern and legacy browsers
Transforms <link>, <style>, and #import CSS
Transforms relative url() paths to absolute URLs
Supports chained and nested var() functions
Supports var() function fallback values
Supports web components / shadow DOM CSS
Watch mode auto-updates on <link> and <style> changes
UMD and ES6 module available
TypeScript definitions included
Lightweight (6k min+gzip) and dependency-free
Limitations
Custom property support is limited to :root and :host declarations
The use of var() is limited to property values (per W3C specification)
Here are a few examples of what the library can handle:
Root-level custom properties
:root {
--a: red;
}
p {
color: var(--a);
}
Chained custom properties
:root {
--a: var(--b);
--b: var(--c);
--c: red;
}
p {
color: var(--a);
}
Nested custom properties
:root {
--a: 1em;
--b: 2;
}
p {
font-size: calc(var(--a) * var(--b));
}
Fallback values
p {
font-size: var(--a, 1rem);
color: var(--b, var(--c, var(--d, red)));
}
Transforms <link>, <style>, and #import CSS
<link rel="stylesheet" href="/absolute/path/to/style.css">
<link rel="stylesheet" href="../relative/path/to/style.css">
<style>
#import "/absolute/path/to/style.css";
#import "../relative/path/to/style.css";
</style>
Transforms web components / shadow DOM
<custom-element>
#shadow-root
<style>
.my-custom-element {
color: var(--test-color);
}
</style>
<div class="my-custom-element">Hello.</div>
</custom-element>
For the sake of completeness: w3c specs
Hope this helps.
(Shameless self-promotion: Check)

Make a seperate .css file for your variables. Copy/paste the contents of the variable.css file to the end of your main.css file. Find and replace all the variable names in the main.css file to the hex code for those variables. For example: ctrl-h to find var(--myWhiteVariable) and replace with #111111.
Side note: if you keep the :root{ } in the main.css file and just comment it out, you can use that to track those hex codes later if you want to update your fallback colors.

Another way to do it is declaring colors in a JS file (in my case I'm using react) and then just use the variable you defined in the JS file.
For example:
in globals.js
export const COLORS = {
yellow: '#F4B400',
yellowLight: '#F4C849',
purple: '#7237CC',
purple1: '#A374EB',
}
in your file
import { COLORS } from 'globals'
and then just use COLORS.yellow, COLORS.purple, etc.

body {
--text-color : red; /* --text-color 정의 */
}
body {
color: var(--text-color, red); /* --text-color 정의되지 않으면 red로 대체됨 */
}
body {
color: var(--text-color, var(--text-color-other, blue));
/* --text-color, --text-color-other 가 정의되지 않으면 blue로 대체됨 */
}

There is no way yet in "normal" css but take a look at sass/scss or less.
here is a scss example
$font-stack: Helvetica, sans-serif;
$primary-color: #333;
body {
font: 100% $font-stack;
color: $primary-color;
}

I recommend setting your css variables as sass variables, then using sass interpolation to render the color in your elements.
:root {
--text-color: #123456;
}
$text-color: var(--text-color);
body {
color: #{$text-color};
}

If im not wrong there is a workaround, the CSS #ID Selector. Which should work for IE > 6 I guess.. So you can
.one { };
<div class="one">
should work as
#one {};
<div id="one">

Related

Generating CSS from Angular SCSS?

Is there a way to see the CSS that corresponds to the SCSS when we are using SCSS as the preprocessor for Angular?
There is an answer here:
When using angular with scss, how can I see the translated css?
And it mentions using the --extract-css option, however when I try that it looks like it has been deprecated:
sandbox/project $ ng build --extract-css
Unknown option: '--extract-css'
Thoughts?
Styles in Angular Build Files
In your build files the styles of components will actually be compiled in the main.js file. You can find it in the network tab of your browsers developertools.
You will also see a file called styles.css, but this will only contain your global styles. This is because of Angulars view-encapsulation of styles per component. The behavior of angular may change if you change the view-encapsulation strategy as explained here to:
Emulated (default)
ShadowDOM
None
I would not recommend doing that though.
However, if you want you can compile your sass files into css using the command line tool you can install as explained on the official sass website.
You can also just use online sass converters like thisone.
If you are just interested in the global styles here's a reference to How you can switch the format from scss to css in your browser.
Example
app.component.scss
p {
background-color: orange;
}
styles.scss
#import 'default';
p {
color: red;
&:hover {
color: blue;
}
}
default.scss
h1 {
color: teal;
}
Result in Build
styles.css:
h1 {
color: teal;
}
p {
color: red;
}
p:hover {
color: blue;
}
main.js:
AppComponent.ɵfac = function AppComponent_Factory(t) { return new (t || AppComponent)(); };
AppComponent.ɵcmp = /*#__PURE__*/ _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵdefineComponent"]({ type: AppComponent, selectors: [["app-root"]], decls: 1, vars: 0, template: function AppComponent_Template(rf, ctx) { if (rf & 1) {
_angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelement"](0, "lib-my-lib");
} }, directives: [my_lib__WEBPACK_IMPORTED_MODULE_1__.MyLibComponent], styles: ["p[_ngcontent-%COMP%] {\n background-color: orange;\n}\n/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFwcC5jb21wb25lbnQuc2NzcyIsIi4uXFwuLlxcLi5cXC4uXFxBbmd1bGFyJTIwUHJvamVjdHNcXGxpYi1leGFtcGxlXFxzcmNcXGFwcFxcYXBwLmNvbXBvbmVudC5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0VBQ0Usd0JBQUE7QUNDRiIsImZpbGUiOiJhcHAuY29tcG9uZW50LnNjc3MiLCJzb3VyY2VzQ29udGVudCI6WyJwIHtcclxuICBiYWNrZ3JvdW5kLWNvbG9yOiBvcmFuZ2U7XHJcbn1cclxuIiwicCB7XG4gIGJhY2tncm91bmQtY29sb3I6IG9yYW5nZTtcbn0iXX0= */"] });
*Note the orange background-color in the last line.
This is just a complement to the accepted answer. I wrote it up in a medium article, as it was not immediately obvious as styles.scss is opened first when selecting elements in Chrome Developer Tooling, but styles.css is in the tab right next to it.
https://fireflysemantics.medium.com/viewing-generated-global-css-for-angular-sass-projects-857a6887ff0b

Prefix css selectors for make styles from API safe

Let's assume that the user can add styles for every component in admin panel and I get it as string in my Node server:
const stylesFromAPI = ".p { color: red } .bg { background: lime }";
How to prefix this styles before append to my document to avoid conflicts?
I need something like CSS modules but working with strings (not as module loader):
const stylesFromAPI = css(".p { color: red } .bg { background: lime }"); // returns hashedClassname685946898456
<SomeCompontent className={stylesFromAPI} />
produces:
<style>
.hashedClassname685946898456 .p { color: red }
.hashedClassname685946898456 .bg { background: lime }
</style>
<div class="hashedClassname685946898456"></div>
Shadow DOM seems like a reasonable option here. You can create your style tags with inside the shadow DOM without having to deal with any selector prefixes. For example, using the react-shadow package:
import root from 'react-shadow';
Then in JSX, something like:
<root.div>
<style type="text/css">
{/* CSS string here */}
</style>
<div>
{/* Stuff here */}
</div>
</root.div>
Check out a working example of this here: https://github.com/joshdavenport/stack-overflow-61566764-react-css-shadow-dom
The main downside here is your styles from outside the shadow DOM will not apply. Those using the shadow DOM for components see this as a good thing, those simply trying to scope CSS do not. Not sure what it is you're scoping, so I can't really tell if that would be an issue for you.
If it is, you could re-import your styles within the shadow DOM, though I can't really point out how to do that without knowing what bundler is in use and how it is in use.
Alternatively you could pull apart your imported CSS using the css package, iterate over the selectors prefixing all with a randomly generated class, and then re-stringify.

LESS mixins vs classes

I'm looking into LESS because I definitely see some of their benefits. For instance colour declaration.
One thing I don't understand tho, and maybe I'm not getting the flow right is - why use the following LESS snippet
.radius {
-webkit-border-radius:5px;
-moz-border-radius:5px;
border-radius:5px;
}
.btn-red{
background-color:red;
.radius;
}
.btn-green{
background-color:green;
.radius;
}
...
When we can use the .radius class in the html file right away. I'm left with the impression that LESS will add a ton of duplicate code once it gets compiled.
I'm using the following, which makes more sense. Same with font-size, margins, etc... Aren't classes used in such cases?
<div class="btn-red radius">Cancel</div>
<div class="btn-green radius">Go</div>
The snippet above does not benefit from SASS/LESS capabilities that much. Lets have a closer look and check this SCSS snippet.
// Abstract placeholder.
%radius {
border-radius: 5px;
}
// Put your global styling here.
// I'm assuming that you can alter the markup and have button.btn.btn-green
.btn {
// Color modifier.
&-red {
#extend %radius;
background-color: red;
}
&-green {
#extend %radius;
background-color: green;
}
}
The CSS output will be:
.btn-red, .btn-green {
border-radius: 5px;
}
.btn-red {
background-color: red;
}
.btn-green {
background-color: green;
}
And then you have to pick up Autoprefixer and vendor-prefixes issue is solved once and for all.
Because now, you can just specify the class btn_red or btn_green and all the buttons will automatically have a radius.
Your HTML should contain only the semantics, and styling or classes referring to styling should not be part of it.
That applies to the other classes as well. If for instance, you would rename btn_red to btn_cancel, you have a meaningful classname that you can apply to any kind of cancel button. And in the CSS you can specify that a cancel button is red and a 'Go' button is green, and both have a radius, without needing to modify the HTML at all.
So, the ultimate goal is to have the HTML describe the structure and the CSS describe how that structure should look. And a CSS preprocessor is only their to make a bulky spaghetti-like CSS file more structured.
There are several benefits.
You can use more semantic class names. Rather than encoding style information directly in your class names, (btn-red, radius) you could use a single class that conveys the usage of the style, rather than its contents.
You can avoid repeating yourself.
#radius-size: 5px;
-webkit-border-radius:#radius-size;
-moz-border-radius:#radius-size;
border-radius:#radius-size;
You can parameterize it so that you'd be able to use different radiuses (radii?) in different contexts.
.radius(#radius-size) { ... }
Because there are cases that developer has-no-access or don't-want to change the markup. and the only solution is to include all props from a predefined class.
for example:
you have bootstrap loaded (then you already have .has-success and .has-error classes) and if you want to use HTML5's native form validation using input's :valid and :invalid states, you have to use JavaScript to add/remove success/error classes based on input's states. but with this feature of LESS you can include all props of success/error class inside input's states. the code for this example could be something like this:
#myinput {
&:valid { .has-success; }
&:invalid { .has-error; }
}

Declare a global CSS property ? Is this possible?

I have a very wierd question, I dont know wether if its possible in css or not
Suppose I have say 3 different css classes as shown below, as you can see I have a common property of all these classes, I want to declare this color somewhere else and pass a reference to it here, so if next time I want to change the color I can simply change at one place rather than changing in all the 5 classes.
I know that you can use body{}, or a wrapper for this but that would affect the colors of the entire site right ? Is there a way to do this ?
Is this even possible ?
.abc {
color:red;
}
.abc2 {
color:red;
}
.abc3 {
color:red;
}
.abc4 {
color:red;
}
.abc5 {
color:red;
}
The bad news: you can't do it in CSS.
The good news: you can write in a meta-CSS language like LESS, which then processes a LESS file to pure CSS. This is called a "mixin".
In LESS:
#errorColor: red;
.error-color {
color: #errorColor;
}
#error-1 {
.error-color;
}
.all-errors {
.error-color;
}
More info: http://lesscss.org/#-mixins
if you want to declare all of them at a time, you can use:
.abc, .abc2, .abc3, .abc4, .abc5 {
color:red;
}
Or you can declare an additional class & add to all the .abc, .abc2.... & make its color:red;.
This can not be done with CSS, but that is still a very popular thing to do by using a CSS preprocessor such as LESS, SASS, SCSS, or Stylus.
A preprocessor will let you define a variable (say $red = #F00). It will replace the variable in your CSS document with the variable value for you, allowing you to write very DRY and module CSS.
This functionality is referred to as "CSS variables", which is part of the future spec, but not yet implemented on any browsers.
For now, the best way to do this in pure CSS is to declare an additional class for the desired "global", and then add that class to all relevant items.
.abc_global { color: red; }
.abc1 { /* additional styling */ }
.abc2 { /* additional styling */ }
<div class="abc1 abc_global"></div>
<div class="abc2 abc_global"></div>
With LESS
You are able to define that red color once:
.myRedColor {
color:red;
}
Now you can call that red on any CSS styles. Even NESTED styles! It's a wicked tool!
.abc1 {
.myRedColor;
}
.abc2 {
.myRedColor;
}
.abc3 {
.myRedColor;
}
.abc4 {
.myRedColor;
}
NESTED EXAMPLE:
.abc {
.itsEasyAsOneTwoThree{
.myRedColor;
}
}
Now all of our "itsEasyAsOneTwoThree" classes that are properly nested inside of an "abc" class will be assigned the red style. No more remembering those long #867530 color codes :) How cool is that?!
You can also use PostCSS with the plugin postcss-preset-env and support custom properties/variables, then use the :root selector to add global css variables.
:root {
--color-gray: #333333;
--color-white: #ffffff;
--color-black: #000000;
}

css framework and color schemes

I can't find a CSS frameowrk that lets me plugin my own color scheme.
For example, in my current project I imported blueprint/screen.css. To change the color of the font, I have to change body { color..}, h2 { color..}, h3 {color..}, etc.
Isn't there something out there that provides nice css defaults, but also lets may play around with color schemes?
You can try http://lesscss.org/.
It allows you to use things such as variables in your CSS, which sounds like exactly what you're after:
// LESS
#color: #4D926F;
#header {
color: #color;
}
h2 {
color: #color;
}
Create your own CSS file that loads after Blueprint. You'll need to redefine everything, but the Blueprint defaults aren't far off from the browser defaults.
If you have multiple color schemes you want to quickly switch out, set the class on your <html> tag. Then use your CSS file to define custom styles for each.
CSS:
.theme1 body {
font-family: Tahoma;
color: #500;
}
.theme2 body {
font-family: Verdana;
color: #050;
}
For the first theme:
<html class="theme1">
For the second theme:
<html class="theme2">
Couldn't you just edit the blueprint/screen.css file? You could also use something like SASS and then create all the defaults at the top of the stylesheet and then have it go throughout the stylesheet when it renders it.

Resources