Creating CSS Global Variables : Stylesheet theme management [duplicate] - css

This question already has answers here:
How can I define colors as variables in CSS?
(19 answers)
Closed 6 years ago.
Is there a way to set global variables in css such as:
#Color1 = #fff;
#Color2 = #b00;
h1 {
color:#Color1;
background:#Color2;
}

Latest Update: 16/01/2020
CSS Custom Properties (Variables) have arrived!
It's 2020 and time to officially roll out this feature in your new applications.
Preprocessor "NOT" required!
There is a lot of repetition in CSS. A single color may be used in several places.
For some CSS declarations, it is possible to declare this higher in the cascade and let CSS inheritance solve this problem naturally.
For non-trivial projects, this is not always possible. By declaring a variable on the :root pseudo-element, a CSS author can halt some instances of repetition by using the variable.
How it works
Set your variable at the top of your stylesheet:
CSS
Create a root class:
:root {
}
Create variables (-- [String] : [value])
:root {
--red: #b00;
--blue: #00b;
--fullwidth: 100%;
}
Set your variables anywhere in your CSS document:
h1 {
color: var(--red);
}
#MyText {
color: var(--blue);
width: var(--fullwidth);
}
BROWSER SUPPORT / COMPATIBILITY
See caniuse.com for current compatability.
Firefox: Version 31+ (Enabled by default)
Supported since 2014 (Leading the way as usual.)
More info from Mozilla
Chrome: Version 49+ (Enabled by default).
Supported since 2016
Safari/IOS Safari: Version 9.1/9.3 (Enabled by default).
Supported since 2016
Opera: Version 39+ (Enabled by default).
Supported since 2016
Android: Version 52+ (Enabled by default).
Supported since 2016
Edge: Version 15+ (Enabled by default).
Supported since 2017
CSS Custom Properties landed in Windows Insider Preview build 14986
IE: When pigs fly.
It's time to finally let this ship sink. No one enjoyed riding her anyway. ☺
W3C SPEC
Full specification for upcoming CSS variables
Read more
TRY IT OUT
A fiddle and snippet are attached below for testing:
(It will only work with supported browsers.)
DEMO FIDDLE
:root {
--red: #b00;
--blue: #4679bd;
--grey: #ddd;
--W200: 200px;
--Lft: left;
}
.Bx1,
.Bx2,
.Bx3,
.Bx4 {
float: var(--Lft);
width: var(--W200);
height: var(--W200);
margin: 10px;
padding: 10px;
border: 1px solid var(--red);
}
.Bx1 {
color: var(--red);
background: var(--grey);
}
.Bx2 {
color: var(--grey);
background: black;
}
.Bx3 {
color: var(--grey);
background: var(--blue);
}
.Bx4 {
color: var(--grey);
background: var(--red);
}
<p>If you see four square boxes then variables are working as expected.</p>
<div class="Bx1">I should be red text on grey background.</div>
<div class="Bx2">I should be grey text on black background.</div>
<div class="Bx3">I should be grey text on blue background.</div>
<div class="Bx4">I should be grey text on red background.</div>

You can't create variables in CSS right now. If you want this sort of functionality you will need to use a CSS preprocessor like SASS or LESS. Here are your styles as they would appear in SASS:
$Color1:#fff;
$Color2:#b00;
$Color3:#050;
h1 {
color:$Color1;
background:$Color2;
}
They also allow you to do other (awesome) things like nesting selectors:
#some-id {
color:red;
&:hover {
cursor:pointer;
}
}
This would compile to:
#some-id { color:red; }
#some-id:hover { cursor:pointer; }
Check out the official SASS tutorial for setup instructions and more on syntax/features. Personally I use a Visual Studio extension called Web Workbench by Mindscape for easy developing, there are a lot of plugins for other IDEs as well.
Update
As of July/August 2014, Firefox has implemented the draft spec for CSS variables, here is the syntax:
:root {
--main-color: #06c;
--accent-color: #006;
}
/* The rest of the CSS file */
#foo h1 {
color: var(--main-color);
}

It's not possible using CSS, but using a CSS preprocessor like less or SASS.

Try SASS http://sass-lang.com/ or LESS http://lesscss.org/
I love SASS and use it for all my projects.

