Tailwind CSS: The `outline` class does not exist. Yet this is not a custom style, but a framework class - css

In a new project I get the strange behavior where everything works as intended, except for Outline and related: https://tailwindcss.com/docs/outline-style
The error received:
The outline class does not exist. If you're sure that outline
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 is in an #apply for a component eg:
.button {
#apply bg-primary hover:bg-secondary;
}
.primary {
#apply border-2 md:border-none border-primary md:border-transparent;
}
Yet this does not work:
.outline {
#apply outline outline-2 outline-offset-2 focus:outline-yellow-500;
}
To ensure this is in the same import tree, these are applied in the index.css as part of the components layer:
#layer components {
...
}
Any insights into this will be highly appreciated, as none of the references (tailwind documentation, nor their repo bugs, addresses this issue in a workable manner, each example found points to user error. Which may just be the case here, but I am yet to find the issue.

You can't apply a class to itself. outline is already defined (one of the default tailwind classes), you are trying to define and apply it again.
See the error: https://play.tailwindcss.com/cdQLeYFcNH?file=css
Error
<css input>: Circular dependency detected when using: #apply outline
Use a different custom class. Like .custom-outline: https://play.tailwindcss.com/qo8M6Zkj31

Related

TailwindCSS 3 classes doesn't override previous classes

I am facing an issue which is mind-numbing in the world of CSS.
TailwindCSS 3 classes just doesn't override previous classes.
For example, there is this component, I created:
import * as React from "react";
const TextBox = ({ addClassName, children }) => {
const className = `text-xl leading-7.5 font-lato font-normal ${addClassName}`;
return <div className={className}>{children}</div>;
};
export default TextBox;
Then I go ahead and use this component above at another place, like this:
<TextBox addClassName="text-4xl">My New Text</TextBox>
Now when I inspect it in the browser, it shows both of the font-size:
Screenshot from the browser inspect
class="text-xl leading-7.5 font-lato font-normal text-4xl"
As you can see both of the classes are there, both referring to font-size, and the larger one is after the smaller one.
And still ONLY the small ( the original ) font-size will be the dominant.
( as a side note, I did try to put the addClassName variable in the front as well, no help )
Why is this?
I appreciate any help getting with this.
Thank you
I found the answer from dev.to.
The reasons your code didn't work are:
It turns out that the space-separated CSS class list that the class HTML attribute accepts is not treated as a list when calculating CSS rules precedence by the browser. The class attribute actually contains the set of classes the element has, so the order doesn't matter.
As the order that the classes appear in the class attribute doesn't matter, the rule that comes later in the CSS stylesheets wins.
Moreover, it wasn't warranted that the 'text-4xl' was defined after the 'text-xl' in the CSS stylesheet.
So to solve this problem, I recommended using tailwind-merge to override previous classes.
Tailwind-merge is a utility function to efficiently merge Tailwind CSS classes in JS without style conflicts.
One of its features was: Last conflicting class wins
twMerge('p-5 p-2 p-4') // → 'p-4'
Quoting from redit
In CSS if you have two selectors with equal specificity the one that comes last in the CSS structure takes precedence. The order in the class attribute has no effect.
Suggested solution would be to write your own class after tailwindcss import statement, or edit it using inline style.
My personal tip: Don't use two classes that target the same css property, text-lg and text-4xg both target font-size, you need a way (suggest clsx lib) to put only one class name and not the other
import clsx from 'clsx';
let condition = false;
function Component(){
return (
<div>
<p className={clsx({
"text-lg": condition,
"text-4xl": !condition,
})}>
...
</p>
</div>
);
}
I have had the same problem, and didn't want to add yet another dependency and increase my app's bundle size to solve something that doesn't have to be this hard. So I looked into the tailwind docs and found this:
Use the components layer for any more complicated classes you want to
add to your project that you’d still like to be able to override with
utility classes.
#tailwind base;
#tailwind components;
#tailwind utilities;
#layer components {
.card {
background-color: theme('colors.white');
border-radius: theme('borderRadius.lg');
padding: theme('spacing.6');
box-shadow: theme('boxShadow.xl');
}
/* ... */
}
By defining component classes in the components layer, you can still
use utility classes to override them when necessary:
<!-- Will look like a card, but with square corners -->
<div class="card rounded-none">
<!-- ... -->
</div>
Though this means you will have to write a component class every time you want to override an element with predefined classes.
https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes
I would suggest you to try clsx or clsssnames for better usage with tailwind classes instead of string interpolation
I found a Solution guys.
Setup props with default CSS values at the original component, and then at the time of the usage of this aforementioned component, if we need different style, we just gave that in the props.

