Can you set body id dynamically in React? - html

I am trying to implement dark mode in my app.
The idea is to add this to the root element:
<div id="dark">
And then this in CSS:
#dark {
background-color: #1A1A2E;
}
And then in Css, customize each dom element by using classes. For example, here I will work on cards:
#dark .card-body {
background-color: #16213E !important;;
}
#dark .card-header {
background-color: #0F3460 !important;
}
Now, this works perfectly fine.
But, with Modals, it does not work. I think it's because Modals are not rendered initially so for some reason the dark style does not apply to them.
What worked though is adding id="dark" to each modal:
#dark .modal-header {
background-color: #0F3460 !important;
}
#dark .modal-body {
background-color: #16213E !important;;
}
#dark .modal-footer {
background-color: #16213E !important;;
}
<Modal
// dark doesn't get applied automatically for modals because apparently modals are not rendered in the beginning
id="dark"
isOpen={this.state.isModalOpen}
toggle={this.toggleModal}
>
<div className="modal-header">
But, it'll be a pain to apply this to every single modal.
One solution mentioned here:
Modal should be the descendant of a tag which has id="dark". It is
loaded by the script right below the script tag and you are trying to
put 'dark' id on some div tag and the modal doesn't lie inside it,
thus the CSS selector not targeting it.
So, you need to put id="dark" on the body tag.
This solves the modals issue.
But, the problem is in my original implementation of dark mode, I am controlling that id in the root component like this:
// Root component
<div id={this.state.should_enable_dark_mode ? "dark" : "default"}>
And should_enable_dark_mode is managed like this:
manageDarkMode() {
window.addEventListener("storage", () => {
console.log("change to local storage!");
let should_enable_dark_mode = localStorage.darkMode == "true";
this.setState({
should_enable_dark_mode,
});
});
}
So the problem with the solution mentioned above is that I couldn't find a way to control the body tag from the react app. And I am not sure if it's a good thing to do.
What do you think I should do?

I see in the comments to your original question that you decided to just modify the body element in the browser DOM, which will probably work fine since the body element is not controlled by React and will likely not be changed by any other code.
I would however like to suggest a few improvements that makes it at bit less dirty:
use a data attribute like data-display-mode="dark" as a target for your CSS selectors instead of the ID. IDs are supposed to be stable and other tools and libraries (e.g. UI test tools) might rely on this.
use the Modal.container property to attach your Modals to the App element (the React-controlled global parent div defined in your React code, which you can control, not the app-root-div in index.html). Then set your data-display-mode attribute here by React-means. This way you will not bypass the virtual DOM.
use CSS custom properties for defining your colors, and then define all dark mode modifications in one place. Don't spread your dark-mode-styling code across multiple class selectors - you will have a hard time maintaining this.

Related

host + ng-deep + body css not applied

