React global SCSS: class styling not working - css

I am using React with SASS.
For my components, I am using modular CSS, however, in my Layout.js file, I want to use a main.scss file.
My main.scssfile is working as when I add style to selectors such as body {} or p {}, they style these elements. It's the styles for classes that aren't seeming to come through. For instance, in my global.scss file, I have the following css
body {
margin: 0;
}
.marginsContainer {
width: 90%;
margin: auto;
padding: 100px;
}
The body is working. The .mainContainer isn't.
I am trying to use .mainContainer in my Layout.js file, like so
import Navbar from './Navbar';
import Head from 'next/head';
import '../global-styles/main.scss';
const Layout = (props) => (
<div>
<Head>
<title>Practise Site</title>
</Head>
<Navbar />
<div className="marginsContainer">
{props.children}
</div>
</div>
);
export default Layout;
What might be the problem here?

Are you using css-modules?
In that case, css-modules adds a hash at the end of the class name. You can avoid it by switching to the global scope for your class.
:global {
.marginsContainer {
width: 90%;
margin: auto;
padding: 100px;
}
}
A better solution is to use the class name with the hash, by importing the stylesheet like this.
import styles from '../global-styles/main.scss';
And setting the class name like this.
<div className={styles.marginsContainer}>

Related

Unable to alter CSS styles by id

I have a very simple div in my footer:
import React from "react";
import { useHistory } from "react-router-dom";
import style from "./DesktopFooter.module.css";
const DesktopFooter = () => {
const history = useHistory();
return (
<div className={style.container}>
<div className={style.footerNav} id="phoneNumber">
999-999-9999
</div>
<div className={style.footerNav}>
</div>
<div className={style.footerNav}></div>
</div>
);
};
export default DesktopFooter;
In my CSS I want to style both on the class and id:
.footerNav {
width: 50%;
display: flex;
}
#phoneNumber {
font-size: 2rem;
}
However my component is not recognizing the id styling I try to apply.
Could anyone point me in the right direction.
Ya, After you update a question, I found the issue, you are try to load style for id as normal Dom, but its will not work since you are not include css file as is, you are import style file to style param...
so, what you need to do is replace id="PhoneNumber" to this
<div className={styles["footerNav"]} id={styles["phoneNumber"]}>
999-999-9999
</div>
Check the demo url
Full Code:
import React from "react";
import style from "./MyComponent.module.css";
export default function App() {
return (
<div className={style.container}>
<div className={style["footerNav"]} id={style["phoneNumber"]}>
999-999-9999
</div>
<div className={style.footerNav}></div>
<div className={style.footerNav}></div>
</div>
);
}
I would suggest having it as either a class or an id. Classes usually have a higher priority, meaning that the id will be ignored.
This is what it should look like:
.phoneNumber {
font-size: 2rem;
width: 50%;
display: flex;
}
<div class = "phoneNumber">999-999-9999</div>
However, if you would like to get around this, I would use another element within the div, such as:
#myID{
font-size: 2rem;
}
.phoneNumber {
width: 50%;
display: flex;
}
<div class = "phoneNumber">
<p id="myID"> 999-999-999 </p>
</div>
Ok I found a solution, or at least a work around. The problem seems to be that the file was a css module and not just a css file.
I changed the name of the css file from DesktopFooter.module.css to DesktopFooter.css
and I changed my import statement from
import style from "./DesktopFooter.module.css" to import "./DesktopFooter.css

How styling works over components in angular?