Sass generated classes not getting applied

I have a custom sass setup with bootstrap 5 and bunch of my own SCSS files, all of this gets compiled in style.css using gulp. I have a _colors.scss file which stores all the colors according to our design language. We use this to generate a bunch of classes that can be used any where to change colors:
// Text Colors
$colors: (
"icon-color": $slate-500,
'slate-10': $slate-10,
'slate-40': $slate-40,
'slate-300': $slate-300,
"secondary": $secondary-text-color,
"green": $green,
"light-green": $green-color,
"blue": $blue,
"blue-200": $blue-200,
"blue-300": $blue-300,
"blue-400": $blue-400,
"dodger-blue": $dodger-blue,
"mariner-blue": $mariner-blue,
"light-blue": $blue-100,
"cadet-blue" : $cadet-blue,
"aqua-10": $aqua-10,
"gray": $gray,
"gray-light": $gray-light,
"light-gray": $gray-100,
"bright-gray": $bright-gray,
"gray-200": $gray-200,
"clay": $clay,
"clay-10": $clay-10,
"mandy-pink": $mandy-pink,
"aqua": $aqua,
"violet": $violet,
"white": $white,
"primary": $primary-text-color
);
#each $color-name, $color-value in $colors {
.text-#{$color-name} {
color: $color-value !important;
}
.bg-#{$color-name} {
background-color: $color-value !important;
}
.border-#{$color-name} {
border-color: $color-value !important;
}
}
Problem is certain classes like .text-gray or .text-blue are not working. My guess is that since bootstrap also uses variables called gray and blue, its conflicting with my variables in _colors.scss.
On closer look, the css does gets generated properly (I found below declaration in final style.css):
.case-study .case-study-right .card .data-bar p:last-of-type,.share .social-media>span,.text-color-gray-200,.text-gray-200 {
color: #69727A!important
}
But using .text-gray has no effect, the class is not getting applied.
How do I fix this? please help!
First, if you're sure that you see the correct selector and the correct rule in your CSS file: it should be applied. And so, the rule should be visible in the browser console (even if overridden).
If you see it in your CSS file, but not applied in the browser console: check that your CSS file is valid (and that your gulp production script compiles fine), as a bad character could mess some part of it.
If you see your CSS in the browser console, but it's overridden by some bootstrap rules, you can override bootsrap variables, and change bootstrap colors by yours like so (import bootstrap before this):
$theme-colors: (
primary: #121212,
success: #8bcea8
...
);
You could also try this to replace bootstrap values by yours:
$theme-colors: map-merge($theme-colors, $colors);
The simple answer is:
Use Bootstrap 5 the intended way!
Bootstrap is a complex framework. All that huge number of classes work together including overwriting color settings if provided and used the intended way. In your code example you additional create helper classes Bootstrap would provide to you out of the box if you use it the Bootstrap way. As you did not do it leads to conflicts which are not easy to handle ... and nearly impossible to solve without to have the possibility to analyize the page itself.
This is what you may check:
You may check: are there other classes which blocks your classes?
In your example you use !important to get higher specifity. But the color is overwritten by other classes ...
Maybe that are Bootstrap which uses !important as well. In that case you can try to add your classes at the end of your CSS (after the Bootstrap classes) so they are able to overwrite in case of identical specifity.
Additional: in your example you added a huge bunch of non-bootstrap-classes. Maybe this individual added classes blocks your styling by adding a color with higher specifity (using !important as well which is not a good technique at all) to your element than your added class do.
In that case same solution may be possible ... but individual classes with !important and an additional higher specifity (i.e. using two class names in the selector) will win over your helper classes also your helper class comes later in your CSS file.
To be honest: most often analyzing such an huddle of classes indeed is only possible in the browser on the page direct using the developer tools.
But best way indeed would be ...
Do a correct Bootstrap theming and use Bootstrap classes!!!
You really don't need to create the helper classes on your own. Just do a SASS setup of Bootstrap ... and add your needed/additional colors NOT (or not only) to map $colors but AS WELL TO Bootstrap map $theme-colors. Bootstrap builds up helper-/utility-/elements-color-classes not on $colors but on $theme-colors. That means: doing that this intended way ... all your helper classes you added in your project on your own will be provided by Bootstrap mechanic in the correct order and avoiding conflicts to your CSS.
Use Bootstrap classes to style your page. Now you don't need to create an additional class .case-study { color: gray }. Just use the Bootstrap helper class and add .text-gray to same element. (Note: In your example you use the incredible number of NINE classes to do the same styling. In case 'text in cards' here is a nice hint how to realize it the bootstrap way: https://getbootstrap.com/docs/5.0/components/card/#border).
Just thinking about using complex Framework...
Bootstrap is done to help you. As there is a lot of code using that Framework only makes sense to use the code as much as possible without writing new classes. So best way indeed to work with it is to use the Bootstrap elements and styling them the Bootstrap way. That makes it simple and avoids conflicts... And: you are able to do nearly everything with these elements.
And if you need to extend Bootstrap i.e. with additonal classes: avoid (deep) nested classes and !important as well so you are able to overwrite settings with simple helper classes.
i had the similar problem it was my scss was successfully converted to the css but not applied, after checking for hours i found out ,i have written B capital while the class name was btn
so when everything is working then the problem is always in your code syntax!

