ReactJS styles 'leaking' to other components - javascript

So I have two components... a Navbar component, and an AboutPage component.
They are both in the same directory, 'App'
App
-- Navbar --> Navbar.css, Navbar.js
-- AboutPage --> Aboutpage.css, Aboutpage.js
So as you can see, they have two separate stylesheets.
In the JS pages the correct CSS file is being imported as well.
When I do a style like this for example:
Navbar Component
p { background: red }
^^ this style also applies to the p's in the Aboutpage. I even tried to give the P in Aboutpage its on id and style it that way and it still failed.

That's the expected behaviour.
No matter which file you specify a rule like p { background: red }, it's going to be applied to all DOM.
Specifying and id attribute to won't work either. The above rule is general enough to apply to all <p>s.
If you want to specify css files for each component, you should also create component specific css classes. Like the following example.
import React from 'react';
import './DottedBox.css';
const DottedBox = () => (
<div className="DottedBox">
<p className="DottedBox_content">Get started with CSS styling</p>
</div>
);
export default DottedBox;
and its css file:
.DottedBox {
margin: 40px;
border: 5px dotted pink;
}
.DottedBox_content {
font-size: 15px;
text-align: center;
}
If you want different ways of defining css for React, this resource adds 3 more ways of doing so, in addition to the above way.

You can also use css modules. They scope your CSS locally and are awesome

Scoping styles to a component requires WebComponents which relies on several newer browser features, particularly shadowRoot "shadownDOM" which supports this separation directly. These are most easily used with lit-element and/or Polymer 3.

Sometimes we need a global CSS which could affect another component even if we use module import, I didn't find anything to answer that in the official documentation, so my workaround is to use something like the following code in the component itself, and, it works fine :)
<style>
{
`
#page {
padding:0;
margin-top:0;
margin-bottom: 0;
margin-left: 0;
margin-right:0;
}
#media print {
#page {
size: 80mm 21cm;
}
}
`
}
</style>

Related

One of the styles doesn't work but the other do

I am making a web page to play a game. It uses two containers (inside a component). They show 2 images but by default they are empty. I apply one style to them: img-container which set the dimentions and color the background (it must be black), but the style doesn't work, although all other styles do.
Clarifications: At start, the div uses 2 classes (img-container and flex-child, which works fine). Also, I am working with Visual Studio Code.
I already try: change class name, reboot the host (closing VS Code an using 'npm start'), using another web browser (chrome and firefox) and change property values for bigger ones. This doesn't work but insert the properties in preexisting CSS classes and call they do.
Component code:
import React, { Component } from 'react';
//Class component
class PPT extends Component {
render() {
return (
<div id = "PPT">
<h3 id="explanation">¿Cómo se juega? </h3>
<div id="container" className="flex-parent">
<div id="player_hand" className="flex-child">
<h2>Jugador</h2>
<div className="img-container"></div>
</div>
<div id="computer_hand" className="flex-child">
<h2>Computadora</h2>
<div className="img-container"></div>
</div>
</div>
</div>
)
}
}
export default PPT;
CSS style:
#PPT {
margin-top: 90px;
margin-bottom: 15px;
}
#img-container {
background-color: #262626;
width: 474px;
height: 266px;
}
You are using #img-container while you must use .img-container because it's a class. I also suggest that you remove that hyphen(-) and use an _ instead to maintain proper naming convention of classes in react and to also respect lint rule as your approach will show a warning in some editors. At the end your class name must look like img_container in jsx and like this .img_conatiner in css.
The wrong part is this section in your JSX:
className="img-container"
since you are using className you have to provide a class in your related css file for it, like below:
.img-container {
background-color: #262626;
width: 474px;
height: 266px;
}
You are selecting your element in a wrong way!
In CSS, # is an ID selector, while . is a class selector. So, to target an element with class name img-container, you should use .image-container, and not #img-container.

Can I add a classname to a CSS variable?

