I have a custom ReactJS component that I want to style in a certain way and provide as a plugin to many different web sites. But when web sites use global styles (Twitter bootstrap or another css framework) it adds and overrides styles of my component. For example:
global.css:
label {
color: red;
font-weight: bold;
}
component.js:
class HelloMessage extends React.Component {
render() {
let style = {
color: "green"
};
return (<label style={style}>Hello</label>);
}
}
result:
Above I didn't use "font-weight: bold" in my component's style but in result my component is using it.
I'd like to be able to encapsulate my custom components's styles in a way that makes them look the same across all the web sites.
The best approach in my view is to define some kind of reset class for your component and put in a set of css resets you can find out there
(e.g. http://meyerweb.com/eric/tools/css/reset/)
The definition in a sass file could look like this:
.your-component-reset {
div, span, object, iframe {
margin: 0;
padding: 0;
border: 0;
font-weight: normal;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
// add some more reset styles
}
To avoid writing a lot when you don't want to use sass just use the universal selector *:
.your-component-reset * {
margin: 0;
padding: 0;
font-weight: normal;
// other reset styles ...
}
Related
A WebComponent may include CSS Custom Properties in its encapsulated styles.
This gives consumers of the component a way to customise that component's styles:
See: Creating style hooks using CSS custom properties | Google Web Fundamentals
Declaring
--fancy-tabs-bg: red
in the main styles means that when the shadow-root styles include
background-color: var(--fancy-tabs-bg, #9E9E9E)
the background-color will be red (or whatever value --fancy-tabs-bg is set to).
But... I note in the same article it explicitly states:
One gotcha with :host is that rules in the parent page have higher
specificity than :host rules defined in the element. That is,
outside styles win. This allows users to override your top-level
styling from the outside.
and again, later:
Outside styles always win over styles defined in shadow DOM. For example, if the user writes the selector fancy-tabs { width: 500px; }, it will trump the component's rule: :host { width: 650px;}
So... instead of declaring a value for --fancy-tabs-bg we could just... set a value for background-color (?)
Really? Let's find out.
Here's a WebComponent (largely copied from the article referenced above) where the first two instances of the component are styled using a CSS Custom Property (ie. --fancy-tabs-bg) and the third instance is styled directly, using the relevant CSS Property (ie. background-color).
class FancyTabs extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({mode: "open"});
}
connectedCallback() {
this.root.innerHTML = `
<style>
:host {
display: block;
width: 100px;
height: 100px;
margin: 6px;
border-radius: 10px;
}
:host([background]) {
background-color: var(--fancy-tabs-bg, #9E9E9E);
}
</style>
`;
}
}
customElements.define('fancy-tabs', FancyTabs);
fancy-tabs {
float: left;
}
fancy-tabs:nth-of-type(1) {
--fancy-tabs-bg: red;
}
fancy-tabs:nth-of-type(2) {
--fancy-tabs-bg: orange;
}
fancy-tabs:nth-of-type(3) {
background-color: green;
}
<fancy-tabs background>...</fancy-tabs>
<fancy-tabs background>...</fancy-tabs>
<fancy-tabs background>...</fancy-tabs>
There's no difference, is there?
So why use CSS Custom Properties at all? Why highlight in the public interface that a particular CSS property is available for user-customisation? Surely all CSS properties are available for user-customisation, aren't they?
What am I missing?
You won't notice any difference when dealing with the host element but you can clearly see the use of CSS variables when having more elements inside:
Example where CSS variables is useful to update the styling of nested elements. I doubt you can find a better way without CSS variables.
class FancyTabs extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: 'closed' });
const css = `
:host {
display: block;
width: 100px;
height: 100px;
margin: 6px;
border-radius: 10px;
}
:host([background]) {
background-color: var(--fancy-tabs-bg, #9E9E9E);
}
div {
padding: var(--p,0px);
border:var(--b,0px) solid;
}`
this.styles = document.createElement('style');
this.styles.innerHTML = css;
}
connectedCallback() {
const div = document.createElement('div');
div.innerHTML = this.innerHTML;
this.shadow.appendChild(this.styles);
this.shadow.appendChild(div);
}
}
customElements.define('fancy-tabs', FancyTabs);
fancy-tabs {
float: left;
}
fancy-tabs:nth-of-type(1) {
--fancy-tabs-bg: red;
--p:20px;
--b:5px;
}
fancy-tabs:nth-of-type(2) {
--fancy-tabs-bg: orange;
--p:10px;
--b:3px;
}
fancy-tabs:nth-of-type(3) {
--fancy-tabs-bg: orange;
padding:20px; /* will get applied to host*/
border-width:5px; /* will do nothing */
}
<fancy-tabs background>text here</fancy-tabs>
<fancy-tabs background>text here</fancy-tabs>
<fancy-tabs background>text here</fancy-tabs>
I need help with creating a logic for my React component. If the divider line appears once on the page it should not be rendered again.
So, if I add the component to the page it styles the text underneath. But if I try to add the component again to the page, the divider line/styling should be ignored. I should only be able to add it once
This is my code:
import React from 'react';
const Divider = () => (
<>
<hr className="divider"/>
</>
);
/* Seperate css file */
hr.divider {
height: 0;
border: 0;
border-top: solid 1px #cdcdcd;
}
hr.divider ~ p.story-text {
font-size: 0.90rem;
font-weight: normal;
font-stretch: normal;
font-style: normal;
letter-spacing: normal;
line-height: 1.75rem;
color:#707174;
#include text-styles(.75rem, 1.75em, "Gordita");
#include breakpoint(tablet) {
#include text-styles(.90rem, 2em, "Gordita");
}
}
hr.divider ~ p.story-text:last-of-type {
border-top: solid 1px red;
}
You need to use the component LifeCycle tools provided by ReactJS. ComponenDidMount() loads the only once when the class is loaded but the render() function is called on each action of the user or the app. Here is a link to ReactJS docs telling how to use ComponentDidMount(): https://reactjs.org/docs/react-component.html#componentdidmount
It may be better to add a condition in the parent component (the one that calls Divider), but given the current snippets:
const Divider = () => (
let dividers = document.getElementsByClassName('divider')
if (dividers.length > 0) {
return null
} else {
return <hr className="divider"/>
}
);
This will not stop your component from rendering. It will only stop more than one hr from rendering.
Im working on a simple button example which i plan to extend. I have added a new button and included some constants as well. so far so good. In case i want to use more button versions like version1, version2, version3 of the same button with some styles changed like the background color. How should i do that? And how should they be exported?
const PrimaryButton = styled.button`
font: inherit;
padding: 0.5em 1em;
border: 1px solid;
background-color: ${buttonBackgroundColor};
color: ${buttonColor};
border-radius: 0.25em;
border-color: ${colors.blueLight};
margin-right: 0.5em;
cursor: pointer;
outline:none;
:hover {
background-color: ${colors.blueLight};
}
`;
Maybe it is possible to extend the button (how?) or does it make more sense to add different components for each button? For my typography i have use "extend". That works. How would that be for the different button versions? Is there a similar way?
export const H1 = styled.h1`
font-size: 30px;
color: red;
`
export const H2 = H1.withComponent('h2').extend`
font-size: 24px;
`
It was working as i added a new component. I imported the PrimaryButton into the new defined component called "Version2".
import PrimaryButton from './primary';
From here i updated the PrimaryButton like this:
const Version2 = PrimaryButton.extend`background-color: red;`
This has the advantage that we have a master component for a button. Now we are able to extend the master with diversity of additional styles. In my case background-color.
With the help of
export default Version2;
we are now able to add this button called "Version2" into our render function like:
<PrimaryButton>ClickMe!</PrimaryButton>
<Version2>ClickMe!</Version2>
and now we get the different buttons. And it´s very modular and clean as well.
One can set the class(es) for the data cell using the colModel for the column, is there a similar way to declare additional classes for the the corresponding TH/label? I can see that there is a programmatic way using setLabel, but I'd want it in the declaration, if possible.
You can use the fact that jqGrid create column headers having ids which are constructed from the grid id and the column name property. For example if the grid has id='list' and you want set some styles for the column with the name 'name' (name: 'name') you can define CSS styles forid='list_name'.
The demo looks like
and uses the following CSS styles
<style type="text/css">
#list_name {
text-align: left;
font-style: italic;
color: red
}
#list_closed {
font-weight: normal;
}
#list_note {
text-align: left
}
#list_amount, #list_tax, #list_total {
text-align: right;
margin-right: 20px
}
</style>
If I have a style defined
.style1
{
width: 140px;
}
can I reference it from a second style?
.style2
{
ref: .style1;
}
Or is there a way via javascript/jQuery?
--- Edit
To clarify the problem, I am trying to apply whatever style is defined for a #x and #c to .x and .c without altering the CSS as the CSS is going to have updates that are out of my control.
I used width but really the style would be something more complex with font, border and other style elements being specified.
Specifying multiple class names does work when the style is being applied to a class so I'll mark existing responses as answers, but I need to take the style being applied to an id and also apply it to a class style ... if that makes any sense.
There's no way to do it with CSS -- it's an oft-requested feature, but not included in the spec yet. You also can't do it directly with JS, but there's sort of a hacky workaround:
$('.style2').addClass ('style1');
you can achieve the same functionality by allowing elements to inherit multiple styles. ex.
<p class="style1 style2">stuff</p>
and then your css would include, for example:
.style1 {width:140px;}
.style2 {height:140px;}
edit: actually robert's answer might better approximate the method you are trying to achieve
.style1, .style2 {width: 140px;}
.style2 {height: 140px;}
<p class="style2">i will have both width and height applied</p>
One way to use the same code for multiple blocks is the following:
.style1, .style2 { width: 140px; }
Another way is use pre -processing tool, like less and sass. Then after you compile the less/sass file, it will result as normal css.
Here is the documentation of less and sass.
// example of LESS
#header {
h1 {
font-size: 26px;
font-weight: bold;
}
p { font-size: 12px;
a { text-decoration: none;
&:hover { border-width: 1px }
}
}
}
/* Compiled CSS */
#header h1 {
font-size: 26px;
font-weight: bold;
}
#header p {
font-size: 12px;
}
#header p a {
text-decoration: none;
}
#header p a:hover {
border-width: 1px;
}
Some options:
Generate your CSS dynamically, either on the fly or as you're authoring your style sheets (I use a Visual Studio macros to implement constants for fonts, numbers, and colors - and to calculate light/dark tints of colors). This topic has been much discussed elsewhere on this site.
If you have a number of styles that are 140px wide and you want to have the flexibility of changing that dimension for all of those styles, you could do this:
div.FixedWidth {width:140px;}
div.Style1 {whatever}
div.Style2 {whatever}
and
<div class="Style1 FixedWidth">...</div>
<div class="Style2 FixedWidth">...</div>
Are you talking about getting all of the computed styles set on a particular Element and applying those to a second Element?
If that's the case, I think you're going to need to iterate through one Element's computed styles using and then apply those to your other Elements' cssText properties to set them as inline styles.
Something like:
el = document.getElementById('someId');
var cStyle = '';
for(var i in el.style){
if(el.style[i].length > 0){ cStyle += i + ':' + el.style[i] + ';';
}
$('.someClass').each(function(){ this.style.cssText = cStyle; });
If you know that you'll only be dealing with a finite set of CSS properties, you could simplify the above as:
el = $('#someId');
var styleProps = {'border-top':true,'width':true,'height':true};
var cStyle = '';
for(var i in styleProps){
cStyle += styleProps[i] + ':' + el.style(styleProps[i]) + ';';
}
$('.someClass').each(function(){ this.style.cssText = cStyle; });
I'll caveat the above code with the fact that I'm not sure whether or not the IEs will return a CSSStyleDeclaration Object for an HTMLElement's style property like Mozilla will (the first example). I also haven't given the above a test, so rely on it as pseudo-code only.
I was trying this same thing and found this webpage (as well as some others). There isn't a DIRECT way to do this. IE:
<html><head><title>Test</title><style>
.a { font-size: 12pt; }
.b { font-size: 24pt; }
.c { b }
</style></head><body>
<span class='c'>This is a test</span></body></html>
Does NOT work. The problem here is you (like me) are trying to do things in a logical fashion. (ie: A-then-B-then-C)
As others have pointed out - this just does not work. Although it SHOULD work and CSS SHOULD have a lot of other features too. It doesn't so you have to do a work around. Some have already posted the jQuery way to get around this but what you want CAN be achieved with a slight modification.
<html><head><title>Test</title><style>
.a { font-size: 12pt; }
.b,.c { font-size: 24pt; }
</style></head><body>
<span class='c'>This is a test</span></body></html>
This achieves the same effect - just in a different way. Instead of trying to assign "a" or "b" to "c" - just assign "c" to "a" or "b". You get the same effect without it affecting the rest of your code.
The next question that should pop into your mind is "Can I do this for multiple CSS items. (Like font-size, font-weight, font-family?) The answer is YES. Just add the ",.c" part onto each of the things you want it to be a part of and all of those "parts" will become a part of ".c".
<html>
<head>
<title>Test</title>
<style>
.a { font-size: 12pt; }
.b,.c { font-size: 24pt; }
.d { font-weight: normal; }
.e,.c { font-weight: bold; }
.f { font-family: times; }
.g,.c { font-family: Arial; }
</style>
</head>
<body>
<span class='c'>This is a test</span>
</body>
</html>