I'd like to ask for a little nudge to get my brain out of the box I got it into.
Context
Angular 4 using Angular CLI and AoT.
All methods mentioned in https://angular.io/docs/ts/latest/guide/component-styles.html describe ways to set complex CSS of a component while it is being written by a developer.
After a component is created, Angular allows to adjust individual styles and even assign various CSS class names to tags in the component as you please, all that using [ngClass], <div [class.something]="condition">, various #HostBinding decorators and some other methods.
However, none of the above can change the CSS declaration the component is using. The methods above can either (a) use what is already available in the stylesheet defined by the developer or (b) set individual CSS properties to individual HTML tags in the component's template.
Question
How would I update the CSS for the whole component on runtime so that all elements in that component respond to the new CSS?
Say I introduce a new style for a div.someClass and I want all matching elements div.someClass to reflect the new style.
Plunker
A showcase of my attempts is here: https://plnkr.co/edit/N2C40cSb7hd1AyOxWWdT
The button should be red, based on the value of MyChildComponent.styles
I think I understand why it doesn't work the way I would expect: shortly said, styles are built in the component during compilation, not runtime, including those found inside <style /> tags in the template.
But knowing why it doesn't work doesn't help me to make it work.
Any help highly appreciated.
Solution 1
Inserting a new css class is not possible ( as far as i know ) but you can insert css properties to your component dynamically.
I modified your dynamicStyles() to this
get dynamicStyles(): any{
return {'background': 'red' };
}
that returns an object instead of string because you will pass this object to ngStyle of your button.
In your template, I change the button like this
<button type="button"
[ngStyle]="styles">
Button
</button>
Here's a plunkr
Solution 2
This is something that I would not recommend but in your case it might be useful. You can add this
encapsulation: ViewEncapsulation.None
and the import
import {ViewEncapsulation} from '#angular/core'
to your #Component.You can leak your component's css so that you can use it on your child component. Then in your child component, add a [ngClass] in your button so that you can just pass a variable via #Input() if it should be red.
<button type="button"
[ngClass]="{'redButton': isButtonRed}"
>Button</button>
And in your style.css
.redButton{
background:red;
}
And in your main component.
<div>
<h2>Hello name</h2>
<my-child [isButtonRed]="true"></my-child>
</div>
Here's another plunkr
Hope this helps.
Related
i am implementing a multilingual react application and i need a way to apply some css code to most of the components based on the selected language. something similar to direction-rtl and direction-ltr which applies to all the components when applied to the body component. i want to set a class like lang-en to all the components and then in the css file of the components set some css codes for the times that they have the lang-en class
for instance i want to set the background of all the .rec to be red when lang-en is applied
.rec.lang-en{
background-color: red;
}
You can create component that is parent of all your class and on that component check language and set style for your language like below
ReactDOM.render(
<DetectLanguageLayout>
<ChildClass/>
</DetectLanguageLayout>,
document.getElementById('root')
);
And DetectLanguageLayout is like below
<div className={`your-style ${lang=="en"?"bg-white":"bg-red"}`}>
<div>{props.children}</div>
</div>
I am facing an issue which is mind-numbing in the world of CSS.
TailwindCSS 3 classes just doesn't override previous classes.
For example, there is this component, I created:
import * as React from "react";
const TextBox = ({ addClassName, children }) => {
const className = `text-xl leading-7.5 font-lato font-normal ${addClassName}`;
return <div className={className}>{children}</div>;
};
export default TextBox;
Then I go ahead and use this component above at another place, like this:
<TextBox addClassName="text-4xl">My New Text</TextBox>
Now when I inspect it in the browser, it shows both of the font-size:
Screenshot from the browser inspect
class="text-xl leading-7.5 font-lato font-normal text-4xl"
As you can see both of the classes are there, both referring to font-size, and the larger one is after the smaller one.
And still ONLY the small ( the original ) font-size will be the dominant.
( as a side note, I did try to put the addClassName variable in the front as well, no help )
Why is this?
I appreciate any help getting with this.
Thank you
I found the answer from dev.to.
The reasons your code didn't work are:
It turns out that the space-separated CSS class list that the class HTML attribute accepts is not treated as a list when calculating CSS rules precedence by the browser. The class attribute actually contains the set of classes the element has, so the order doesn't matter.
As the order that the classes appear in the class attribute doesn't matter, the rule that comes later in the CSS stylesheets wins.
Moreover, it wasn't warranted that the 'text-4xl' was defined after the 'text-xl' in the CSS stylesheet.
So to solve this problem, I recommended using tailwind-merge to override previous classes.
Tailwind-merge is a utility function to efficiently merge Tailwind CSS classes in JS without style conflicts.
One of its features was: Last conflicting class wins
twMerge('p-5 p-2 p-4') // → 'p-4'
Quoting from redit
In CSS if you have two selectors with equal specificity the one that comes last in the CSS structure takes precedence. The order in the class attribute has no effect.
Suggested solution would be to write your own class after tailwindcss import statement, or edit it using inline style.
My personal tip: Don't use two classes that target the same css property, text-lg and text-4xg both target font-size, you need a way (suggest clsx lib) to put only one class name and not the other
import clsx from 'clsx';
let condition = false;
function Component(){
return (
<div>
<p className={clsx({
"text-lg": condition,
"text-4xl": !condition,
})}>
...
</p>
</div>
);
}
I have had the same problem, and didn't want to add yet another dependency and increase my app's bundle size to solve something that doesn't have to be this hard. So I looked into the tailwind docs and found this:
Use the components layer for any more complicated classes you want to
add to your project that you’d still like to be able to override with
utility classes.
#tailwind base;
#tailwind components;
#tailwind utilities;
#layer components {
.card {
background-color: theme('colors.white');
border-radius: theme('borderRadius.lg');
padding: theme('spacing.6');
box-shadow: theme('boxShadow.xl');
}
/* ... */
}
By defining component classes in the components layer, you can still
use utility classes to override them when necessary:
<!-- Will look like a card, but with square corners -->
<div class="card rounded-none">
<!-- ... -->
</div>
Though this means you will have to write a component class every time you want to override an element with predefined classes.
https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes
I would suggest you to try clsx or clsssnames for better usage with tailwind classes instead of string interpolation
I found a Solution guys.
Setup props with default CSS values at the original component, and then at the time of the usage of this aforementioned component, if we need different style, we just gave that in the props.
I have a simple front-end React app created using npx create-react-app. The app is using react-router-dom routes. When I directly change the URI in the browser from say, localhost:3000/ to localhost:3000/search it will navigate to the <Route>but with no CSS rendered; just HTML from the component.
How can I make sure CSS is rendered in the new route when directly navigating in the browser? My future goal is to be able to copy and paste a route in a new tab and navigate to the correct page and display results from an API.
Css style sheets will need to be imported either at the root level or within the file itself.
style sheets need to be imported when used and then the corresponding classname will need to be used within the component or tag.
Another useful way to set react css without style sheets is by using in line styles
e.g
<div style ={{float: "right", textAlign : "center"}}> </div>
EDIT
A really easy way to get styles going within a react project is install bootstrap.
then buttons and stuff can be assigned classNames such as
<div className = "jumbotron"></>
this will leave a grey box around the items.
<div className = "btn btn-primary"></>
this will give you a blue styled button.
Any more information or help within your application let me know and provide some code snippets.
You can use styled-components. styled-components are widely used in ReactJs and React Native and it's a perfect choice.
styled-component : https://www.npmjs.com/package/styled-components
I realized that react apps created using npx create-react-app allow you to import a css module for components.
Given the component, Button.jsx, you can simply create a css module with the convention, [module-name].module.css. For the case of Button.jsx, create a file named Button.module.css, import "styles" from the module. Styles will be an object containing all the CSS styles.
I if I had a folder named "components" with all my components, I could make a folder within "components", say called "compStyles", and create all the [module-name].module.css files in there.
Button.module.css:
/* class names must be camelCased */
.myButton {
margin: 0 auto;
}
span {
fontSize: 20px;
}
If I had the above mentioned file structure, I could import and use like so:
import React from 'react';
import styles from './styles/Button.module.css';
const Button = () => {
return (
<div className={styles.myButton}>
<button><span>Some Button</span></button>
</div>
)
}
export default Button;
Styles for the span will be automatically applied, and any other class will be referenced by styles.className. Create one file for every component, and each component's CSS will take care of itself and not break like it would if it was in the public folder.
When I need a component to change slightly for a new use, I've looked at transclusion and multi-slot transclusion vs adding HTML around the component but there are still situations where a component's internal styling needs to be changed.
You can pass a style in as an input, and then set it in the template with [ngStyle].
So for a simple example i'll show how to do this with a background color.
customComponent.html
<div [ngStyle]="{'background-color': data?.backgroundColor }">
<p> the background color will be set from an input </p>
</div>
customComponent.ts
#Input('data')
data: {
backgroundColor: string;
};
parent.html
<customComponent [data]="{backgroundColor: 'grey'}"></customComponent>
Components should be self contained and programmed so they don't require refactoring whenever a new use is needed.
One solution is to add a class to the parent using ng-class, and then use regular css rules to style the child: one set of rules that requires the class to be on the parent div, and another set that doesn’t require the class to be on the parent div.
Example css:
.my_class {Normal styling}
.my_parent_div_class .my_class {Special styling goes here}
I'm familiar with assigning CSS classes to GWT elements to control their formatting, but what if I want to change an attribute in one of those CSS classes?
I've got a styled list of data. CSS classes are used to indicate the various data types (important, routine, trivial). I wish to allow the user to hide trivial entries. I'd like to modify the span.trivial CSS class to set display:none
I'm aware I could loop through the entries, see if an entry is trivial and add a noShow class (which itself has display:none) - but then I'm doing the looping, I'd rather let the browser do the work.
Is this possible in GWT?
Ian
I assume we have a structure similar to the following one
<div>
<span class="routine">A</span>
<span class="trivial">B</span>
<span class="trivial">C</span>
<div>
This is how I would solve the problem:
.hideTrivial span.trivial {
display: none;
}
<div class="hideTrivial">
<span class="routine">A</span>
<span class="trivial">B</span>
<span class="trivial">C</span>
<div>
The ".hideTrivial span.trivial" selector applies only to "trivial" spans, if they occur within another element that has the class "hideTrivial". (Note: The span doesn't have to be a direct child of the "hideTrivial" div - it's ok, if you have a deeper element hierarchy.)
So to turn on/off hiding, you simply add/remove the "hideTrivial" class from the outer div.
(This technique can be used with and without GWT.)
AFAIK, javascript can not change the CSS file and have it reapplied. The same goes for GWT (since it compiles down to JS). So, you can not change a CSS rule and have all elements in your DOM reflect the change.
However, you can get a style of a DOM element and change that style. But that is for a particular element. In your case you'd still need to write code to traverses a set of element and make the change.
My suggestion would be to look at gwtQuery (a port, not a wrapper, of jQuery to GWT). It's super-efficient and super-compact. Here is a one-liner to do what you need:
$("span.trivial").hide()
Fot those who need to modify global CSS property values: you can choose StyleInjector for that purpose.
http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/dom/client/StyleInjector.html