Is it possible to add a classname to a CSS variable or is there some other way to set it up so that I don't have to manipulate each individual variable directly via javascript? I'd like to keep all my styles in CSS and simply turn on relevant classes with JS. For example, If something like this was possible in CSS:
:root.white{ --bgcol:#FFF; --col:#000; }
:root.black{ --bgcol:#000; --col:#FFF; }
Then I could then just toggle the .black or .white class from javascript to trigger all vars to change. What's the best approach for this type of setup?
That's frankly the best (as in most idiomatic) approach — the use of class names, if not altogether separate stylesheets (as has been tradition for many, many years), to theme entire layouts via custom properties. It's the most "fundamentally CSS" approach with JavaScript merely being the glue that makes the theme switching work. You really can't do much better than that.
For those unaware what :root means and wondering where exactly the class names are being applied, it's the html element (the parent of body). So there is nothing special going on here — you're simply switching class names on the html element. It just happens that global custom properties are conventionally defined for the document root element since it's at the top level of the inheritance chain.
If you have any theme-agnostic custom properties, as well as style properties (i.e. not custom properties) that apply to the root element, keep them in their own unqualified :root rule, separate from your themed custom properties, so they won't be affected by theme switching. Here's an example:
const root = document.documentElement;
// Default theme - should assign declaratively in markup, not JS
// For a classless default theme, move its custom properties to unqualified :root
// Again, keep it separate from the other :root rule that contains non-theme props
// Remember, the cascade is your friend, not the enemy
root.classList.add('white');
document.querySelector('button').addEventListener('click', function() {
root.classList.toggle('white');
root.classList.toggle('black');
});
:root {
--spacing: 1rem;
color: var(--col);
background-color: var(--bgcol);
}
:root.white {
--bgcol: #FFF;
--col: #000;
}
:root.black {
--bgcol: #000;
--col: #FFF;
}
p {
margin: var(--spacing);
border: thin dashed;
padding: var(--spacing);
}
<button>Switch themes</button>
<p>Hello world!
Using :root selector is identical to using html, except its specifity is higher, thus there is no issues in using this approach.
For example:
:root {
--bg: red;
}
:root.blue {
--bg: blue;
}
// ...
div {
background: var(--bg);
}
Later, you should just change html's class and variables will change.
You can see an example in this fiddle.

Correct way to apply global styles into Shadow DOM

This questions is similar to some other on StackOverflow, but I couldn't find any answer describing applicable to my situation and non-deprecated method (and I'm starting thinking that maybe there is no any good solution for that situation).
Let's say we have some main.css file which includes common styles for buttons, lists, links and so on. So it's just some standard .css file which contains common styles that we want to reuse across the application. And we want to apply the same styles to Web Components with Shadow DOM.
There are a few ways, that I know about, to accomplish that:
Using one of deprecated approaches: ::shadow, >>>, /deep/ selectors. But those selectors are deprecated by now, so I guess it's not good approach to move forward with.
Using css variables. This approach is good for customization purposes, if we need to set a few properties. But it's too complex if we want to migrate 10-20 common styles from main.css file.
Using #import statement or "link" tags inside of Shadow DOM. It will work, but it will duplicate all styles for every component. If we have 10 web components we will end up with 10 duplicates of exactly the same styles. It doesn't sound like good enough solution too. Especially if we have a lot of common styles, sounds like it can be bad solution from performance point of view.
Don't use Shadow DOM at all and use global styles :) But it's not solution for current problem.
I also checked how the same problem resolved in Angular Framework (I checked version 5 of Angular). When I set encapsulation behavior to Native, it's just actually duplicating styles (like in #3 described above), what I think isn't the best way (but maybe the best currently existing way).
So, does anyone know if there is any other way to solve this problem without described above drawbacks? It just sounds like current drawbacks of Shadow DOM bring even more problems than it tries to solve.
There's no real drawback with solution 3:
Whether you apply a CSS style to n elements in a main document, or to 1 element in n Shadow DOM, the style will be duplicated to the whole n elements anyways.
If you import a document n times in n Shadow DOM, il will be actually be loaded only one time and reused through the browser cache.
After that, it will depend on the browser implementation of Shadow DOM and CSS styles, and you should see a performance degradation only the thousands of Shadow DOM.
2019 update for Chrome 73+ and Opera 60+
Now you can directly instanciate a CSSStyleSheet object and assign it to different Shadow DOMs.
This way the HTML won't be duplicated.
var css = new CSSStyleSheet()
css.replaceSync( "#import url( main.css )" )
host.shadowRoot.adoptedStyleSheets = [css]
host2.shadowRoot.adoptedStyleSheets = [css]
You can also apply it to the global document:
document.adoptedStyleSheets = [css]
The other advantage is that an update on the stylesheet will be applied to all Shadow DOMs (and document) that adopted it.
css.replaceSync( '.color { color: red }' )
I managed to do it using javascript modules but I doubt it's the cleanest solution.
You can create a GlobalStyles.js file that will contain the css styling that is common throughout various components. Changing the language mode on your editor to 'html' will provide syntax highlighting for the css.
const GlobalStyles = {
main: `
<style>
body {
overflow: hidden;
margin: 0;
font-family: 'Poppins';
}
h3 {
font-size: 39px;
}
</style>
`,
button: `
<style>
button {
display: block;
cursor: pointer;
outline: none;
font-family: 'Poppins Medium';
line-height: 17px;
padding: 9px 13px;
font-size: 15px;
background-color: #9f28d8;
color: white;
border: 2px solid;
border-radius: 5px;
border-color: #9f28d8;
width: max-content;
}
</style>
`
}
export default GlobalStyles;
Afterwards, you can import it into another js file that contains the code to the shadow dom of your custom element.
import GlobalStyles from './GlobalStyles.js';
const template = document.createElement('template');
template.innerHTML = `
${GlobalStyles.button}
<style>
ul {
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
width: 20em;
list-style-type: none;
}
</style>
<ul></ul>
<button>Click me</button>
`;
export class CustomList extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(document.importNode(template.content, true));
}
}
The drawback with this approach is it only works if you are working purely with js files.

