What does :global (colon global) do? - css

In some SCSS files, I see the following:
:global {
/* ... */
}
I don't know if it is an SCSS feature or a CSS feature.
I tried searching about it but couldn't find any good results at first sight.

The :global operator is used in CSS Modules. Modular CSS uses a CSS Modules compiler to scope CSS styles within their respective modules (e.g., React component).
Here's an example from a React module (in the file ErrorMessaging.less for the ErrorMessaging.jsx React component):
:global(.ocssContainer) {
.ui_column {
padding-left: 0;
}
}
This gets compiled into:
.ErrorMessaging__alertContainer--1I-Cz .ocssContainer .ErrorMessaging__ui_column--3uMUS {
padding-left: 0;
}
But now I add a :global modifier onto .ui_column:
:global(.ocssContainer) {
:global(.ui_column) {
padding-left: 0;
}
}
And this is what it compiles to:
.ErrorMessaging__alertContainer--1I-Cz .ocssContainer .ui_column {
padding-left: 0;
}
Now .ui_column can apply to any child element with that style, including in a child React component, and not just .ui_column elements that are part of the ErrorMessaging React component.

It looks like they are using CSS Modules. If you follow the docs they say:
:global switches to global scope for the current selector resp.
identifier. :global(.xxx) resp. #keyframes :global(xxx) declares the
stuff in parenthesis in the global scope.

The :global selector keyword is used in css modules to specify that a class should not be scoped to the component in which it is defined. This selector allows the class to be used globally in the application, rather than just within a specific component. For example, let say you have a .is-global-class class defined in a CSS Module file, you can use :global(.is-global-class) to apply that class to an element and make it available globally.

Related

change width in ::before property using angular and css [duplicate]

Is there any way to control a CSS variable defined at a component's root level using Angular methods? In JavaScript, we have document.documentElement.style.setProperty() when we set at root level.
In angular, can we use ':host' to declare css variable for global access within component? or do we need to use something like '::ng-deep :root'?
The following question also remains unanswered:
Angular: Use Renderer 2 to Add CSS Variable
Yes you can set variables in root scope:
:root {
--main-color: red
}
Yes you can use :host selector to target element in which the component is hosted.
:host {
display: block;
border: 1px solid black;
}
You can also use, :host-context to target any ancestor of the component. The :host-context() selector looks for a CSS class in any ancestor of the component host element, up to the document root.
:host-context(.theme-light) h2 {
background-color: #eef;
}
Note: ::ng-deep or /deep/ or >>> has been deprecated.
Read more about it here: special css selectors in angular
Just an additional information.
It works both inside ':root' as well as ':host'
We can set values to them by:
constructor(private elementRef: ElementRef) { }
then
this.elementRef.nativeElement.style.setProperty('--color', 'red');
The most constructive and modular way to use css vars in components (with viewEncapsulation) is as such:
// global css
:root {
--main-color: red
--alt-color: blue
}
// inside component component css
::ng-deep :root {
--specific-css-var: var(--main-color)
}
:host {
background-color: var(--specific-css-var)
}
:host(.conditional-class) {
--specific-css-var: var(--alt-color)
}
NOTE: despite ::ng-deep being deprecated, it hasn't been replaced yet (and has no replacement), as can be read in several discussion like this
Best thing for each component like a background color with out using ::ng-deep (which sets bg for all children)
import the following
import {ElementRef} from '#angular/core';
declare elementref in constructor
constructor(private elementRef: ElementRef) {}
then call the function ngAfterViewInit()
ngAfterViewInit(){
this.elementRef.nativeElement.ownerDocument.body.style.backgroundColor = ' white';
}
this sets bg to white but you can replace it with a hex color as well, so you can do that with every component

HIghlighting row during runtime

I am trying to highlight a row based user input. I am using Angular 5, with ag-grid-angular 19.1.2. Setting the style with gridOptions.getRowStyle changes the background, but I would rather use scss classes if possible. The function setHighlight() is called in the html file through (change)=setHighlight()
setHighlight() {
const nextChronoId = this.getNextChronoDateId();
// this.highlightWithStyle(nextChronoId); // Working solution
this.highlightWithClass(nextChronoId);
const row = this.gridApi.getDisplayedRowAtIndex(nextChronoId);
this.gridApi.redrawRows({ rowNodes: [row]})
}
Function definitions:
highlightWithStyle(id: number) {
this.gridApi.gridCore.gridOptions.getRowStyle = function(params) {
if (params.data.Id === id) {
return { background: 'green' }
}
}
}
highlightWithClass(id: number) {
this.gridApi.gridCore.gridOptions.getRowClass = function(params) {
if (params.data.Id === id) {
return 'highlighted'
}
}
}
My scss class:
/deep/ .ag-theme-balham .ag-row .ag-row-no-focus .ag-row-even .ag-row-level0 .ag-row-last, .highlighted{
background-color: green;
}
My issue
Using getRowClass does not apply my highlighted class correctly to the rowNode. After reading (and trying) this, I think that my custom scss class overwritten by the ag-classes. The same problem occurs when using rowClassRules.
Question
How can I make Angular 5 and ag-grid work together in setting my custom scss class correctly?
Stepping with the debugger shows the class is picked up and appended to the native ag-grid classes.
In rowComp.js:
Addition, screen dump from dev tools:
angular's ViewEncapsulationis the culprit here.
First be aware that all shadow piercing selectors like /deep/ or ::ng-deep are or will be deprecated.
this leaves, to my knowledge, two options.
use ViewEncapsulation.None
add your highlighted class to the global stylesheet
setting ViewEncapsulation.None brings its own possible problems:
All components styles would become globally available styles.
I would advise to go with option two.
this answers sums it up pretty well.
Additionally:
.ag-theme-balham .ag-row .ag-row-no-focus .ag-row-even .ag-row-level0 .ag-row-last
this selector will never match anything, you should change it to
.ag-theme-balham .ag-row.ag-row-no-focus.ag-row-even.ag-row-level0.ag-row-last
every class after ag-theme-balham exists on the same element.
with the selector you wrote, you would denote a hierarchy.
Hope this helps