I do it this way:
The html:
<head>
<style type="text/css"> <? require_once('xCss.php'); ?> </style>
</head>
The xCss.php:
<? // place here your vars
$fntBtn = 'bold 14px Arial'
$colBorder = '#556677' ;
$colBG0 = '#dddddd' ;
$colBG1 = '#44dddd' ;
$colBtn = '#aadddd' ;
// here goes your css after the php-close tag:
?>
button { border: solid 1px <?= $colBorder; ?>; border-radius:4px; font: <?= $fntBtn; ?>; background-color:<?= $colBtn; ?>; }

You will either need LESS or SASS for the same..
But here is another alternative which I believe will work out in CSS3..
http://css3.bradshawenterprises.com/blog/css-variables/
Example :
:root {
-webkit-var-beautifulColor: rgba(255,40,100, 0.8);
-moz-var-beautifulColor: rgba(255,40,100, 0.8);
-ms-var-beautifulColor: rgba(255,40,100, 0.8);
-o-var-beautifulColor: rgba(255,40,100, 0.8);
var-beautifulColor: rgba(255,40,100, 0.8);
}
.example1 h1 {
color: -webkit-var(beautifulColor);
color: -moz-var(beautifulColor);
color: -ms-var(beautifulColor);
color: -o-var(beautifulColor);
color: var(beautifulColor);
}

Related

Compile non-root CSS custom property

Are there any tools to compile CSS custom properties declared at not :root rule? I want following code with custom properties
.dark {
--bg-color: black;
--fg-color: white;
}
.light {
--bg-color: white;
--fg-color: black;
}
.foo {
background: var(--bg-color);
display: block;
}
.bar {
color: var(--fg-color);
display: inline;
}
be compiled to their non-custom-prop equivalents like that
.light .foo, .light.foo {
background: white;
}
.dark .foo, .dark.foo {
background: black;
}
.light .bar, .light.bar {
color: black;
}
.dark .bar, .dark.bar {
color: white;
}
.foo {
display: block;
}
.bar {
display: inline;
}
The goal is to
switch color schemes by switching dark/light class on root DOM element
use valid css syntax (no sass less)
keep rules code compact
It's actually not safe to do that. I can tell you because I tried so hard to make a safe transformation.
But I failed.
https://github.com/postcss/postcss-custom-properties/issues/1
Ideal solution. Your example is valid CSS and can be used in many browsers (not in IE, Edge (but is in development) and Opera Mini as of writing this answer, 2017-03-27, other major browsers are fine).
Suboptimal solution. Some CSS can be transpiled to achieve better browser support. The solution I found does not support variables on non-:root elements, however. There are also other objections against transpiling of 'future' CSS into 'current' CSS. To the best of my knowledge, you will have to implement your own transpiler (or postcss plugin) if you want to transpile custom properties not on the :root element, but be warned that that is hard in general. Now you don't need the general part, so it is possible. Just does, to the best of my knowledge, not exist yet.
Preprocessing solution. Of course, you don't need a general implementation of custom properties. You have different themes that have their own values for the same set of properties and that's it. Thus, a separate stylesheet can be created as a preprocessing step using any CSS preprocessor.
Now you say the following,
use valid css syntax (no sass less)
but I am going to show this anyway, because I believe that it is a valid solution to your problem. It is definitely the only one I know that actually works if you want to/need to support IE, Edge and/or older versions of other major browsers (Firefox < 31, Chrome < 49, Safari < 9.1, Opera < 36)
You could do this using SASS for example, to do the transpiling on the server side.
// define styles, use variables throughout them
// your entire style definition goes into this mixin
#mixin myStyles($fg-color, $bg-color) {
.foo {
display: block;
background: $bg-color;
}
.bar {
display: inline;
color: $fg-color;
}
}
// define themes, that set variables for the above styles
// use named arguments for clarity
.dark {
#include myStyles(
$fg-color: white,
$bg-color: black
);
}
.light {
#include myStyles(
$fg-color: black,
$bg-color: white
);
}
This compiles to the following.
.dark .foo {
display: block;
background: black;
}
.dark .bar {
display: inline;
color: white;
}
.light .foo {
display: block;
background: white;
}
.light .bar {
display: inline;
color: black;
}
This is not exactly what you want to obtain, but very close. Realistically, I think this is the closest you will get to obtaining your desired output. I know you want to
keep rules code compact
but what you are saying there (I think) is that you want to split out custom properties from their rules to save on number of rules, which is not something any preprocessor I know supports.
You can organize your source SASS in separate files to keep an overview easily. You can even set up a build system that generates a separate stylesheet for every theme you have. It is then possible to have your users select an alternative stylesheet. Browsers have some support for this, but switching using JavaScript is also definitely possible in the latter case. Simply set all stylesheets to be disabled except for the selected one. Here is an example.

