Changing CSS variable based on the parent class || Sass and Tailwind CSS - css

I'm styling a Next.js website using Tailwind CSS and trying to build a theme switching mechanism using CSS (Sass) variables.
Mainly I have two modes:
Default mode: Includes light and dark themes.
Minimalist mode: also includes light and dark themes but with much fewer colours (black and white mostly).
So generally the user has four options, and the same tailwind colour changes based on the dynamically provided classes.
Based on the main div class bg-primary should be as follows:
no class provided => default light theme, bg-primary = #79A542; // works perfectly
"dark" => default dark theme, bg-primary = #03004C; // works perfectly
"minimalist" => minimalist light theme, bg-primary = #FEFDF8; // works perfectly
"minimalist dark" => minimalist dark theme, bg-primary = #0f0f0f; // doesn't work
All of the theme combinations work except for "minimalist dark", the bg-primary is #03004C not #0f0f0f why is that? Why is the minimalist dark theme overridden by the default one?
This is my globals.scss file configuration:
#tailwind base;
#import url('https://fonts.googleapis.com/css2?family=Amiri&family=Montserrat&family=Rakkas&family=Roboto&display=swap');
#import url('https://fonts.googleapis.com/css2?family=Aref+Ruqaa&family=Lateef&display=swap');
:root {
/*default mode*/
--primary: #79A542;
--secondary: #CFF0A5;
--third: #CFF0A5;
--inverse: #0f0f0f;
--font-mono: 'Roboto Mono',monospace;
--font-sans: 'Montserrat', sans-serif;
& .arabic {
--font-mono: 'Amiri', serif;
--font-sans: 'Rakkas', cursive;
}
& .dark {
--primary: #03004C;
--secondary: #6A1497;
--third: #E61D6D;
--inverse: #7C54E1;
}
}
.minimalist {
/*Minimalist mode*/
--third: #98999B;
--inverse: transparent;
--primary: #FEFDF8;
--secondary: #0f0f0f;
& .dark {
--primary: #0f0f0f;
--secondary: #FEFDF8;
}
& .arabic {
--font-mono: 'Aref Ruqaa', serif;
--font-sans: 'Lateef', cursive;
}
}
#tailwind components;
#tailwind utilities;
This is my _app.js file:
import '../styles/globals.css'
import Nav from '../components/Nav'
import { useState} from 'react'
function MyApp({ Component, pageProps }) {
const [attributes, setAttributes] = useState("minimalist dark") // Themes are changed here
return (
<div className={attributes}>
<main className="bg-primary">
<Nav/>
</main>
</div>
)
}
export default MyApp
And this is my tailwind.config.js file:
module.exports = {
purge: ['./pages/**/*.js', './components/**/*.js'],
darkMode: 'class', // or 'media' or 'class'
theme: {
extends: {
},
colors: {},
textColor: {
primary: 'var(--primary)',
secondary: 'var(--secondary)',
third: 'var(--third)',
inverse: 'var(--inverse)',
white: 'var(--white)',
black: 'var(--black)',
},
backgroundColor: {
primary: 'var(--primary)',
secondary: 'var(--secondary)',
third: 'var(--third)',
inverse: 'var(--inverse)',
white: 'var(--white)',
black: 'var(--black)',
},
fontFamily: {
'sans': 'var(--font-sans)',
'mono': 'var(--font-mono)',
},
},
variants: {
extend: {},
},
plugins: [],
}
Has the issue something to do with reusing the same dark class? How do I resolve this?

Your current CSS selector will be .minimalist .dark which means the dark class inside the minimalist class. You want to have the minimalist class that's also have a class of dark. In CSS that's .mimimalist.dark, without a space.
In SCSS, you need to remove the space between the parent selector (&) and the class name, like this:
.minimalist {
--third: #98999B;
--inverse: transparent;
--primary: #FEFDF8;
--secondary: #0f0f0f;
&.dark {
--primary: #0f0f0f;
--secondary: #FEFDF8;
}
}
The default .dark class works fine, because it's inside the :root class.

