Inverting colors with CSS Variables - html

I want to create a local inverted theme (modern browsers). Color shades are set using CSS Vars (CSS custom properties). Some elements have more contrast, others are low contrast. Now the inverted container has a black background. Everything within there, should be reversed. Dark grey should be light grey. Light grey should be dark grey.
My goal is to achieve this without reassigning the vars in CSS selectors. For this example it would be easy, but the actual code base is big and there are many selectors. So instead of that I just want change the CSS Vars. Also, I want keep the original CSS Vars to be editable.
Final goal mockup
Simple reassignment of the Vars (light = dark, dark = light) does not work, obviously. I tried to transpose the values to a new placeholder var, but that also didn't worked. Maybe I was doing it wrong? Is there a clean way? I don't think so.
I am aware of workarounds using SASS, or hacks using mix-blend-mode.
Playground:
https://codepen.io/esher/pen/WzRJBy
Example code:
<p class="high-contrast">high contrast</p>
<p class="low-contrast">low contrast</p>
<div class="inverted">
<p class="high-contrast">high contrast</p>
<p class="low-contrast">low contrast</p>
</div>
<style>
:root {
--high-contrast: #222;
--low-contrast: #aaa;
}
.high-contrast { color: var(--high-contrast) }
.low-contrast { color: var(--low-contrast) }
.inverted {
background-color: black;
/* Switching vars does not work
--high-contrast: var(--low-contrast);
--low-contrast: var(--high-contrast);
*/
/* Transposing Vars also doesn't work:
--transposed-low-contrast: var(--low-contrast);
--transposed-high-contrast: var(--high-contrast);
--high-contrast: var(--transposed-low-contrast);
--low-contrast: var(--transposed-high-contrast);
*/
}
/*
I am aware of this solution (see description above):
.inverted p.high-contrast { color: var(--low-contrast); }
.inverted p.low-contrast { color: var(--high-contrast); }
*/
<style>

What about something like this:
:root {
--high-contrast: var(--high);
--low-contrast: var(--low);
--high: #222;
--low: #aaa;
/* Yes I can put them at the end and it will work, why?
Because it's not C, C++ or a programming language, it's CSS
And the order doesn't matter BUT we need to avoid
cyclic dependence between variables.
*/
}
.high-contrast {
color: var(--high-contrast)
}
.low-contrast {
color: var(--low-contrast)
}
.inverted {
--high-contrast: var(--low);
--low-contrast: var(--high);
}
<p class="high-contrast">high contrast</p>
<p class="low-contrast">low contrast</p>
<div class="inverted">
<p class="high-contrast">high contrast</p>
<p class="low-contrast">low contrast</p>
</div>

Related

How are themes implemented in CSS

I am currently using variables keeping track of colors for both light and dark themes (e.g. --light-background-color, --dark-background-color). This isn't too hard with two themes but seems a bit manual and if faced with more themes it becomes impractical.
I have seen things like night shift that apply CSS filters which invert the colors on a webpage. How do these filters work? and how would I go about implementing them?
One way to go about this is to have a set of general theme color variables, rather than specific color variables for specific themes like you're trying to do here.
You can define these variables in the body element and override them with the class or a custom attribute of the body.
Use these variables as you would normally for your other HTML elements, and just change the attribute of the body element to apply a different theme.
The important part here is to make sure your theme color variables have corresponding contrasting color variables as well, so that things like white text on a dark background can swap to dark text on a white background.
Here's an example, where primary and secondary theme and contrast colors are defined in the body element, and are overridden when the body has the "dark" class applied to it:
document.querySelector("button").addEventListener("click", () => document.body.classList.toggle("dark"));
body {
--color-primary: #b4e9ce;
--color-primary-contrast: #000000;
--color-secondary: #308d43;
--color-secondary-contrast: #ffffff;
/* Other theme colors... */
}
body.dark {
--color-primary: #202d26;
--color-primary-contrast: #ffffff;
--color-secondary: #8f8f8f;
--color-secondary-contrast: #000000;
/* Other theme colors... */
}
button {
padding: 10px;
margin-bottom: 20px;
}
.wrapper {
padding: 20px;
background-color: var(--color-primary);
border: solid var(--color-secondary) 10px;
}
.wrapper h1 {
font-family: sans-serif;
text-align: center;
color: var(--color-primary-contrast);
}
<body>
<button>Toggle Theme</button>
<div class="wrapper">
<h1>Hello World</h1>
</div>
</body>
Single Line CSS will change Light Theme to Dark:
<style>
body
{
filter: invert(1);
}
</style>

CSS Design System

