How to protect React component from global styles? - css

I have a react component that will be embedded into an old website. The problem is that this website has some global styles with tag selectors, e.g:
p {
font-size: 14px;
}
Removing these styles from the website is not an option.
So is there any way I can prevent these styles from reaching my component apart from just overriding them?

Create a particular css file for this component and again assign the style for p in this page particularly. It will replace the global one.
OR
You can use inline css because it has more preference than the external css.

You could wrap your .p inside your own class.
Example in plain HTML:
<div class = "you-wrapper">
...
...
...
<p></p>
...
</div>
And in you react code, add your own css:
.you-wrapper p { font-size: 15px; color:red;}
Edited:
/* your css */
.your-wrapper * { all: unset; }
.you-wrapper p { font-size: 15px; color:red;}

Related

Working with nested selectors & vuejs css modules

Is it possible to work with nested css selectors when using vuejs css modules?
For example, I want to scope this css (so that id does not affect child components):
.list {
...
.item {
...
}
}
In the documentation I could see only not-nested examples, but is it at all convenient, since I'll need then name them like .list-item which resembles BEM. But if I use BEM there is no point in using css modules, is there?
Yes, it's possible to work with nested css selectors so they will not affect child components; use css modules.
You need to use a preprocessor to enable nesting, either LESS or SASS.
If using Single File Components your component would look something like this
<template>
<ul :class="$style.list">
<li :class="$style.item"></li>
</ul>
</template>
<!-- Or lang="less" -->
<style module lang="scss">
.list {
...
.item {
...
}
}
</style>
Yes, nesting css selectors is called using scss. You will have to setup scss.
Example make your style tag in the vue component:
<style scoped lang="scss">
The scoped attribute tells it to apply only to this component.
In regards to bem you can do stuff like this in scss:
.list {
//styles-a
&-item {
//styles-b
}
}
which will convert to this in css:
.list {
//styles-a
}
.list-item {
//styles-b
}
If you want, for example, override CSS class of some UI library in Vue you can use :global keyword. Let's say you have a n-dropdown component from Naive UI library. And you want to customize it with overriding its native very deeeeeply nested n-dropdown-option-body__prefix--show-icon CSS class only in current component using CSS modules. Here is how you can do it:
<template>
<n-dropdown :class="$style.menu">
</n-dropdown>
</template>
<style module>
.menu:global.n-dropdown-menu .n-dropdown-option .n-dropdown-option-body .n-dropdown-option-body__prefix.n-dropdown-option-body__prefix--show-icon {
margin-left: 33px;
margin-right: 19px;
}
</style>
In the end you will get selector which looks something like this
.MobileNavMenu_menu_NhSka.n-dropdown-menu .n-dropdown-option .n-dropdown-option-body .n-dropdown-option-body__prefix.n-dropdown-option-body__prefix--show-icon {
margin-left: 33px;
margin-right: 19px;
}
So all classes after :global keyword will be untouched by module manipulations.
If .n-dropdown-menu should be a child of menu then :global should have a whitespace from both sides:
.menu :global .n-dropdown-menu
Vue will remind you about it with horrible crash

CSS reset all styles in a div but allow lower styles to over write it

So have my main style sheet that sets all the styles for my site. But I have a div that opens as menu. I need it to have it's own style and I can't have it or it's decedents inherent any styles from the main style sheet. But after I reset the style I'm then styling the div like it's a whole new element. I found the all: initial; rest the elements. and #we_gallery_edit_window > * sort of works. But when I try to declare the new styles some of the new styles won't take because of precedence. here is my code so far:
h1
{
color: #000000;
background-color: #FFFFFF;
}
#my_div > * /*Clear all previous CSS for #mydiv only */
{
all: initial;
}
.my_div_child h1
{
color: #F0F0F0;
}
<h1>Hello</h1> //Should be black with background
<div id='my_div'>
<h1 class='my_div_child'>Good bye</h1> //Should be grey without background
</div>
<h1>Hello</h1> //Should be black with background
I need a selector that will override everything above it but has no precedence over anything below it. So remove the style set by h1 in the main div, then reset h1 of .my_div_child. it's not just the h1 element I'm having trouble with but that's the easiest example I can think of.
Okay, after seeing the updated post, I think I get the idea.
I think you may be simply using the wrong selectors. You may review CSS selectors if you're unsure.
For one thing, if you want to style an h1 with the class of my_div_child, the rule would be h1.my_div_child, or simply .my_div_child, if you don't have other, non-h1 elements with that class name. Using .my_div_child h1 will select h1 tags inside a parent container with the class of my_div_child, which is not what your HTML shows.
If you want to reset the styles of children of #my_div, you can use the all: initial selector with the wildcard like you did, but instead of using the direct child selector (>), just nest the wildcard regularly:
#my_div * {
all: initial;
}
If you use the direct child selector, only the first level of children in #my_div will be reset, but grandchildren of #my_div won't be, which is probably not what you want.
Those things cleared up, simply use the above statement to reset your styles and then start styling the contents of #my_div as needed, and it should work because various tags (e.g., h1) will be more specific than the wildcard. See code snippet below.
That said, you may find it easier to simply override certain styles that aren't what you want by using specificity than to reset everything in #my_div and start over. Odds are there are some styles the menu will share with the site overall. For example:
h1 {
font-style: italic;
}
#my_div h1 {
font-style: normal;
}
If these approaches don't work, and you're still having trouble with your styles not working, you'd have to post some more specific code so we can work out what the problem is.
Example reset:
html {
background-color: coral;
font-style: italic;
font-family: sans-serif;
}
h1 {
background-color: white;
}
#my_div * {
all: initial;
}
#my_div .my_div_child {
color: darkgray;
font-size: 4em;
/* note that font-style and font-family don't need rules b/c they have been reset by all: initial above */
}
<h1>Hello</h1> <!-- Should be black with background -->
<div id="my_div">
<h1 class="my_div_child">Good bye</h1> <!-- Should be grey without background -->
</div>
<h1>Hello</h1> <!-- Should be black with background -->