Related

TailwindCSS, change default border color for dark theme?

I'm using TailwindCSS for my project, I want to set a default border color, for the normal theme I did this via:
module.exports = {
mode: "jit",
purge: ["{pages,app}/**/*.{jsx,tsx}", "node_modules/react-toastify/**"],
darkMode: "media",
theme: {
extend: {
borderColor: (theme) => ({
DEFAULT: theme("colors.gray.100"), // Light theme default border color
dark: {
DEFAULT: theme("colors.gray.800"), // Dark theme default border color NOT WORKING
},
}),
// ...
}
For the light theme, it is working fine, however, for the dark theme, I cannot seem to find a way to apply a default value, any ideas of how to make this work?
Thanks a lot!
I figure out a way, hope it helps.
The tailwind suggests that we make use of index.css instead of configuring in tailwind.config.js
As mentioned in https://tailwindcss.com/docs/functions-and-directives
So the code goes like:
tailwind.config.js
const colors = require("tailwindcss/colors");
module.exports = {
mode: "jit",
darkMode: "media",
content: ["./src/**/*.{js,jsx}", "./public/index.html"],
theme: {
extend: {
colors: {
gray: colors.gray,
light: {
primary: colors.orange,
},
dark: {
primary: colors.green,
},
},
/* Add any default values here */
/* borderWidth: {
DEFAULT: "4px",
},*/
},
},
plugins: [],
};
index.css
#tailwind base;
#tailwind components;
#tailwind utilities;
#layer base {
/* Can directly apply colors : hard coded values for light and dark */
.bg-color {
#apply bg-white dark:bg-black;
}
/* Can use custom color defined in the tailwind.config.css file */
.bg-text {
#apply text-light-primary-800 dark:text-dark-primary-500;
}
/* This is how you apply the border-color for both light and dark mode */
.border-color {
#apply border-black dark:border-white;
}
}
DarkMode.js
import React from "react";
const DarkMode = () => {
return (
<div className=" min-h-screen min-w-full bg-color">
<div className="border-color border-4 bg-text font-bold">
Hello
</div>
</div>
);
};
export default DarkMode;
In light theme:
In dark theme:
For your desired border-color change the border-color property as shown below.
.border-color {
#apply border-gray-100 dark:border-gray-800;
}
I've used this approach and it works pretty well.
#layer components {
.border,
.border-r,
.border-l,
.border-t,
.border-b,
.border-x,
.border-y {
#apply dark:border-dark-600;
}
}
Simply use
#layer base {
*,
::before,
::after {
#apply dark:border-gray-600;
}
}
Because Tailwind implements border-color by default. It works!

How to define a sass map for specific CSS selector