Confused about overriding CSS styles

I understand CSS basics, but I keep running into trouble with conflicting styles. Consider the following styles.
First, the default font color in my style sheets is black. I want that color applied to all picture captions - unless they're contained in divs with a class CoolL or CoolR...
.CoolL .Caption, .CoolR .Caption { color: #900; }
Now all the captions in the Cool series have brown text. But there are situations where I want the captions to have a black background with white text, so I created this rule:
.Black { background: #000; color: #fff; }
Now consider the following HTML. Class Caption by itself should have black text. However, this is inside a div with a class CoolR, so it displays brown text instead. But I added the class Black to the last div, which should change the background to black and the text color to white...
<div class="CoolR Plus Max300">
<div class="Shadow2">
<img src="">
<div class="Caption Black">Text</div>
</div>
</div>
In fact, the background is displaying black, but the text color is still brown.
I get these problems all the time, and the only way I can fix them is to write long, detailed styles, like this...
.Black, .Caption .Black, .CoolR .Caption.Black, .EverythingElseThatCouldBeBlack .Black { background: #000; color: #fff; }
What am I missing? Thanks.
I think you are over complicating things. This will become a maintenance issue as you add more styles. I would define separate classes and keep things simple. It's also important to understand CSS specificity.
.caption {
color: #000;
}
.cool-caption {
color: #900;
}
.caption-with-background {
background-color: #000;
color: #fff;
}
You could try :
.Black { background: #000 !important; color: #fff !important; }
There are a few fixes, but as previously recommended you should mark all of the settings you want to override previous ones with !important. With that, your code would look like this:
.Black {
background: #000;
color: #fff;
}
Also, not sure if you asked this, but you can apply CSS to all components by using the *, like so:
* {
//blahblahblah
}
you are defining the first case with a descendant selector which overrides the second class, which is merely a class. every answer given already will work but are entirely unnecessary. just add this to your style sheet:
.CoolR1 .Black, .Black{ background: #000; color: #fff;}
/** you could also chain your classes for specificity power **/
.Black.Caption{color:#fff}
that should do it. you can read more about selectors here:
http://docs.webplatform.org/wiki/css/selectors
I think that generally a more specific rule overrides a more general one, thus the more specific '.CoolR .Caption' is overriding the more general .Black. You'll probably be able to override this with !important, but a better style might be to reduce the complexity of your rules:
.Cool .caption { color: #900; }
.Cool .caption.black { color: background: #000; color: #fff; }
And put .L and .R in separate classes
.Cool.L { . . . } /* For things specific to CoolL, but not CoolR */
.Cool.R { . . . } /* and vice-versa */

fail to change placeholder color with Bootstrap 3

Two questions:
I am trying to make the placeholder text white. But it doesn't work. I am using Bootstrap 3. JSFiddle demo
Another question is how do I change placeholder color not globally. That is, I have multiple fields, I want only one field to have white placeholder, all the others remain in default color.
html:
<form id="search-form" class="navbar-form navbar-left" role="search">
<div class="">
<div class="right-inner-addon"> <i class="icon-search search-submit"></i>
<input type="search" class="form-control" placeholder="search" />
</div>
</div>
</form>
css:
.right-inner-addon {
position: relative;
}
.right-inner-addon input {
padding-right: 30px;
background-color:#303030;
font-size: 13px;
color:white;
}
.right-inner-addon i {
position: absolute;
right: 0px;
padding: 10px 12px;
/* pointer-events: none; */
cursor: pointer;
color:white;
}
/* do not group these rules*/
::-webkit-input-placeholder { color: white; }
FF 4-18
:-moz-placeholder { color: white; }
FF 19+
::-moz-placeholder { color: white; }
IE 10+
:-ms-input-placeholder { color: white; }
Assign the placeholder to a class selector like this:
.form-control::-webkit-input-placeholder { color: white; } /* WebKit, Blink, Edge */
.form-control:-moz-placeholder { color: white; } /* Mozilla Firefox 4 to 18 */
.form-control::-moz-placeholder { color: white; } /* Mozilla Firefox 19+ */
.form-control:-ms-input-placeholder { color: white; } /* Internet Explorer 10-11 */
.form-control::-ms-input-placeholder { color: white; } /* Microsoft Edge */
It will work then since a stronger selector was probably overriding your global. I'm on a tablet so i cant inspect and confirm which stronger selector it was :) But it does work I tried it in your fiddle.
This also answers your second question. By assigning it to a class or id and giving an input only that class you can control what inputs to style.
There was an issue posted here about this: https://github.com/twbs/bootstrap/issues/14107
The issue was solved by this commit: https://github.com/twbs/bootstrap/commit/bd292ca3b89da982abf34473318c77ace3417fb5
The solution therefore is to override it back to #999 and not white as suggested (and also overriding all bootstraps styles, not just for webkit-styles):
.form-control::-moz-placeholder {
color: #999;
}
.form-control:-ms-input-placeholder {
color: #999;
}
.form-control::-webkit-input-placeholder {
color: #999;
}
A Possible Gotcha
Recommended Sanity Check - Make sure to add the form-control class to your inputs.
If you have bootstrap css loaded on your page, but your inputs don't have the
class="form-control" then placeholder CSS selector won't apply to them.
Example markup from the docs:
I know this didn't apply to the OP's markup but as I missed this at first and spent a little bit of effort trying to debug it, I'm posting this answer to help others.
I'm using Bootstrap 4 and Dennis Puzak's solution does not work for me.
The next solution works for me
.form-control::placeholder { color: white;} /* Chrome, Firefox, Opera*/
:-ms-input-placeholder.form-control { color: white; } /* Internet Explorer*/
.form-control::-ms-input-placeholder { color: white; } /* Microsoft Edge*/
Bootstrap has 3 lines of CSS, within your bootstrap.css generated file that control the placeholder text color:
.form-control::-moz-placeholder {
color: #999999;
opacity: 1;
}
.form-control:-ms-input-placeholder {
color: #999999;
}
.form-control::-webkit-input-placeholder {
color: #999999;
}
Now if you add this to your own CSS file it won't override bootstrap's because it is less specific. So assmuning your form inside a then add that to your CSS:
form .form-control::-moz-placeholder {
color: #fff;
opacity: 1;
}
form .form-control:-ms-input-placeholder {
color: #fff;
}
form .form-control::-webkit-input-placeholder {
color: #fff;
}
Voila that will override bootstrap's CSS.
The others did not work in my case (Bootstrap 4). Here is the solution I used.
html .form-control::-webkit-input-placeholder { color:white; }
html .form-control:-moz-placeholder { color:white; }
html .form-control::-moz-placeholder { color:white; }
html .form-control:-ms-input-placeholder { color:white; }
If we use a stronger selector (html first), we don't need to use the hacky value !important.
This overrides bootstraps CSS as we use a higher level of specificity to target .form-control elements (html first instead of .form-control first).
I think qwertzman is on the right track for the best solution to this.
If you only wanted to style a specific placeholder, then his answer still holds true.
But if you want to override the colour of all placeholders, (which is more probable) and if you are already compiling your own custom Bootstrap LESS, the answer is even simpler!
Override this LESS variable:
#input-color-placeholder
Boostrap Placeholder Mixin:
#mixin placeholder($color: $input-color-placeholder) {
// Firefox
&::-moz-placeholder {
color: $color;
opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526
}
&:-ms-input-placeholder { color: $color; } // Internet Explorer 10+
&::-webkit-input-placeholder { color: $color; } // Safari and Chrome
}
now call it:
#include placeholder($white);
You should check out this answer : Change an HTML5 input's placeholder color with CSS
Work on most browser, the solution in this thread is not working on FF 30+ for example
With LESS the actual mixin is in vendor-prefixes.less
.placeholder(#color: #input-color-placeholder) {
...
}
This mixin is called in forms.less on line 133:
.placeholder();
Your solution in LESS is:
.placeholder(#fff);
Imho the best way to go. Just use Winless or a composer compiler like Gulp/Grunt works, too and even better/faster.

What is the Caio Hack?

I was playing around right-clicking my line numbers in Dreamweaver, trying to bookmark a line.
I noticed this menu entry:
What is the Caio Hack? With alert('hi'); highlighted, this is the result:
It's an old CSS hack.
"Caio Hack is a simple CSS comments-based hack used in 'inline' and
'external' CSS declarations to hide information from Netscape 4"
For example, this code hides the .foo2 selector to Netscape 4:
.foo1
{
color: green;
background-color: yellow;
}
/*/*/
.foo2
{
color: red;<code></code>
}
/* */
.foo3
{
color: blue;
}
Source: http://en.wikibooks.org/wiki/Cascading_Style_Sheets/Hacks_and_Filters/Caio_Hack
The Caio Hack is named after its discoverer, Caio Chassot.
It is a CSS hack for hiding rules from Netscape 4, exploiting a bug in NN4's parser.
By opening a comment using /*/*/, all subsequent CSS would be ignored by NN, because it thinks the comment didn't close.
To end the block, you'd use /* */.
For example:
.foo1
{
color: green;
background-color: yellow;
}
/*/*/
.foo2
{
color: red;
}
/* */
.foo3
{
color: blue;
}
More info at:
Wikibooks
CSS Discuss
http://css-discuss.incutio.com/wiki/Caio_Hack
It hides CSS codes from Netscape4 and sometimes Opera.

LESS CSS - Change variable value for theme colors depending on body class

Getting to grips with LESS here but one thing is still a little unclear.
Lets say I have multiple color themes for my website, controlled by a class on the body tag. From this I can redefine the various colors for each element within each theme. Easy enough but fairly time consuming if I have a lot of elements to change... and a lot of themes. Every time I add a new theme I need to write out all the selectors again, with different color values.
I am basing my working so far on another post I found:
LESS.css variable depending on class
... However it still seems overly complicated for what I want to do in that I still have to write out all the selectors and include the mixin before dropping in the same CSS with the color variable.
I have created a CODEPEN HERE
I'd appreciate it if anyone had time to take a little look and advise me how I could approach this differently or how I could streamline this process.
Many thanks to anyone who helps out :)
Assuming you remain with wanting to theme it within one style sheet (and not multiple sheets as cimmanon noted in the comments), and assuming you are using LESS 1.3.2+, then the following code works to reduce the amount of duplication by setting up a loop through the classes that need theme changes.
Note that this does not work on Codepen (it is throwing an error uncaught throw #, perhaps because they are running an earlier version of LESS), but you can see it compiling correctly by putting the code into LESS's compiler.
LESS (based off your Codepen code with an added theme for demo)
//////////////////////////////////////////////////////
// CONSTANTS
#lightColour: #fff;
#darkColour: #000;
#lightBg: #fff;
#darkBg: #000;
#numberOfThemes: 3; //controls theme loop
//////////////////////////////////////////////////////
// MIXINS
//Theme Definitions by parametric mixin numbers (1), (2), etc.
.themeDefs(1) {
#lightColour: #f00;
#darkColour: #fff;
#lightBg: #f00;
#darkBg: #fff;
}
.themeDefs(2) {
//inverse of 1
#lightColour: #fff;
#darkColour: #f00;
#lightBg: #fff;
#darkBg: #f00;
}
.themeDefs(3) {
#lightColour: #cfc;
#darkColour: #363;
#lightBg: #cfc;
#darkBg: #363;
}
.curvy {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
//////////////////////////////////////////////////////
// GENERAL STYLING
* {padding: 0;margin: 0;}
html {text-align: center;}
h2 {padding: 20px 0;}
.box {
.curvy;
color: #lightColour;
background: #darkBg;
display:inline-block; width:10%; padding:20px 5%; margin:0 1% 20px 1%;
}
//////////////////////////////////////////////////////
// THEME BUILDING
.buildThemes(#index) when (#index < #numberOfThemes + 1) {
.theme-#{index} {
.themeDefs(#index);
color: #lightColour;
background: #darkBg;
.box {
color: #darkColour;
background: #lightBg;
}
}
.buildThemes(#index + 1);
}
//stop loop
.buildThemes(#index) {}
//start theme building loop
.buildThemes(1);
CSS Output (only showing the looped theme css for brevity)
.theme-1 {
color: #ff0000;
background: #ffffff;
}
.theme-1 .box {
color: #ffffff;
background: #ff0000;
}
.theme-2 {
color: #ffffff;
background: #ff0000;
}
.theme-2 .box {
color: #ff0000;
background: #ffffff;
}
.theme-3 {
color: #ccffcc;
background: #336633;
}
.theme-3 .box {
color: #336633;
background: #ccffcc;
}

Resources