Question is not clear but I'll break it down. In angular we can write isolated css for styling. It works pretty well for native html elements. But unlike react, angular wrap our html with custom elements like <app-card>...</app-card>. When I write css for those wrapper elements, it doesn't work .
If I have a post list like
<div class="post-list">
<app-card [post]="post" *ngFor="let post of posts"></app-card>
</div>
If I write css to apply some vertical gap between app-card components in PostListComponent. Well nothing happens.
.post-list app-card:not(:last-child) {
margin-bottom: 2rem;
}
How can I make it work? Or with angular logic, how can I apply vertical gap between angular components
Just add display: block; on your app-card component & it will work as expected.
.post-list app-card {
display: block;
}
.post-list app-card:not(:last-child) {
margin-bottom: 2rem;
}
<div class="post-list">
<app-card>Card 1</app-card>
<app-card>Card 2</app-card>
<app-card>Card 3</app-card>
</div>
You can define encapsulation: ViewEncapsulation.None in your Component like this:
#Component({
selector: 'foo',
template: './foo.component.html',
styleUrls: ['./foo.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class FooComponent { }
Which will treat your .css as the same if you were putting it in the global scope.
To be more accurate, it won't append .fooComponent to each css rule in foo.component.scss.
You can make the iteration in div tag then add your class
<div class="post-list">
<div class="post" *ngFor="let post of posts">
<app-card [post]="post"></app-card>
</div>
</div>
And in your css
.post-list .post:not(:last-child) {
margin-bottom: 2rem;
}
There is no reason it shouldn't work. Just tried to put in some of your code here. https://stackblitz.com/edit/angular-scss-demo-icqrye
app.component.html
<div class="post-list">
<app-new *ngFor="let item of [1,2,3,4]"></app-new>
</div>
styles.scss
.post-list app-new:not(:last-child) p {
margin-top: 2rem;
color: green;
}
And it works perfectly. Are you looking for something else?
And if you want to add the style (margins) to the component directly, you will first need to set the display of the component to block/flex as per requirement.
.post-list app-new:not(:last-child) {
display: flex;
}

React CSS Modules - Apply style to child each tag

I'm struggling with applying css style for each child of given tag. I'm using CSS modules together with semantic-ui-react:
character.module.css
.Character > GridColumn {
border: solid 4px red;
}
character.js
import React, {Component} from 'react';
import {Grid, GridColumn} from "semantic-ui-react";
import styles from './character.module.css';
class Character extends Component {
render() {
return (
<div>
<Grid centered textAlign='center' className={styles.Character}>
<GridColumn floated='left' width={1}>
<h1>Some content</h1>
</GridColumn>
<GridColumn floated='right' width={2}>
<h1>Some content</h1>
</GridColumn>
</Grid>
</div>
);
}
}
export default Character;
Above approach doesn't work. I tried to apply style manually via chrome tools and border is pretty visible, where I'm making misatke? Is it even possible to do it with CSS modules?
You cant access GridColumn from css as it's not a valid tag.
One Solution: change it to the wrapper div of GridColumm, something like:
.Character > div {
border: solid 4px red;
}
Other Solution is to add class to each GridColumn component in css module file, something like: .GridColumn
Now you can access it through css:
.Character > .GridColumnv{
border: solid 4px red;
}

I have a plunker. When I define my css globally, it works. When I define my css in my component, it fails. What's going on?

With reference to this plunker:
https://plnkr.co/edit/GWsbdDWVvBYNMqyxzlLY?p=preview
I have the same css specified in the styles.css file, and in the src/app.ts file.
If I comment in the css in styles.css and comment out the css in src/app.ts, it works.
styles.css:
/* If these are commented in, and the ones in src/app.ts are
* commented out, the three items are spaced appropriately. */
/***
md-toolbar-row {
justify-content: space-between;
}
md-toolbar {
justify-content: space-between;
}
***/
If I comment out the css in styles.css and comment in the css in src/app.ts, it fails.
src/app.ts:
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<md-toolbar color="primary">
<span><md-icon>mood</md-icon></span>
<span>Yay, Material in Angular 2!</span>
<button md-icon-button>
<md-icon>more_vert</md-icon>
</button>
</md-toolbar>
</div>
`,
// If these are commented in, and the ones in style.css are
// commented out, the three items are scrunched together.
/***/
styles: [
`md-toolbar-row {
justify-content: space-between;
}`,
`md-toolbar {
justify-content: space-between;
}`
]
/***/
})
export class App {
name:string;
constructor() {
this.name = `Angular! v${VERSION.full}`
}
}
I'm having trouble visualizing the difference between defining the css for the whole application, and for the specific component. Can someone tell me what's going on?
=================================
#bryan60 and #Steveland83 seem to indicate that the problem lies somewhere in the view encapsulation. And upon further investigation, it does in a sense.
If you look at the code below, you will see that the styles for md-toolbar and md-toolbar-row have an attribute attached. But the html for md-toolbar and md-toolbar-row does not match. Only md-toolbar has the attribute attached. md-toolbar-row doesn't. I have marked the relevant four lines with >>>>>.
So that's the problem but:
1. Do I report it to the material design people as an error?
2. Is there some workaround I can use today?
<html>
<head>
:
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
<link href="https://rawgit.com/angular/material2-builds/master/prebuilt-themes/indigo-pink.css" rel="stylesheet">
<style>
>>>>> md-toolbar-row[_ngcontent-c0] {
justify-content: space-between;
}
</style>
<style>
>>>>> md-toolbar[_ngcontent-c0] {
justify-content: space-between;
}
</style>
<style>
.mat-toolbar {
display: flex;
: :
.mat-mini-fab,
.mat-raised-button {
outline: solid 1px
}
}
</style>
</head>
<body class="mat-app-background">
<my-app _nghost-c0="" ng-version="4.4.0-RC.0">
<div _ngcontent-c0="">
<h2 _ngcontent-c0="">Hello Angular! v4.4.0-RC.0</h2>
>>>>> <md-toolbar _ngcontent-c0="" class="mat-toolbar mat-primary" color="primary" role="toolbar" ng-reflect-color="primary">
<div class="mat-toolbar-layout">
>>>>> <md-toolbar-row class="mat-toolbar-row">
<span _ngcontent-c0=""><md-icon _ngcontent-c0="" class="mat-icon material-icons" role="img" aria-hidden="true">mood</md-icon></span>
<span _ngcontent-c0="">Yay, Material in Angular 2!</span>
<button _ngcontent-c0="" class="mat-icon-button" md-icon-button=""><span class="mat-button-wrapper">
<md-icon _ngcontent-c0="" class="mat-icon material-icons" role="img" aria-hidden="true">more_vert</md-icon>
</span>
<div class="mat-button-ripple mat-ripple mat-button-ripple-round" md-ripple="" ng-reflect-trigger="[object HTMLButtonElement]" ng-reflect-centered="true" ng-reflect-disabled="false"></div>
<div class="mat-button-focus-overlay"></div>
</button>
</md-toolbar-row>
</div>
</md-toolbar>
</div>
</my-app>
</body>
</html>
One of the Angular features is View Encapsulation which basically means that you can define styles scoped only to a specific component without affecting any other components.
By default styles are scoped only for the component they are referenced in, but you can choose to override that to make them available globally by setting your components encapsulation to None.
E.g.
import { Component, ViewEncapsulation } from '#angular/core';
#Component({
selector: 'component-that-shares-styles',
templateUrl: './component-that-shares-styles.component.html',
styleUrls: ['./component-that-shares-styles.component.scss'],
encapsulation: ViewEncapsulation.None // <-- Set encapsulation here
})
*Note that you will need to import ViewEncapsulation from #angular/core
Okay, with help from #Steveland83 and #bryon60, I came to a definite answer. The Material Design people are aware of this problem. They have made a writeup.
https://github.com/angular/material2/blob/master/guides/customizing-component-styles.md
Here's their summary:
Styling other components
If your component has view encapsulation turned on (default), your component styles will only
affect the top level children in your template. HTML elements belonging to child components cannot
be targeted by your component styles unless you do one of the following:
Add the overriding style to you global stylesheet. Scope the selectors so that it only affects
the specific elements you need it to.
Turn view encapsulation off on your component. If you do this, be sure to scope your styles
appropriately, or else you may end up incidentally targeting other components elswhere in your
application.
Use a deprecated shadow-piercing descendant combinator to force styles to apply to all the child
elements. Read more about this deprecated solution in the
Angular documentation.
I don't want to use global css, or a deprecated solution. I guess I will style with classes, and not elements. If someone has a better idea, tell me!

Overriding the encapsulated :host-style of external component

Is it possible to override :host-styling of an external angular2-component?
We're making a library including a sidebar-component. This component has a default (fallback) background, but this should be overridable by css/theme used in the app.
#Component({
selector: 'sidebar',
styles: [`
:host { background-color: green; }
`],
template: `
<h1>sidebar</h1>
<ng-content></ng-content>
`
})
export class SideBarComponent { .... }
Main App css:
<style>
sidebar {background: red; color: yellow; }
</style>
This returns a sidebar with green background and yellow text, but I want a red background...
Edited:
As found on http://blog.angular-university.io/how-to-create-an-angular-2-library-and-how-to-consume-it-jspm-vs-webpack/: add an attribute to the body-tag:
<body override>
<app></app>
</body>
And in your css: use a selector for this attribute:
[override] hello-world h1 {
color:red;
}
This way, your css does not have to be parsed.
Previous solution:
I've found a solution myself: instead of linking my (theming) css-file in index.html, which isn't parsed, I imported this particular css-file in the app.component.ts annotation.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet/css" type="text/css" href="/assets/style/app.css" />
</head>
<body>
<app></app>
</body>
</html>
app.component.ts:
import { ... }
#Component({
selector: 'app',
styles: [`
#import "assets/style/theme.css";
`],
template: `
...`,
})
export class AppComponent {...}
theme.css:
sidebar {background: red; }
Its not possible to overwrite styles set in a component's styles this way. See point 3 on the "Using Component Styles" section in the Component Styles docs (https://angular.io/docs/ts/latest/guide/component-styles.html)
Our component's styles cannot be changed by changes to styles
elsewhere in the application.
Using :host-context is probably a nicer way to acheive this (although i have never tried myself).
You should try to check the same with host-context. As per documentation host-context works just like the function form of :host(). It looks for a CSS class in any ancestor of the component host element, all the way up to the document root. It's useful when combined with another selector.
In the following example, we apply a background-color style to all <h2> elements inside the component, only if some ancestor element has the CSS class theme-light.
:host-context(.theme-light) h2 {
background-color: #eef;
}

Resources