I am trying to customize scss in my project so that I can use css variables according to css selector applied on outermost element.
The basic Idea I have is to define color variables and then use those color variables to define semantic color variables in two different css selectors.
$primary: orange;
$primary-dark: redorange;
$warn: red;
$accent: grey;
$dark-grey: #757678;
$light-grey: #f7f7f7;
$error-text: $warn;
.light {
$background: $light-grey;
$button-bg: $primary;
}
.dark {
$background: $dark-grey;
$button-bg: $primary-dark;
}
This is one solution I tried, but in scss we cannot change scope of variables according to selectors.
So I tried using functions.
$white: #fff;
$light-grey: #eaeaea
$primry-dark: redorange;
$primary: orange;
$black: #000;
$semantic-colors: (
background: (
screen: $white,
tile: $light-grey,
),
buttons: (
primary: $primary
link: $white
icons: $primary-dark;
)
);
#function semantic-color($semantic-color:'background', $tone: "base") {
// #return red;
#return map-get(map-get($semantic-colors, $semantic-color), $tone);
}
.side-nav-link {
background-color: semantic-color(background, tile);
}
The above code works fine. but I want to have a color map based on a theme. for eg:
dark has its own semantic color map and light has its own and I can access based on scope.
.light {
$semantic-colors: (
background: (
base: $white,
tile: $light-grey,
),
buttons: (
primary: $primary,
link: $white,
icons: $primary-dark;
)
);
}
.dark {
$semantic-colors: (
background: (
base: $black,
tile: $dark-grey,
),
buttons: (
primary: $primary-dark,
link: $black,
icons: $primary;
)
);
}
I can create two different maps within semantic-color map:
$semantic-colors: (
light:(
background: (
base: $white,
tile: $light-grey,
),
buttons: (
primary: $primary
link: $white
icons: $primary-dark;
)
),
dark:(
background: (
base: $black,
tile: $dark-grey,
),
buttons: (
primary: $primary-dark,
link: $black,
icons: $primary;
)
)
);
and then modify my function to get color within a specific map based on $theme variable.
For eg:
$theme: dark;
#function semantic-color($semantic-color:'background', $tone: "base") {
// #return red;
#return map-get(map-get(map-get($semantic-colors, $theme), $semantic-color), $tone);
}
but I don't know a way to define $theme according to .light and .dark selectors.
If I try doing something like this:
.light {
$theme: light;
}
.dark {
$theme: dark;
}
and then use the $theme variable in the semantic-color function then I get the error $theme is not defined.
so my question is
"Is there a way I can define $theme or semantic-color function or $sematic-color map according to a CSS selector (.light or .dark in my case)?"
I have read sass documentation but could not find any solution to suit my situation.
Articles I referred to:
Theming in SASS
Creating a Color Language in Web Interfaces (with Sass Maps)
educba SASS Map
I am not quits sure if I did it completly right ... but as I see your idea and code in general works well.
The only thing seems to be: there had been some errors in your code seeting up $semantic-colors !?
This (correctedt version = only corrections in $semantic-colors) works here:
//########### SASS: demo file
//### VARS
$primary: orange;
$primary-dark: redorange;
$warn: red;
$accent: grey;
$dark-grey: #757678;
$light-grey: #f7f7f7;
$white: #ffffff;
$black: #000000;
$error-text: $warn;
$semantic-colors: (
light: (
background: (
base: $white,
tile: $light-grey,
),
buttons: (
primary: $primary,
link: $white,
icons: $primary-dark,
),
),
dark: (
background: (
base: $black,
tile: $dark-grey,
),
buttons: (
primary: $primary-dark,
link: $black,
icons: $primary,
),
),
);
//### METHODS
$theme: dark;
#function semantic-color($semantic-color: "background", $tone: "base") {
// #return red;
#return map-get(
map-get(map-get($semantic-colors, $theme), $semantic-color),
$tone
);
}
//### STYLES
.light {
$theme: light;
background: semantic-color('background', 'base');
}
//###########################
//###### CSS: compiled file
.light {
background: #ffffff; // if $theme changes to dark this becomes #000000
}
Because of your comment I believe to understand your question better now. So, according to your last comment I add an additional answer as it is more an explanation about the general howto than a concrete answer to your code.
First: I believe your code (SASS-map/-function) works the right way
To me it seems more a question about understanding how the theme technique works.
So let's start from the base:
1. What you need to do for theming in html:
// set a theme anchor with classes
// --> class to body
<body class="theme_light">
... code ...
... all elements within body will be styled by theme-light-classes
// or ALTERNATIVE do it with a marker where your app starts in html
// --> class to app-root-element
<div class="app_root theme_light">
... code ...
... all elements within app-div will by styled by theme-light-classes
</div>
</body>
2. Based on HTML what you nee in CSS:
Write the styling for your elements for both(!) themes based on the used marker technique (body or app) ...
// write styling classes for both themes (dark + light)
// as child selector based on the html theme-anchor-classes
/* stylings light theme */
.theme_light .content {
background: #theme-light-background-color;
color: #theme-light-font-color;
}
.theme_light .button {
background: #theme-light-button-background-color;
color: #theme-light-button-font-color;
}
/* stylings dark theme */
.theme_dark .content {
background: #theme-dark-background-color;
color: #theme-dark-font-color;
}
.theme_dark .button {
background: #theme-dark-button-background-color;
color: #theme-dark-button-font-color;
}
// if you anchor with app class your css-selectors would have to be
/* light theme */
.app_root.theme_light .content { ... }
.app_root.theme_light .content { ... }
/* dark theme */
.app_root.theme_dark .content { ... }
.app_root.theme_dark .content { ... }
3. Use your SASS-function/-map to achieve this in SASS
In this step we use your (still working) function and map from your question. Writing the CSS in SASS is as easy with nesting the element classes ...
// write themes dark & white nested to the anchor classes
// use function & map from question
.theme_light {
// set sass theme varible
// to get from function values for theme light
$theme: light;
// write stylings
// function will automatic return values for light theme
body {
background: semantic-color('background', 'base');
color: semantic-color('text-color', 'base');
}
button {
background: semantic-color('buttons', 'primary');
color: semantic-color('buttons-text', 'primary');
}
}
.theme_dark {
// set sass theme varible
// to get from function values for theme dark
$theme: dark;
// write stylings
// function will automatic NOW return values for light theme
body {
background: semantic-color('background', 'base');
color: semantic-color('text-color', 'base');
}
button {
background: semantic-color('buttons', 'primary');
color: semantic-color('buttons-text', 'primary');
}
}
//###
//### --> that will compile the needed css!!!
//###
//### NOTE:
//--> if you use app-anchor-class
//--> your nesting would be as follow
.app_root.theme_light { ... same code as above ... }
.app_root.theme_dark { ... same code as above ... }
HINTS:
As you see your function is a powerful tool: as shown in the example it leads to write identical code twice. If you write a SASS mixin (use directive #content to pass individual theme styles to it) you can reduce it so you are able to write all themes at once.
As you see the SASS variable $theme is used IN SASS as switch which changes your function semantic-color() to get the right color (light or dark).
There are many approches to realize theme stylings in SASS. This is one of the traditional methods and having a good organized map a very intuitive one.

How do I modify the default styling of the Typography prose class in TailwindCSS?

I have a TailwindCSS 2.0 project and I've installed all the plugins, including the Typography plugin. When I create a div class="prose", I can put any headings, paragraphs, lists, etc into it and it gets styled by the Typography plugin.
In my project, I want all the within the prose class to be a certain blue, by default. And I also want the links to be a certain link colour that I've defined in my config. These are just a couple of modifications that I want to make so that the default prose class styles everything with my styles. How do I go about that and what is the best practice for it?
Typography plugin can be extended
tailwind.config.js
module.exports = {
theme: {
typography: {
DEFAULT: { // this is for prose class
css: {
color: theme('colors.yourSpecificColor'), // change global color scheme
p: {
fontSize: '14px', // key can be in camelCase...
'text-align': 'center', // or as it is in css (but in quotes).
},
a: {
// change anchor color and on hover
color: '#03989E',
'&:hover': { // could be any. It's like extending css selector
color: '#F7941E',
},
},
ul: {
'> li': {
'&::before': { // more complex example - add before to an li element.
content: '',
....,
},
},
},
},
},
sm: { // and this is for prose-sm.
css: {
....
},
},
},
},
}
Also worse to mention, if you change something in "other" breakpoints than just prose, for ex, 'prose-sm', 'prose-md', etc, changes does not inherits, so if you will change color to blue in prose, it will not change in prose-sm
Customization can be found here
P.S. In example bellow I could messed up with amount of curly brackets, sorry, to hard to track :)
vue 3
For people wanting to customize their own Typography including font size and name for all breakpoints
tailwind config
inside tailwind.config.js in extend
extend: {
fontSize: {
'exampleFont': '36px',
},
In your main.css
#tailwind base;
#tailwind components;
#tailwind utilities;
#layer base {
html {
#screen md {
.text-exampleFont {
font-size: 48px;
}
}
#screen lg {
.text-exampleFont {
font-size: 60px;
}
}
}
}
yourComponent.vue
<div class="text-exampleFont">hello</div>