Hash or prefix all CSS class names in a Vue CLI project to avoid class inheritance

I need to hash (or just prefix_) all CSS class names in a Vue CLI project to avoid class inheritance when I embed the app inside an existing HTML page.
Basically the Vue app/widget I've made uses some CSS class names like .title, .container, .date, .location etc, and the problem I've got is that the global CSS on the website where I'm embedding this Vue app already uses the class names .title, .container etc, so it's applying those styles to my Vue app as well. I just want a simple way — maybe using vue.config.js — to instruct webpack to randomly hash or prefix the CSS class names so that they are completely unique and won't inherit any parent styling. Thanks
Thanks to the comments above I managed to get it to work. The implementation is not as straight forward as I'd have liked because it requires changing a lot of my existing code — I was hoping for a quicker, simpler solution that would just take my existing code and hash the preexisting CSS classes — which I'm pretty sure must be possible as it seems like such a trivial task? Anyway, here's my setup for now:
vue.config.js
module.exports = {
css: {
requireModuleExtension: false,
loaderOptions: {
css: {
modules: {
localIdentName: '[hash:6]'
}
}
}
}
}
my-component.vue
<template>
<div :class="$style.myClass"> ... </div>
</template>
<style module>
.myClass {
color: red;
}
</style>
Using the above setup I get a div which, instead of being:
<div class="myClass"> ... </div>
is now rendered as:
<div class="_2d736c"> ... </div>
Note the module attribute on the <style> tag which is important. Also note the class name binding: :class (or v-bind:class) not just class.
Hope that helps someone. Thanks

How and where to use ::ng-deep?