Control CSS variable from Angular 5

Is there any way to control a CSS variable defined at a component's root level using Angular methods? In JavaScript, we have document.documentElement.style.setProperty() when we set at root level.
In angular, can we use ':host' to declare css variable for global access within component? or do we need to use something like '::ng-deep :root'?
The following question also remains unanswered:
Angular: Use Renderer 2 to Add CSS Variable
Yes you can set variables in root scope:
:root {
--main-color: red
}
Yes you can use :host selector to target element in which the component is hosted.
:host {
display: block;
border: 1px solid black;
}
You can also use, :host-context to target any ancestor of the component. The :host-context() selector looks for a CSS class in any ancestor of the component host element, up to the document root.
:host-context(.theme-light) h2 {
background-color: #eef;
}
Note: ::ng-deep or /deep/ or >>> has been deprecated.
Read more about it here: special css selectors in angular
Just an additional information.
It works both inside ':root' as well as ':host'
We can set values to them by:
constructor(private elementRef: ElementRef) { }
then
this.elementRef.nativeElement.style.setProperty('--color', 'red');
The most constructive and modular way to use css vars in components (with viewEncapsulation) is as such:
// global css
:root {
--main-color: red
--alt-color: blue
}
// inside component component css
::ng-deep :root {
--specific-css-var: var(--main-color)
}
:host {
background-color: var(--specific-css-var)
}
:host(.conditional-class) {
--specific-css-var: var(--alt-color)
}
NOTE: despite ::ng-deep being deprecated, it hasn't been replaced yet (and has no replacement), as can be read in several discussion like this
Best thing for each component like a background color with out using ::ng-deep (which sets bg for all children)
import the following
import {ElementRef} from '#angular/core';
declare elementref in constructor
constructor(private elementRef: ElementRef) {}
then call the function ngAfterViewInit()
ngAfterViewInit(){
this.elementRef.nativeElement.ownerDocument.body.style.backgroundColor = ' white';
}
this sets bg to white but you can replace it with a hex color as well, so you can do that with every component

Using css modules how do I define a global class

I am using css modules, however a library I use in a component to append tweets with JavaScript adds some elements to my component in the following structure:
<div class='user'></div>
<div class='tweet'></div>
I want to now style these elements in my css module for the component, as follows:
MyComponent.css
.user {
/* styles */
}
.tweet {
/* styles */
}
However of course now my .user class changes to .MyComponent__user___HZWfM due to the hash naming in the webpack loader.
How can I set a global style in my css module?
According to the css modules docs, :global switches to the global scope for the current selector. e.g.
:global(.example-classname)
So this should work:
:global(.tweet) {
text-align: left;
}
:global(.user) {
text-align: left;
}
Or define a global block
:global {
.tweet {
text-align: left;
}
.user {
text-align: left;
}
}
Can use module class with static class with this way.
myStyle.module.css
.moduleClass_g1m59k:global(.StaticClass) {
background-color: orange;
}
Output will generate like this
.moduleClass_g1m59k.StaticClass {
background-color: orange;
}
Many people have struggled with this and there doesn't seem to be any one agreed upon solution. The one I have settled with involves some tweaking of your bundler and specifically addresses the need to import libraries as-is without having to wrap them or edit them manually.
In my webpack config I have set it to scan all files ending css except those within the 'node_modules' and 'src/static' folders. I import my libraries from here and they dont suffer the classname transforms so I am free to use regular classnames for global css and the className={styles.element} convention as usual for modular css (which will compile down to .component_element__1a2b3 or something similar).
Here is an example of a working production webpack config with this solution:
http://pastebin.com/w56FeDQA

How to override mixins in LESS CSS 1.4+

I've been using what I thought was a very elegant pattern for defining the styles of reusable components/widgets, using LESS. It works beautifully in LESS 1.3-, but after upgrading recently, my whole library is broken. Does anyone know a way to accomplish something like this in 1.4+?
Here's a very simple example of a component:
#componentName {
.loadMixins(){
.text() {}
.header() {}
}
.apply(){
> h3 {
// markup-specific styles
padding: 3px;
margin-bottom: 0;
// custom styles
.header();
}
> div.body, > div.popup p {
color: red;
// custom styles
.text()
}
}
}
And here's how it would be used:
.coolWidget {
#componentName.loadMixins();
// override mixins here
.text(){
color: green;
}
#componentName.apply();
}
This keeps all the markup-dependent styles abstracted from the user. I could completely change my markup and the user's styles would still work. According to the less.js changelog, 1.4.0 Beta 1 has a line "variables in mixins no longer 'leak' into their calling scope"
Is there any way around this?
Strictly speaking nested variables and mixins are still expanded into calling scope unless this scope already has those names defined.
Your example above results in a error:
SyntaxError: .header is undefined...
and it's expected as no .header() is actually defined within the .coolWidget (or anywhere else).
This can be fixed by providing "default" definitions for .text and .header somewhere inside #componentName.
For example if you modify .loadMixins() to:
.loadMixins() {
.text();
.header();
// default properties in case a caller does not provide its own:
.text() {}
.header() {}
}
then the example compiles OK and all text/header properties are overridden as expected.
I can imagine how your library may become broken because of new scope rules but this particular example you gave above does not illustrate the problem.

Resources