I'm trying to make a background color for a specific component being display in the whole component page.
It's working fine with
\ ::ng-deep body
background-color: red
But the things is when i do it like that, the body css is bleeding to the other component page, which become red too.
So what i really want to do, is making it local with host.
I tried to use
\:host ::ng-deep body
But it wasn't working too, the body background did not change color until i add a specific body tag to my html file component.
But i don't want to add a body tag because when i do this, the body size is limited to the element in the page.
I also try to use ViewEncapsulation, but it messed up with all my css.
Any help would be appreciate.
Your first issue (As you found out) with ng-deep is that it bleeds into other pages. And because CSS is lazy loaded inside Angular, everything will be fine until you go to that page, and then head to another page and suddenly everything will be red.
Your second issue is that the :host pseudo selector isn't saying "For this page only" it's saying "For everything inside this component".
So as an example :
If I have a component called MyComponent, and I have css like :
:host ng-deep div {
background-color :red;
}
And I have a template like so :
<body>
<app-mycomponent>
<div></div>
</app-mycomponent>
<app-secondcomponent>
<div></div>
</app-secondcomponent>
</body>
Only the div inside app-mycomponent would be red. The div inside app-secondcomponent would not be read. Again, :host allows you to ng-deep only within that component.
So why would you need this? Generally it's because you may use a library that you want to style, so you can place it inside a wrapper component and use ng-deep commands freely with the :host prefix, so only the library component inside that wrapper is styled and the rest of your application is unaffected.
So what's the solution? Well the other issue you have is that the <body> tag is actually outside the scope of your angular app. Typically when I've had to edit the body/html tags as a whole, I've just used plain old javascript.
So for example :
export class AppComponent implements OnInit, OnDestroy {
ngOnDestroy(): void {
document.body.style.backgroundColor = 'transparent';
}
ngOnInit(): void {
document.body.style.backgroundColor = 'red';
}
}
It's not the nicest thing in the world, but it's also not terrible. I mostly have to do this when creating modal components that want to stop the body scrolling etc.
For more reading on NG-Deep bleeding : https://tutorialsforangular.com/2020/04/13/the-dangers-of-ng-deep-bleeding/
And how :host works : https://tutorialsforangular.com/2019/12/24/using-the-css-pseudo-element-host-in-angular/

First dynamically added component not getting styling from a class

I have a big list of dynamically added components and all of them are getting styling from the css class except the first one. It's specifically a darkmode or litemode class that gets added depending on the if this.state.dark === true or not
here's the function that renders them
renderComponent(info) {
return <Info isDark={this.isDark()} isHidden={this.state.hide === true} user={info} key={info} />
}
and this is what calls that function
{info.map(this.renderComponent)}
css class that's not rendering on first component
.darkmode + .other-class {
background-color: rgb(131, 21, 21);
}
I've tried conditionally rendering the page into a separate version with just darkmode and using the classes directly everywhere(ie there's no way they don't have the class).
In inspect element it says they have the class and even styling from a different area in the css is being applied. but the background stays transparent on just the first element.
I've also tried adding the class in the component itself and it's always the exact same result.
https://i.imgur.com/vLa8Tn9.png picture of the element not loading the css
https://i.imgur.com/cJxT5bU.png picture of element that is loading the css
I think this is a problem with your CSS selector.
The plus (+) sign select and style every element that is placed inmediately after the first element in your CSS selector.
In W3School you can see this behaviour
I think what you are trying to do is this:
.darkmode.Offline {
background-color: rgb(131, 21, 21);
}

Visual Composer: nth-child not working with css classes

I am working on a website for a client, and she has Visual Composer installed. For a post grid, I need to assign a different color to each post title. My approach was to find the grid-item container and append :nth-child to it, then direct it to the custom css class I really want to apply the different color to.
Example code, based on the actual code:
.vc_grid-item:first-child > ... > vc_gitem-zone-a > ... > .custom-post-title {
background-color: red;
}
.vc_grid-item:nth-child(2) > ... > vc_gitem-zone-a > ... > .custom-post-title {
background-color: green;
}
.vc_grid-item:nth-child(3) > ... > vc_gitem-zone-a > ... > .custom-post-title {
background-color: blue;
}
Strangely enough, this technique worked fine for the hover-text effect over the post's featured image.
I tried nth-of-type, but had little luck with it. It would work, but only parsed the first or second of type, applying the same color to all three divs.
I have tried every path permutation I can think of, but not a single one works.
Trying to track down a path through the endless divs that Visual Composer generates is practically impossible. Using the code inspector (Google Chrome), I found dynamically generated classes, classes injected as inline styles, and classes that were in the rendered HTML, but nowhere to be seen in the inspector. After several hours of carefully mapping out different "class paths" to make this work, I gave up out of sheer frustration.
Interestingly enough, the Visual Composer documentation is clear that, by adding custom css classes through its UI, custom styling is easy and straightforward. My experience is that this is true--if you want to apply the same color to all your divs in the post grid. Try customizing each grid-item independently, though, and it's a whole different ball game...one that may be impossible to win.
Any ideas as to how I might get this to work without resorting to some kind of hacky JavaScript black magic?
If you want to target a series of elements with the class .vc_grid-item, what you need is :nth-of-class... and it doesn't exist.
If you state the type of element, then you can use :nth-of-type:
div:nth-of-type(3).vc_grid-item > ... > .custom-post-title {background-color: blue;}
N.B. This sort of thing will be much easier when CSS4 :nth-match arrives.
Then, in this kind of situation, you will be able to use:
:nth-match(3 of '.vc_grid-item')
Further Reading: http://www.w3.org/TR/selectors4/#selected-child-index
child point to tbody in table
you must use tbody in selector for pointing child to tr
.vc_grid-item tbody :nth-child(1){
background-color: green;
}
.vc_grid-item tbody :nth-child(2){
background-color: blue;
}