I'm thinking of making a CSS design system which includes classes like
.text-red {color: red}
Im super confused, I love the design system approach but anomalies are a big concern.
UPDATE: This is how what I have so far to generate colours
Background Utilities Via SCSS #each
On hover of an element I want to make it darker or lighter dynamically. I was thinking of creating a class like .darken or .lighten and I have it decrease a certain amount of colour, would I just inherit the colour and use something like -50% or something along those lines.
I guess I could create like 10 utilities with inherit as the background color and then decrease a certain amount like 50% or 25%
But how that work for on hover.
UPDATE:
This is what I have so far, not efficent but its kind of what I want with hardcoded colour
//Base Background Colour
#each $name, $colour in $colours {
.background-#{$name} {
background-color: $colour;
}
}
//Darken Background Colour
#each $name, $colour in $colours {
.background-#{$name}-light {
background-color: lighten($colour,10%);
}
}
#each $name, $colour in $colours {
.background-#{$name}-dark {
background-color: darken($colour,10%);
}
}
You could for instance add an extra class name:
.text-red {
color: red;
font-family: ebrima;
}
.text-red.darker {
color: rgb(110, 20, 20);
}
<html>
<head>
</head>
<body>
<h1 class="text-red darker">Hello there, I'm text!</h1>
<h1 class="text-red">I'm also text!</h1>
</body>
</html>
Wouldn't that be good enough?
Or would that be way too labor intensive?

revealjs with Rmarkdown - setting fonts and drawing lines

I'm using the revealjs library in R to build a set of slides. I would like to:
customise font color
put a dotted border line that separates headers and footers
I've managed to set the colour of text that appears on a slide by adding the following into the CSS file:
#mycustom {
color: blue;
}
Then in the markdown document, I would use it loke so:
## Slide 2 {#mycustom}
XYZ
- a
- b
- c
This changes the colour of everything except for "Slide 2". I'd like to control the headers as well, and ideally I'd like to be able to set these colours in the CSS once.
As for my second issue, I've added the following to the CSS file:
.reveal .header {
padding: 1px;
border: 1px dashed orange;
}
Then I modified the revealjs template that can be found under <R_DIR/library/revealjs/rmarkdown/templates/revealjs_presentation/resources/default.html> and added <div class="header"></div> under <div class="slides"> but the result looks disappointing: I'm getting a small double dashed line as shown in the attached image.
If you have a suggestion on how to improve this, please let me know.
Many thanks!
As for your first problem, why not just use
<style>
#myCustom > h1, #myCustom > h2 {
color: #FF0000;
}
/* or if you want to change all h1: */
h1 {
color: #00FF00 !important;
}
</style>

Why is * given more specificity than property inheritance in CSS?

Put simply, I have a page with these two styles:
* {
color: black;
}
div.error {
color: red
}
And a page structure like:
<html>
...
<div class="error">
<div class="row form">
<div class="column">
Error text.
</div>
</div>
</div>
...
</html>
You would expect "Error text" to be red, wouldn't you. But it is, in fact, rendered black in all browsers. Is this the expected behavior?
My second question, is contingent on whether this is the expected behavior. if it is, then why would a designer ever color every element on his whole website with "black" or some other color if that means it cannot be overridden with inheritance in specific places?
--EDIT--
The question is asked in the context of where you'd want a default color to be placed across the whole website, but wherever you want, you could say "this whole section inherits color #ffeeff". For example, a special form, contained by a divider of class "form." You don't want to label every sub-element of form with a special class like "white-text" to color everything white. You just want to set the "form" class's color and have it propagate to sub-elements.
* is more specific than agent stylesheets (the default stylesheets that come with the browser), and inherited properties are nothing more than something like this:
div {
/* ... */
color: inherit;
/* ... */
}
In the agent stylesheet, so your * with color: black is more specific than agent:div with color: inherit, thus it wins.
It is the expected behavior, for the text to be red, you want to specify:
div.column {
/* ... */
color:red;
/* ... */
}
Do check: (why) is the CSS star selector considered harmful? as suggested by 4castle.
just do that instead:
<style>
* {
color: black;
}
div.error {
color: red
}
</style>
<div>
<div class="row">
<div class="column error">
Error text.
</div>
</div>
</div>

Avoiding repeated constants in CSS