Including styles within another style

So I have been pondering about this and I don't think this exists. I also understand that my logic my be counter with what stylesheets are trying to accommodate, but let's give it a go:
Take the following example:
// Example "template style"
.blue_bold {
color: blue;
font-weight: bold;
/* other styles can go here */
}
So let's say I want to add that to my footer I would in my HTML go:
<div class="blue_bold" id="footer">
// Content goes here
</div>
This is perfect, but what if I want to add that element to a number of my elements. Say I want to add it to my navigation as well, I would then have to add that class to each element:
<div class="blue_bold" id="navigation">
// Content
</div>
....
<div class="blue_bold" id="footer">
// Content
</div>
My question is, as appose to declaring it via a class or style, is there no way to "attach" the style to another style within my stylesheet? (as example:)
#navigation, #footer {
attach_style(".blue_bold");
}
That way I can minimize my code by creating "base styles" and then attach those styles to individual styles within my stylesheet? This is again just a question, not something I wish to impliment, but I figure that given the above it would be a "nice to have" for people working with say brand guideline documents and want to attach specific styles to individual styles without going to the html to do it.
Any ideas? Does this exists?
You can't do it with pure CSS. You'll need to use LESS, or SASS/SCSS to generate your CSS.
Syntax examples here :
LESS
.blue_bold {
color: blue;
font-weight: bold;
}
#navigation,
#footer {
.blue_bold;
}
SCSS
.blue_bold {
color: blue;
font-weight: bold;
}
#navigation,
#footer {
#extend .blue_bold;
}
you will need to have a look on sass or less they are your best options.
sass here
less here
You can use sass or less but a more basic slight workaround is just to list the elements in your css like so:
#navigation,
#footer,
.some-other-element,
.another-element
{
// css styles go here that you want to apply to each element listed above
}
Can't see any benefits. What you're asking for is not a standard CSS.
You can define this for all elements with class blue_bold
.blue_bold {
color: blue;
font-weight: bold;
/* other styles can go here */
}
For this block
<div class="blue_bold" id="navigation"></div>
You can simply add another declaration like this:
#navigation, #footer {
background: black;
color: red;
}
Everything from .blue_bold will be used unless overwritten. What's wrong about it?

How do i prevent my CSS affecting external plugins?

As an example I got a css class which applies to all labels within my website.
label
{
font-size: 18px;
}
Now after i install a external JS plugin i find that the plugin itself is affected by my base css.
<div>
<div class="plugin" />
<label>Xyz</label>
//Dynamic html inserted by plugin
</div>
The plugin has its own stylesheet so how can i prevent my base css style touching any elements within the plugin div?
EDIT
I must add that label was a very simple example. The actual layout is more complex with global styles touching various elements.
Don't make your css too general, try to be as specific as possible when you want to style only some of your elements. If you can't select your elements without affecting the plugin's elements add a class to them.
label{ /* too general, don't use this */
/* ... */
}
body > div > form > label{ /* more specific, but maybe still affecting your plugin */
/* ... */
}
label.noplugin{ /* use a class on non-plugin elements */
/* ... */
}
div:not(.plugin) > label{ /* affecting only children of div which are NOT
tagged with the plugin class */
/* ... */
}
So in your case a better way to style your label would be
<div>
<div class="plugin">
<label>Xyz</label>
//Dynamic html inserted by plugin
</div>
</div>
CSS:
*:not(.plugin) > label
{
font-size: 18px;
}
Please note that :not is unfortunately not supported by IE ≤8.
You need to do two things.
i) Give your parent container ID
ii) And style child label of container.
Here is fiddle workout.

Can you scope CSS files so that they only apply to the descendants of a given element?

Given a css file, is there a way to scope the entire file so that it only applies to elements within a given element:
e.g. given:
<div id="container">
<span class="some_element"/>
<!-- etc -->
</div>
Is there a way to scope an entire css file to apply to all elements within "container" without prepending #container to every single css clause?
I’m afraid not. Some CSS pre-processors allow you to write code that achieves the same thing though.
E.g. LESS implements nested rules:
/* This LESS code... */
#header {
h1 {
font-size: 26px;
font-weight: bold;
}
p { font-size: 12px;
a { text-decoration: none;
&:hover { border-width: 1px }
}
}
}
/* ...produces this 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;
}
And Andy mentioned SASS, which does the same thing.
You can use the scoped attribute on a <style> element, although there's little to no browser support for it. In your example:
<div id="container">
<style scoped>.some_element{}</style>
<span class="some_element"></span>
</div>
Here's a jQuery Polyfill: http://thingsinjars.com/post/360/scoped-style/
There are 2 ways you could approach this:
1) In HTML5, (not widely supported yet) there is to be a scoped attribute you can put on a <style> tag. Here is a brief article on the subject.
2) You could use a dynamic stylesheet language (like LESS or SASS) that allow you to nest related CSS rules together.
Not with CSS alone, but you can use Sass, which compiled into CSS.
You could use BEM naming notation -- http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/ ("block, element, modifier").
Your example would become:
<div id="container">
<span class="container__some_element"/>
<!-- etc -->
</div>
Yes, if you don't use an abbreviation, you're writing the same number of characters in your CSS... but your styles will have less specificity -- which can be beneficial.
Hopefully browser support for <style scoped> will get better in the coming years!
You could load the page in with php and throw whatever tag you want in dynamically, or do the same with javascript/jQuery... although that's fairly clumsy. There's no built in method to do this as CSS is always applied to the entire page.

Resources