I'm using tailwind CSS and would like to nest the entire tailwind CSS base/components/utilities code in a nested CSS class so that the code will be applied when used in children of the HTML elements inside that class
I know it's possible to use a prefix system instead, but I don't want to have to modify all html class attributes, so it's not an option for me.
main.css
.webapp {
#tailwind base;
#tailwind components;
#tailwind utilities;
}
I'm using the configuration from the official documentation https://tailwindcss.com/docs/using-with-preprocessors#nesting
postcss.config.js
module.exports = {
plugins: {
'postcss-import': {},
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {},
}
}
tailwind.config.js
module.exports = {
content: [
"../default/pages/*.html"
],
theme: {
extend: {},
},
plugins: [],
}
cmd
tailwindcss --postcss -i ./main.scss -o ./output.css --watch
The problem is that, in output.css, the nesting of the node responsive css class is handled properly but not the media queries
output.css sample
.webapp button,
.webapp input,
.webapp optgroup,
.webapp select,
.webapp textarea {
font-family: inherit;
/* 1 */
font-size: 100%;
/* 1 */
font-weight: inherit;
/* 1 */
line-height: inherit;
/* 1 */
color: inherit;
/* 1 */
margin: 0;
/* 2 */
padding: 0;
/* 3 */
}
#media (min-width: 1024px) {
.lg\:static {
position: static;
}
.lg\:bottom-0 {
bottom: 0px;
}
}
The nesting of .webapp class is only working outside the #media. It's the same for .hover/ and .focus/ . I would need it to include everything to make it work.
Thanks for your help !
Related
I managed to create a scoped CSS class like this:
.container {
#import "./baa";
/* other props ... */
}
but since #import is getting depreciated, what are my options to make a scoped CSS class now?
If you want to keep your CSS separated from any "framework" setup, the best way is probably to use the mixins system. It's definitely not the best way, but it's what come the closest as what you want, without going with CSS modules or else.
You can define your mixins in some file and import them where you need.
Exemple:
#mixin reset-list {
margin: 0;
padding: 0;
list-style: none;
}
#mixin horizontal-list {
#include reset-list;
li {
display: inline-block;
margin: {
left: -2px;
right: 2em;
}
}
}
nav ul {
#include horizontal-list;
}
I've been learning about using CSS in React and have come across the idea of CSS modules, as part of that I came across this article https://blog.fearcat.in/a?ID=00550-af5ece9b-eb49-4e13-8711-26e00c48c84e which discusses using :global and :local in CSS files but it mentions this at one point
:local(.className)
, Which is equivalent to .className
So I understand from this article that using :global would put that CSS rule at the global level, but why use :local if it is equivalent to just having .className? there doesn't seem to be any functional difference.
By default, the CSS in CSS modules is local. But when you use :global qualifier/block, and inside that, if you want to switch back to local CSS, then you should it.
Imagine you are using global mode for CSS modules using css-loader options:
module: {
rules: [
{
test: /\.css$/i,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
// THIS IS IMPORTANT
modules: 'global'
}
}
],
}
]
}
For above configuration, consider following example:
.abc { color: red; }
:global(.abc) { color: green; }
:local .xyz { color: blue; }
:local(.xyz) .pqr { color: yellow; }
.abc :local .xyz .pqr { color: cyan; }
It would be compiled into following CSS.
/* Since it is global model for CSS modules, classname is not hashed */
.abc { color: red; }
/* .global(.abc) has no effect here */
.abc { color: green; }
/* :local .xyz means anything after :local will be hashed */
.dkzEiLgPjIar3vTOyiHv { color: blue; }
/* .local(.xyz) .pqr means only .xyz is hashed */
.dkzEiLgPjIar3vTOyiHv .pqr { color: yellow; }
/* Everything after the :local is hashed i.e. both .xyz and .pqr */
.abc .dkzEiLgPjIar3vTOyiHv .k3SKPTpkzRcircxhU4Dd { color: cyan; }
The difference between :local and :local(selector) is subtle. The former is aggressive (hashed selector after it) and latter is lenient. The same but inverse logic applies if I am using CSS Scope as local i.e. modules: true or modules: 'local'.
Now to your question, why would I use :local inside :global is when I have some component whose styles should be changed when it is inside some or top level component. Imagine, a .text should be 18px in size when it it is inside the .blogArticle. Otherwise this component should render by default as 14px:
:local .text { font-size: 14px; }
.blogArticle :local(.text) { font-size: 18px ;}
But in general, you are right. You would rarely need to put local inside global. The only reason you would be doing that is some legacy complex CSS that you are migrating to newer codebase and want to keep related blocks of CSS closer together for better readability. Last but not least, consider deep nested legacy CSS like this:
.abc :local .xyz .pqr :global(.def) {
color: cyan;
}
I start global, then switch to :local and then again to :global(.def). But needing to do this is a good case of anti-pattern/code-smell.
There is a difference when you will have the same className in multiple components.
For example you have the compoment A with <div className={classes.wrapper}> and then you have Component B with <div className={classes.wrapper}. With normal css the if the attributes in css file of those "wrapper" class will be different will overide the first one by the last one.
Is like blocked scoped in your component and dont "lives" away from the component.
And of course you can add every other attribute in global.css file that will occur in the whole project
.wrapper{ //component A
display:flex;
flex-direction:column;
}
.wrapper { //component B
display:flex;
flex-direction:column;
width:60%;
}
With normal css the last attributes will overide the first .wrapper so with modules is 100% not the same style in your div.
Not sure what the best way to import is but '#import' is deprecated and #use should be used instead. I have a grid file that I want to include in style.scss .
_grid.scss
.main-content {
display:grid;
/* Set up grid stuff */
}
header{
grid-area: header;
}
I need to import into here.
style.scss
body{
/* More code here */
}
The final complied code should look like this:
.main-content {
display:grid;
/* Set up grid stuff */
}
header{
grid-area: header;
}
body{
/* More code here */
}
I know this is wrong, but this is what I have tried:
#use 'grid' as *;
$main-content
What about using a mixin?
_grid.scss
#mixin grid {
/* Wrap all the code here from _grid.scss */
.main-content {
display:grid;
/* Set up grid stuff */
}
header{
grid-area: header;
}
}
style.css
#use 'grid' as *;
#include $grid
body{
}
#use is really tricky at the moment ... a real big impact to the language.
(A) First of all you should check if you indeed use the most actual SASS version: DART SASS. HEAD UP: MOST actual compilers even in good maintained frameworks DO NOT YET!!! Here are information about how to find/install compiler with most actual version:
Solution with installing via NPM:
Is it better to use the Live Sass Compiler (VS Code extension) or to install and run Sass via npm? (+ tips how to change from node-sass to dart-sass)
If more comfortable with VS Code:
Live Sass Compiler - #use causes compilation error
(B) #use changes the structure how to write SASS code substantial.
What NOT works with #use is to import code right in the middle of the code like you can do with #import. So, if you need to do so you are right with your last code example using a mixin including code to the body tag. But you need to move the mixin to the body tag where you want to include the code:
//### > SASS _grid.scss
#mixin grid {
.main-content {
display:grid;
/* Set up grid stuff */
}
header{
grid-area: header;
}
}
//### > SASS main.scss
#use 'grid' as *;
body {
#include grid;
}
//### --> compiles to CSS
body .main-content {
display: grid;
/* Set up grid stuff */
}
body header {
grid-area: header;
}
But honestly there are very few scenarios when you need to nest your grid css into the body tag!
If you divide your SASS into partial files and do the output in a main file which only wraps all code together you are able to do use #use very similar to the common use of #import. Example:
//### > SASS PARTIAL _typography.scss
/* TYPOGRAPHY */
html {
font-family: sans-serif;
}
h1 {
font-size: 24px;
}
//### > SASS PARTIAL _structure.scss
/* STRUCTURE */
header{
padding: 10px 20px;
background: darkgray;
}
main {
padding: 20px 20px;
background: white;
}
footer {
padding: 20px 20px 80px 20px;
background: black;
}
//### > SASS PARTIAL _grid.scss
/* GRID HELPER CLASSES */
.grid-col_4 {
display: grid;
grid-template-columns: 25% 25% 25% 25%;
}
//### > SASS MAIN main.scss
// WRAP PARTIALS TOGETHER
// only '#use' files, no css code here
#use 'typography' as *;
#use 'structure' as *;
#use 'grid' as *;
//### --> compiles to CSS
/* TYPOGRAPHY */
html {
font-family: sans-serif;
}
h1 {
font-size: 24px;
}
/* STRUCTURE */
header {
padding: 10px 20px;
background: darkgray;
}
main {
padding: 20px 20px;
background: white;
}
footer {
padding: 20px 20px 80px 20px;
background: black;
}
/* GRID HELPER CLASSES */
.grid-col_4 {
display: grid;
grid-template-columns: 25% 25% 25% 25%;
}
HEAD UP:
Even that seems very similar to the use of #import there is a VERY BIG DIFFERENCE to #import.
If you use variables/mixins/functions you are not able to #import them to the main.scss as before first and they are ready to use by the next included files! With #use now YOU HAVE TO #use the files separatly in every partial file where you need the variables/mixins/function.
If you like you may have an additional look about how that works:
https://stackoverflow.com/a/66300336/9268485
But note: what sounds easy indeed is more complicated in practical use ... even when the projects and modules are bigger and more structured ...
Project configurations splinters to different configurations files and in some cases it additional seems to lead to code/variables repetitions if you need to include different modules with same variables settings ... in every case more code is needed. But up to now that seems to be the future ...
I ended up just using #import , I seriously doubt they would remove it in the next 3 years and break everyone's code everywhere
In vuetify they have helper classes for typography.
for example, .display-4 goods for h1. here the full list.
When I choose display-1 for some element, In all resolutions the class gets the same font size (34px).
I was expecting to:
.display-4 will have font size of 34px in screen wide of 1024px.
.display-4 will have font size of 18px in screen wide of 300px.
According to this I have two questions, why is that? and how to make my font size elements be responsive using vuetify?
Update
Vuetify version 1.5
Take a look at display helpers example to see how to use a class when hitting a breakpoint. That being said, you can use dynamic class binding and breakpoint object in Vuetify.
Example:
:class="{'subheading': $vuetify.breakpoint. smAndDown, 'display-2': $vuetify.breakpoint. mdAndUp}"
Vuetify version 2
breakpoint object
Display
My solution changes font-sizes globally in the variables.scss file:
This is assuming you're using Vuetify 2 and #vue/cli-service 3.11 or later.
Step 1:
In src/scss/ create _emptyfile.sass and _font-size-overrides.scss.
In the _emptyfile.sass you can add this comment:
// empty file to workaround this issue: https://github.com/vuetifyjs/vuetify/issues/7795
Step 2:
In the _font-size-overrides.scss file:
/**
* define font-sizes with css custom properties.
* you can change the values of these properties in a media query
*/
:root {
--headings-size-h1: 28px;
--headings-size-h2: 22px;
#media #{map-get($display-breakpoints, 'lg-and-up')} {
--headings-size-h1: 32px;
--headings-size-h2: 26px;
}
}
Step 3:
In the variables.scss file (where you override the Vuetify variables):
/**
* Override Vuetify variables as you normally would
* NOTE: remember to provide a fallback for browsers that don't support Custom Properties
* In my case, I've used the mobile font-sizes as a fallback
*/
$headings: (
'h1': (
'size': var(--headings-size-h1, 28px),
),
'h2': (
'size': var(--headings-size-h2, 22px),
)
);
Step 3:
In the vue.config.js file:
module.exports = {
css: {
loaderOptions: {
sass: {
prependData: `#import "#/scss/_emptyfile.sass"` // empty file to workaround this issue: https://github.com/vuetifyjs/vuetify/issues/7795
},
scss: {
prependData: `#import "#/scss/variables.scss"; #import "#/scss/_font-size-overrides.scss";`,
}
}
},
};
font-sizes globally in the variables.scss file
html {
font-size: 90%;
#media only screen and (min-width: 600px) {
font-size: 94%;
}
#media only screen and (min-width: 1000px) {
font-size: 98%;
}
#media only screen and (min-width: 1200px) {
font-size: 100%;
}
}
I'm setting up a basic angular app, and I'm trying to inject some css to my views. This is an example of one of my components:
import { Component } from 'angular2/core';
import { ROUTER_PROVIDERS, ROUTER_DIRECTIVES, RouteConfig } from 'angular2/router';
import { LandingComponent } from './landing.component';
import { PortfolioComponent } from './portfolio.component';
#Component({
selector: 'portfolio-app',
templateUrl: '/app/views/template.html',
styleUrls: ['../app/styles/template.css'],
directives: [ROUTER_DIRECTIVES],
providers: [ROUTER_PROVIDERS]
})
#RouteConfig([
{ path: '/landing', name: 'Landing', component: LandingComponent, useAsDefault: true },
{ path: '/portfolio', name: 'Portfolio', component: PortfolioComponent }
])
export class AppComponent { }
Now the .css file is requested from my server, and when I inspect the page source, I can see it was added to the head. But something weird is happening:
<style>#media (min-width: 768px) {
.outer[_ngcontent-mav-3] {
display: table;
position: absolute;
height: 100%;
width: 100%;
}
.mainContainer[_ngcontent-mav-3] {
display: table-cell;
vertical-align: middle;
}
.appContainer[_ngcontent-mav-3] {
width: 95%;
border-radius: 50%;
}
.heightElement[_ngcontent-mav-3] {
height: 0;
padding-bottom: 100%;
}
}</style>
gets generated from this file:
/* Small devices (tablets, 768px and up) */
#media (min-width: 768px) {
/* center the mainContainer */
.outer {
display: table;
position: absolute;
height: 100%;
width: 100%;
}
.mainContainer {
display: table-cell;
vertical-align: middle;
}
.appContainer {
width: 95%;
border-radius: 50%;
}
.heightElement {
height: 0;
padding-bottom: 100%;
}
}
Can somebody please explain where the _ngcontent-mav tag comes from, what does it stand for and how to get rid of it?
I think this is the reason why my style is not getting applied to my templates.
If you need more info about the app structure, please checkout my gitRepo, or ask and I'll add the code to the question.
Thanks for the help.
update2
::slotted is now supported by all new browsers and can be used with `ViewEncapsulation.ShadowDom
https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted
update
/deep/ and >>> are deprecated.
::ng-deep replaces them. ::-deep is also marked deprecated in source and the docs, but this means that it will also be removed eventually.
I think it depends on what W3C comes up with for theming the shadow DOM (like https://tabatkins.github.io/specs/css-shadow-parts/)
It's basically a workaround until all browsers support that natively and ViewEncapsulation.Emulated can be removed entirely.
::ng-deep is also supported in SASS (or will be, depending on the SASS implementation)
original
View encapsulation helps to prevent styles bleeding into or out of components. The default encapsulation is ViewEncapsulation.Emulated where classes like _ngcontent-mav-x are added to component tags and also styles are rewritten to only apply to matching classes.
This emulates to some degree the default behavior of the shadow DOM.
You can disable this encapsulation adding encapsulation: ViewEncapsulation.None to the #Component() decorator.
Another way is the recently (re-)introduced shadow piercing CSS combinators >>>, /deep/, and ::shadow. These combinators were introduced for styling shadow DOM but are deprecated there. Angular introduce them recently until other mechanisms like CSS variables are implemented.
See also https://github.com/angular/angular/pull/7563 (https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta10-2016-03-17)
>>> and /deep/ are equivalent and using this combinators makes the styles ignore the the added helper classes (_ngcontent-mav-x)
* >>> my-component, /* same as */
* /deep/ my-component {
background-color: blue;
}
applies to all my-component tags not matter how deep they are nested in other components.
some-component::shadow * {
background-color: green;
}
applies to all elements in the template of some-component, but not further descendants.
They can also be combined
* /deep/ my-component::shadow div {
background-color: blue;
}
this applies to all div elements in the template of all my-component templates no matter how deep my-component is nested in other components.
/deep/, >>>, and ::shadow can only be used with
encapsulation: ViewEncapsulation.None
encapsulation: ViewEncapsulation.Emulated
encapsulation: ViewEncapsulation.Native when the browser supports them natively (Chrome does but prints a warning in the console that they are deprecated) or
when the browser doesn't native support shadow DOM and the
web_components polyfills are loaded.
For a simple example see also the Plunker from this question https://stackoverflow.com/a/36226061/217408
See also this presentation from ng-conf 2016 https://www.youtube.com/watch?v=J5Bvy4KhIs0
You should try this,
import {ViewEncapsulation} from 'angular2/core';
#Component({
...
encapsulation: ViewEncapsulation.None,
...
})