How to customize Ant.design styles

Who knows how to customize Ant.design styles in proper way?
For example, I want to change the default backgroundColor and height of Header section:
import React, { Component } from 'react';
import { Form, Layout } from 'antd';
const { Header, Footer, Sider, Content } = Layout;
export default class Login extends Component {
render () {
return (
<div>
<Layout>
<Header style={{backgroundColor: '#555555', height: '5vh'}}>header</Header>
<Layout>
<Content>main content</Content>
</Layout>
<Footer>footer</Footer>
</Layout>
</div>
)
}
}
Is it ok, or there is a better way to customize styles?
Because I have not found some component's attributes or smth. like this.
Antd has externized most of their styling variable in LESS variables
as you can see in
https://github.com/ant-design/ant-design/blob/master/components/style/themes/default.less
To be able to overwrite those variables you need to use modifyVar function from LESS
you can find more about theming here
So to your specific question, #layout-header-background does the job
This is how i customized the default antd styles in a particular component
In scss or less
.booking_information_table {
:global {
.ant-table-thead > tr > th,
.ant-table-tbody > tr > td {
padding: 0 0 !important;
background-color: unset;
border: none;
overflow-wrap: break-word;
}
}
}
In js file
after the import statement
import styles from './component.module.less'
In return
<Table
dataSource={bookingInformationDataSource}
columns={bookingInformationColumns}
pagination={false}
className={styles.booking_information_table}
/>
My personal approach (I'm working with dva-cli though):
Every time I need to override the CSS, I use a CSS file located in the same folder and import it such as:
your-component.js:
import styles from './your-stylesheet.css';
...
< AntdComponent className= {styles.thestyle} />
your-stylesheet.css:
.thestyle {
background-color: '#555555';
}
In the less file(like a CSS) you can handle customize styles. For
example in your case
.ant-layout-header{
height: 100vh;
background-color:#f50;
}
If you use Ant card
.ant-card-head{color:#j14}
I hope you can understand now
The above mentioned approaches work for simple components like Header but don't always work for complex components like Menu, Tabs, Collapse, Select, and others, due to styles nesting priority. At work we use the approach described by jayanes but we go deeper into nested Ant Design classes. Let me explain it in the following example: when you import Tabs from "antd", you have only 2 tags to override styles for: Tabs and TabPane.
<div className={styles.tabsContainer}>
<Tabs className={styles.tabs}>
<TabPane className={styles.tabPane}>
Tab 1 Title
</TabPane>
</Tabs>
</div>
But this antd component has a very complex structure. You can verify in dev tools: it has .ant-tabs-bar, .ant-tabs-nav-container, .ant-tabs-tab-prev, .ant-tabs-tab-next, .ant-tabs-nav-wrap, .ant-tabs-nav-scroll, .ant-tabs-tab-active, .ant-tabs-ink-bar and others.
The way to go is: in your less file nest the .ant-... classes inside your own parent component's className (in order to avoid overriding all the antd classes in the whole app after code compilation). Write there your own css properties, for example:
.tabsContainer {
.ant-tabs-tab-active {
background: #fff266;
color: #31365c;
&:hover {
color: darken(#31365c, 5%);
}
}
.ant-tabs-ink-bar {
background: #fff266;
}
}
If you still need more detailed explanation, please refer to the video I posted on YouTube on how to customize Ant Design components - tabs.
Override the component style
Because of the special needs of the project, we often meet the need to cover the component style, here is a simple example.
Override the component style
Customizing Antd theme Colors can be a hassle thus, I created a package that allows you to change them easily with post CSS you can even change them to CSS variables and change them in runtime.
For more info https://www.npmjs.com/package/ant-post-css-theme

Angular 4 style overriding addons

while developping an angular 4 app using angular-cli + sass, i have this problem with multiple plugins. so here is the scenario:
I have a main style.scss file that import other styles files ..., so if i want to modify a plugin style, let say a slider component styles, i will create a slider.scss and import it into my main style.scss file, the problem is that the imported component css is injected into the browser after my main css file. so when i want to modify something i need to add !important to the rule.
here is a snapshot of chrome inspect css tool:
element.style {
left: 100%;
}
<style>…</style>
.noUi-marker-horizontal.noUi-marker-large {
height: 15px;
}
<style>…</style>
.noUi-marker-horizontal.noUi-marker {
margin-left: -1px;
width: 2px;
height: 5px;
}
<style>…</style>
.noUi-marker-horizontal.noUi-marker-large {
height: 10px !important;
}
my custom css is the last one.
I want to know if there is a way to load my css style file after the components css file, i can use precedence rule to make it work, but i want to know if there is a more clean way.

Categories

Resources