Are there any useful techniques for reducing the repetition of constants in a CSS file?
(For example, a bunch of different selectors which should all apply the same colour, or the same font size)?
Recently, variables have been added to the official CSS specs.
Variables allow you to so something like this :
body, html {
margin: 0;
height: 100%;
}
.theme-default {
--page-background-color: #cec;
--page-color: #333;
--button-border-width: 1px;
--button-border-color: #333;
--button-background-color: #f55;
--button-color: #fff;
--gutter-width: 1em;
float: left;
height: 100%;
width: 100%;
background-color: var(--page-background-color);
color: var(--page-color);
}
button {
background-color: var(--button-background-color);
color: var(--button-color);
border-color: var(--button-border-color);
border-width: var(--button-border-width);
}
.pad-box {
padding: var(--gutter-width);
}
<div class="theme-default">
<div class="pad-box">
<p>
This is a test
</p>
<button>
Themed button
</button>
</div>
</div>
Unfortunately, browser support is still very poor. According to CanIUse, the only browsers that support this feature today (march 9th, 2016), are Firefox 43+, Chrome 49+, Safari 9.1+ and iOS Safari 9.3+ :
Alternatives :
Until CSS variables are widely supported, you could consider using a CSS pre-processor language like Less or Sass.
CSS pre-processors wouldn't just allow you to use variables, but pretty much allow you to do anything you can do with a programming language.
For example, in Sass, you could create a function like this :
#function exponent($base, $exponent) {
$value: $base;
#if $exponent > 1 {
#for $i from 2 through $exponent {
$value: $value * $base;
}
}
#if $exponent < 1 {
#for $i from 0 through -$exponent {
$value: $value / $base;
}
}
#return $value;
}
Elements can belong to more than one class, so you can do something like this:
.DefaultBackColor
{
background-color: #123456;
}
.SomeOtherStyle
{
//other stuff here
}
.DefaultForeColor
{
color:#654321;
}
And then in the content portion somewhere:
<div class="DefaultBackColor SomeOtherStyle DefaultForeColor">Your content</div>
The weaknesses here are that it gets pretty wordy in the body and you're unlikely to be able to get it down to listing a color only once. But you might be able to do it only two or three times and you can group those colors together, perhaps in their own sheet. Now when you want to change the color scheme they're all together and the change is pretty simple.
But, yeah, my biggest complain with CSS is the inability to define your own constants.
You should comma seperate each id or class for example:
h1,h2 {
color: #fff;
}
You can use global variables to avoid duplicacy.
p{
background-color: #ccc;
}
h1{
background-color: #ccc;
}
Here, you can initialize a global variable in :root pseudo class selector. :root is top level of the DOM.
:root{
--main--color: #ccc;
}
p{
background-color: var(--main-color);
}
h1{
background-color: var(--main-color);
}
NOTE: This is an experimental technology
Because this technology's specification has not stabilized, check the compatibility table for the proper prefixes to use in various browsers. Also note that the syntax and behavior of an experimental technology is subject to change in future versions of browsers as the spec changes. More Info here
However, you can always use the Syntactically Awesome Style Sheets i.e.
In case Sass, you have to use $variable_name at the top to initialize the global variable.
$base : #ccc;
p{
background-color: $base;
}
h1{
background-color: $base;
}
You can use dynamic css frameworks like less.
Personally, I just use comma-separed selector, but there some solution for writing css programmatically. Maybe this is a little overkill for you simpler needs, but take a look at CleverCSS (Python)
Try Global variables to avoid duplicate coding
h1 {
color: red;
}
p {
font-weight: bold;
}
Or you can create different classes
.deflt-color {
color: green;
}
.dflt-nrml-font {
font-size: 12px;
}
.dflt-header-font {
font-size: 18px;
}
As far as I know, without programmatically generating the CSS file, there's no way to, say, define your favorite shade of blue (#E0EAF1) in one and only one spot.
You could pretty easily write a computer program to generate the file. Execute a simple find-and-replace operation and then save as a .css file.
Go from this source.css…
h1,h2 {
color: %%YOURFAVORITECOLOR%%;
}
div.something {
border-color: %%YOURFAVORITECOLOR%%;
}
to this target.css…
h1,h2 {
color: #E0EAF1;
}
div.something {
border-color: #E0EAF1;
}
with code like this… (VB.NET)
Dim CssText As String = System.IO.File.ReadAllText("C:\source.css")
CssText = CssText.Replace("%%YOURFAVORITECOLOR%%", "#E0EAF1")
System.IO.File.WriteAllText("C:\target.css", CssText)
You can use multiple inheritance in your html elements (e.g. <div class="one two">) but I'm not aware of a way of having constants in the CSS files themselves.
This link (the first found when googling your question) seems to have a fairly indepth look at the issue:
http://icant.co.uk/articles/cssconstants/
CSS Variables, if it ever becomes implemented in all major browsers, may one day resolve this issue.
Until then, you'll either have to copy and paste, or use a preprocessor of whatever sort, like others have suggested (typically using server-sider scripting).
:root {
--primary-color: red;
}
p {
color: var(--primary-color);
}
<p> some red text </p>
You can change color by JS
var styles = getComputedStyle(document.documentElement);
var value = String(styles.getPropertyValue('--primary-color')).trim();
document.documentElement.style.setProperty('--primary-color', 'blue');