iPhone/iPad background image on wrong element

I have an issue where, ocassionally, when I set a background image on an HTML element it displays a completely random image that is also set as a background image elsewhere on the page.
For example, I have a list item that has a background image "myimage-abc.jpg".
I also have a div with a background image of "myimage-123.jpg". Everything is as expected for most people however for some Apple users (of which my Managing Director is one) the image "myimage-123.jpg" shows up on the list item as well as the div.
Has anyone else had this issue before? Any ideas how to get around it?
Thanks
Use inspect element on the element with incorrect background image and see which CSS selectors are overriding the background image that you want to have.
Then report back with the CSS selectors responsible for styling the elements in here. Keep in mind that CSS selectors are very particular about the way in which you use them.
Until then here's something that could be causing your problem, without my knowing your current CSS state.
From an answer on another question:
I've dealt with this before and it's always a strange issue. So here are some thoughts and examples of CSS behavior.
In CSS we have a hierarchy decided both on how you select an element and on its position within your stylesheet. Take for example the following CSS selectors:
body .test-parent .test-child {
color: red;
}
body .test-parent .test-child {
color: blue;
}
The result in this case would return color: blue; as the final style as it is the last read declaration for that elements color value.
However if we declare the following:
body .test-parent-two .test-child-two {
color: red;
}
body .test-child-two {
color: blue;
}
Then the final value is color: red;. This caught me off guard and it took me a while to notice the pattern and fix.
The problem here lies in the selectors. A more in-depth selector (longer / includes more in-between children) will override any others as can be seen by this JSFiddle.
Hope that also helps!

CSS Code To Remove Angular Material v5 Modal Backdrop

I want to remove the backdrop on the modal, i know there is a hasBackdrop property when opening the modal but i only want to hide the backdrop based on some condition which will take place on the modal. So i was thinking I could do so with css but after inspecting element on the modal, I couldnt find anything relating to the backdrop's css.
I quite don't understand the question.
If what you need is maybe remove the shadow box of the dialog, just find the component which contains the dialog you need to work on, find it's style file and add this:
/deep/.mat-dialog-container {
box-shadow: none;
}
More info of the usage of deep can be found on angular docs and more example of their usage here (stackoverflow's question) and on angular's blog website.
If what you need here is remove the backdrop then beforehand create a class like
.no-backdrop {
background: none;
}
and add it to the function, which is used to create a dialog:
this.dialog.open(LoaderComponent, {
backdropClass: 'no-backdrop',
});
You can also just add false as value to the field hasBackdrop like:
this.dialog.open(LoaderComponent, {
hasBackdrop: false
});
as per default, the value is true.
More information can be found on angular material v5's webpage.
Hope it helps someone.
.mat-dialog-container has box-shadow, you can remove the box-shadow. For example you can add box-shadow: none; as an inline role or box-shadow: none !important; . Both will remove the box-shadow.
Try this:
In your .css/.scss file overwrite class
/deep/.cdk-overlay-dark-backdrop {
background:none!important;
}