How and where can one use ::ng-deep in Angular 4?
Actually I want to overwrite some of the CSS properties of the child components from the parent components. Moreover is it supported on IE11?
Usually /deep/ “shadow-piercing” combinator can be used to force a style down to child components. This selector had an alias >>> and now has another one called ::ng-deep.
since /deep/ combinator has been deprecated, it is recommended to use ::ng-deep
For example:
<div class="overview tab-pane" id="overview" role="tabpanel" [innerHTML]="project?.getContent( 'DETAILS')"></div>
and css
.overview {
::ng-deep {
p {
&:last-child {
margin-bottom: 0;
}
}
}
}
it will be applied to child components
I would emphasize the importance of limiting the ::ng-deep to only children of a component by requiring the parent to be an encapsulated css class.
For this to work it's important to use the ::ng-deep after the parent, not before otherwise it would apply to all the classes with the same name the moment the component is loaded.
Using the :host keyword before ::ng-deep will handle this automatically:
:host ::ng-deep .mat-checkbox-layout
Alternatively you can achieve the same behavior by adding a component scoped CSS class before the ::ng-deep keyword:
.my-component ::ng-deep .mat-checkbox-layout {
background-color: aqua;
}
Component template:
<h1 class="my-component">
<mat-checkbox ....></mat-checkbox>
</h1>
Resulting (Angular generated) css will then include the uniquely generated name and apply only to its own component instance:
.my-component[_ngcontent-c1] .mat-checkbox-layout {
background-color: aqua;
}
USAGE
::ng-deep, >>> and /deep/ disable view encapsulation for specific CSS rules, in other words, it gives you access to DOM elements, which are not in your component's HTML. For example, if you're using Angular Material (or any other third-party library like this), some generated elements are outside of your component's area (such as dialog) and you can't access those elements directly or using a regular CSS way. If you want to change the styles of those elements, you can use one of those three things, for example:
::ng-deep .mat-dialog {
/* styles here */
}
For now Angular team recommends making "deep" manipulations only with EMULATED view encapsulation.
DEPRECATION
"deep" manipulations are actually deprecated too, BUT it's still working for now, because Angular does pre-processing support (don't rush to refuse ::ng-deep today, take a look at deprecation practices first).
Anyway, before following this way, I recommend you to take a look at disabling view encapsulation approach (which is not ideal too, it allows your styles to leak into other components), but in some cases, it's a better way. If you decided to disable view encapsulation, it's strongly recommended to use specific classes to avoid CSS rules intersection, and finally, avoid a mess in your stylesheets. It's really easy to disable right in the component's .ts file:
#Component({
selector: '',
template: '',
styles: [''],
encapsulation: ViewEncapsulation.None // Use to disable CSS Encapsulation for this component
})
You can find more info about the view encapsulation in this article.
Make sure not to miss the explanation of :host-context which is directly above ::ng-deep in the angular guide : https://angular.io/guide/component-styles. I missed it up until now and wish I'd seen it sooner.
::ng-deep is often necessary when you didn't write the component and don't have access to its source, but :host-context can be a very useful option when you do.
For example I have a black <h1> header inside a component I designed, and I want the ability to change it to white when it's displayed on a dark themed background.
If I didn't have access to the source I may have to do this in the css for the parent:
.theme-dark widget-box ::ng-deep h1 { color: white; }
But instead with :host-context you can do this inside the component.
h1
{
color: black; // default color
:host-context(.theme-dark) &
{
color: white; // color for dark-theme
}
// OR set an attribute 'outside' with [attr.theme]="'dark'"
:host-context([theme='dark']) &
{
color: white; // color for dark-theme
}
}
This will look anywhere in the component chain for .theme-dark and apply the css to the h1 if found. This is a good alternative to relying too much on ::ng-deep which while often necessary is somewhat of an anti-pattern.
In this case the & is replaced by the h1 (that's how sass/scss works) so you can define your 'normal' and themed/alternative css right next to each other which is very handy.
Be careful to get the correct number of :. For ::ng-deep there are two and for :host-context only one.
Just an update:
You should use ::ng-deep instead of /deep/ which seems to be deprecated.
Per documentation:
The shadow-piercing descendant combinator is deprecated and support is
being removed from major browsers and tools. As such we plan to drop
support in Angular (for all 3 of /deep/, >>> and ::ng-deep). Until
then ::ng-deep should be preferred for a broader compatibility with
the tools.
You can find it here
I looked through all those answers and found nobody mentioned a child component can pass a style CSS in from its parent.
In component ts file, you can use this:
#Input() styles: any = {};
In component html file, you use this:
[ngStyle]="styles"
in parent, you use this :
<yourComponent [styles]="{backgroundColor: 'blue', 'font-size': '16px'}">
Please see more details here: Best way to pass styling to a component
In this way, we didn't break encapsulation, which is one of those most important Object orientation principles
Use ::ng-deep with caution. I used it throughout my app to set the material design toolbar color to different colors throughout my app only to find that when the app was in testing the toolbar colors step on each other. Come to find out it is because these styles becomes global, see this article Here is a working code solution that doesn't bleed into other components.
<mat-toolbar #subbar>
...
</mat-toolbar>
export class BypartSubBarComponent implements AfterViewInit {
#ViewChild('subbar', { static: false }) subbar: MatToolbar;
constructor(
private renderer: Renderer2) { }
ngAfterViewInit() {
this.renderer.setStyle(
this.subbar._elementRef.nativeElement, 'backgroundColor', 'red');
}
}

Multiple class extension not working as expected - final styles generated in the wrong order

The order in which styles are generated seems to be incorrect when extending multiple styles. Consider the following case.
Here are my styles:
.decline {
#extend .minus, .circle;
}
The extended styles simply add content to the before section of the icon.
And this is the HTML (just for reference):
<i class="decline icon"></i>
The target HTML I actually need is as follows:
<i class="minus circle icon"></i>
I cannot directly just add this since the decision of which styles to apply is governed by other logic. And so I used style extension to simplify this process.
The compiler however generates the following CSS:
i.icon.circle:before, i.icon.decline:before {
content: "\f111";
}
i.icon.minus.circle:before, i.icon.decline:before {
content: "\f056";
}
i.icon.minus:before, i.icon.decline:before {
content: "\f068";
}
What I actually wanted was for the 2nd in the above generated list to be used. But it always ends up selecting the 3rd for the final style, regardless of any order in which I try to extend the styles. If I don't use SCSS and manually add the CSS styles after rearranging them so that the 2nd comes last in the ordering, I get what I need.
Is there something wrong with the way I'm doing it or is there an issue with extending multiple classes?
Please note that this is an exact duplicate of an issue I raised on Github. Didn't get any response there, so thought I'd come here for help.

Resources