TailwindCSS and next.js - can't apply custom colors

I am having a particular issue only on one project, which is using nextjs and tailwindcss.
I try to extend the color scheme with some custom colors and intellisennse recognizes the colors, but they are not applied and when I use it with #apply, app just breaks, saying those classes do not exist.
Syntax error: #apply cannot be used with .text-test because .text-test either cannot be found, or its actual definition includes a pseudo-selector like :hover, :active, etc. If you're sure that .text-test exists, make sure that any #import statements are being properly processed before Tailwind CSS sees your CSS, as #apply can only be used for classes in the same CSS tree.
This works in production so colors are applied, error just happens in dev. I can work around it,
but still it boggles me why it is not working.
_app.js
import ClientProvider from '../context/urqlClient'
import makeClient from '../utils/makeUrqlClient'
import '../styles/index.css'
function MyApp({ Component, pageProps }: AppProps) {
return (
<ClientProvider makeClient={makeClient}>
<Component {...pageProps} />
</ClientProvider>
)
}
export default MyApp
tailwind.config.js
module.exports = {
theme: {
colors: {
transparent: colors.transparent,
current: colors.current,
black: colors.black,
white: colors.white,
gray: colors.gray,
orange: colors.orange,
red: colors.red,
},
extend: {
colors: {
barbarian: '#FF7D01',
bard: '#E6CC80',
cleric: '#FFFFFF',
druid: '#FF7D0A',
fighter: '#C79C6E',
monk: '#00FF96',
paladin: '#F58CBA',
ranger: '#ABD473',
rogue: '#FFF569',
sorcerer: '#FF4700',
warlock: '#9482C9',
wizard: '#69CCF0',
},
},
},
variants: {},
plugins: [],
corePlugins: {
float: false,
},
purge: ['./**/*.tsx', './**/*.css'],
future: {
purgeLayersByDefault: true,
removeDeprecatedGapUtilities: true,
},
}
index.css (tailwind stuff only, rest I won't bother you with)
#tailwind base;
#tailwind components;
/* purgecss end ignore */
#tailwind screens;
#tailwind utilities;
html {
font-family: 'Inter var', sans-serif;
width: 100vw;
overflow-x: hidden;
}
...
I think you will need to move your CSS before the #tailwind lines. I think some of your styles must be missing from this component, since I don't see .text-test being referenced anywhere.
Anyways, try this:
html {
font-family: 'Inter var', sans-serif;
width: 100vw;
overflow-x: hidden;
}
...
#tailwind base;
#tailwind components;
/* purgecss end ignore */
#tailwind screens;
#tailwind utilities;

How can I change the underline color in tailwind css

The default underline color in tailwind css is black. How can I change this color for example to a light green.
They have listed a way for one to change the default link underline color in the base style as below
#tailwind base;
a {
color: theme('colors.blue');
text-decoration: underline;
}
#tailwind components;
#tailwind utilities;
How would one go about changing the default normal underline color for say a span tag
There is no way to do that using the default tailwindcss build.
There are 2 ways to override the underline color:
Using simple CSS on your global CSS file
.underline {
text-decoration-color: red;
text-decoration: underline;
}
Extend the underline using the tailwind.config.js config file:
module.exports = {
theme: {
extend: {}
},
variants: {},
plugins: [
function ({addUtilities}) {
const extendUnderline = {
'.underline': {
'textDecoration': 'underline',
'text-decoration-color': 'red',
},
}
addUtilities(extendUnderline)
}
]
}
If you are using v3 of tailwind you can use decoration-{color}.
For example:
<a href="#" class="underline decoration-green">
my link text
</a>
Here are the docs:
https://tailwindcss.com/docs/text-decoration-color

Resources