Using css variable with styled-compoents - css

I know you can wrap your react app with <ThemeProvider /> and you can set a variable for the theme and access it like so:
const Text styled`
color: ${((props) => props.theme.red)};
`
But it's it CSS itself have the variable feature?
You can just do
:root {
--red: tomato;
}
.text {
color: var(--red);
}
is it ok to mix them? or stick to either styled-components or CSS?

Yes it is OK. Those 2 technologies have nothing to do with each other and are not conflicting.
As long as your components can inherit the CSS variables (AKA custom properties) they will work.
Just make sure they are really inherit.
Clearly defining variables on the root element selector (html) will make them available everywhere, but sometimes you don't want global variables, but more local, per page/area/component, so you need to structure you code taking that into account.
The real power of CSS variables is in their inheritance (unlike SCSS variables which are injected/replaces during the build-process).
The power of styled-components is isolation & the ability to share code with javascript. This does hinder their ability to inherit CSS variables defined at parents-level.
You need not bother yourself with this question at all, and simply ignore the fact you are using styled-components. All that matters is the HTML structure, which how inheritance works.
I Googled things for you:
https://medium.com/fbdevclagos/how-to-leverage-styled-components-and-css-variables-to-build-truly-reusable-components-in-react-4bbf50467666
https://betterprogramming.pub/7-ways-to-inherit-styles-using-styled-components-69debaad97e3
https://dev.to/arnonate/using-css-variables-to-tame-styled-component-props-2f9o

Related

Benefits of using CSS modules with React/Vue

I would like to understand the benefits of using CSS Modules with React/Vue.
Currently in my company developers use the following in development:
return (
<div className={styles.User}>
<div className={styles.name}>...</div>
</div>
)
While using a CSS module file, something like:
.User {
background-color: var(--bg-color, red);
.name { color: white; }
}
What should an HTML output such as:
<div class="_User_xyz_1">
<div class="_name_abc_1">...</div>
</div>
Which is a bit confusing for me, as this "encodes" all the class names and creates a great deal of difficulty if I need to do a parent-level modification. Eg.:
<div class="SomeParent">
<User name="David" />
</div>
So:
.SomeParent {
> .User {
--bg-color: blue; // Will not words, because .User is not .User, in fact.
}
}
In personal projects, I prefer to name the primary element of the template by defining it as a "major class", the main. Eg.:
return (
<div className="User">
<div className="name">...</div>
</div>
)
And a regular CSS/SCSS:
.User {
background-color: var(--bg-color, red);
> .name { color: white; }
}
So a parent element's code can affect a child element under expected and controlled conditions.
My question here is: what are the benefits of using the model that my company uses that I am not able to see? Am I missing something using a more "moderate/primitive" model?
Another possibility is: can I modify the style of child elements through the parent element, even with the name of the classes being encoded this way?
CSS modules generate custom classnames for each style and therefore prevent the problem you are facing in your solution. Because each css module style has its own classname you cannot accidentially change a child components style.
SCSS module styles are applied by very unique classes thanks to the hash, and therefore have no real risk of unintended style collisions. This allows you to use short, meaningful class names without having to think of any global styles you might be colliding with. You can confidently style without fear of breaking things elsewhere in your application.
You could, in theory, add generic class names which are not applied via your scss modules to give your parent component a class name with which to work.
Personally I think the React components should be as modular and generic as possible. I think the way to go is such that types are exported from one component. Styles should be inline or at the bottom at a styles object.
hash className, preventing other developers from quickly decompiling your style scheme.

Sass generated classes not getting applied

I have a custom sass setup with bootstrap 5 and bunch of my own SCSS files, all of this gets compiled in style.css using gulp. I have a _colors.scss file which stores all the colors according to our design language. We use this to generate a bunch of classes that can be used any where to change colors:
// Text Colors
$colors: (
"icon-color": $slate-500,
'slate-10': $slate-10,
'slate-40': $slate-40,
'slate-300': $slate-300,
"secondary": $secondary-text-color,
"green": $green,
"light-green": $green-color,
"blue": $blue,
"blue-200": $blue-200,
"blue-300": $blue-300,
"blue-400": $blue-400,
"dodger-blue": $dodger-blue,
"mariner-blue": $mariner-blue,
"light-blue": $blue-100,
"cadet-blue" : $cadet-blue,
"aqua-10": $aqua-10,
"gray": $gray,
"gray-light": $gray-light,
"light-gray": $gray-100,
"bright-gray": $bright-gray,
"gray-200": $gray-200,
"clay": $clay,
"clay-10": $clay-10,
"mandy-pink": $mandy-pink,
"aqua": $aqua,
"violet": $violet,
"white": $white,
"primary": $primary-text-color
);
#each $color-name, $color-value in $colors {
.text-#{$color-name} {
color: $color-value !important;
}
.bg-#{$color-name} {
background-color: $color-value !important;
}
.border-#{$color-name} {
border-color: $color-value !important;
}
}
Problem is certain classes like .text-gray or .text-blue are not working. My guess is that since bootstrap also uses variables called gray and blue, its conflicting with my variables in _colors.scss.
On closer look, the css does gets generated properly (I found below declaration in final style.css):
.case-study .case-study-right .card .data-bar p:last-of-type,.share .social-media>span,.text-color-gray-200,.text-gray-200 {
color: #69727A!important
}
But using .text-gray has no effect, the class is not getting applied.
How do I fix this? please help!
First, if you're sure that you see the correct selector and the correct rule in your CSS file: it should be applied. And so, the rule should be visible in the browser console (even if overridden).
If you see it in your CSS file, but not applied in the browser console: check that your CSS file is valid (and that your gulp production script compiles fine), as a bad character could mess some part of it.
If you see your CSS in the browser console, but it's overridden by some bootstrap rules, you can override bootsrap variables, and change bootstrap colors by yours like so (import bootstrap before this):
$theme-colors: (
primary: #121212,
success: #8bcea8
...
);
You could also try this to replace bootstrap values by yours:
$theme-colors: map-merge($theme-colors, $colors);
The simple answer is:
Use Bootstrap 5 the intended way!
Bootstrap is a complex framework. All that huge number of classes work together including overwriting color settings if provided and used the intended way. In your code example you additional create helper classes Bootstrap would provide to you out of the box if you use it the Bootstrap way. As you did not do it leads to conflicts which are not easy to handle ... and nearly impossible to solve without to have the possibility to analyize the page itself.
This is what you may check:
You may check: are there other classes which blocks your classes?
In your example you use !important to get higher specifity. But the color is overwritten by other classes ...
Maybe that are Bootstrap which uses !important as well. In that case you can try to add your classes at the end of your CSS (after the Bootstrap classes) so they are able to overwrite in case of identical specifity.
Additional: in your example you added a huge bunch of non-bootstrap-classes. Maybe this individual added classes blocks your styling by adding a color with higher specifity (using !important as well which is not a good technique at all) to your element than your added class do.
In that case same solution may be possible ... but individual classes with !important and an additional higher specifity (i.e. using two class names in the selector) will win over your helper classes also your helper class comes later in your CSS file.
To be honest: most often analyzing such an huddle of classes indeed is only possible in the browser on the page direct using the developer tools.
But best way indeed would be ...
Do a correct Bootstrap theming and use Bootstrap classes!!!
You really don't need to create the helper classes on your own. Just do a SASS setup of Bootstrap ... and add your needed/additional colors NOT (or not only) to map $colors but AS WELL TO Bootstrap map $theme-colors. Bootstrap builds up helper-/utility-/elements-color-classes not on $colors but on $theme-colors. That means: doing that this intended way ... all your helper classes you added in your project on your own will be provided by Bootstrap mechanic in the correct order and avoiding conflicts to your CSS.
Use Bootstrap classes to style your page. Now you don't need to create an additional class .case-study { color: gray }. Just use the Bootstrap helper class and add .text-gray to same element. (Note: In your example you use the incredible number of NINE classes to do the same styling. In case 'text in cards' here is a nice hint how to realize it the bootstrap way: https://getbootstrap.com/docs/5.0/components/card/#border).
Just thinking about using complex Framework...
Bootstrap is done to help you. As there is a lot of code using that Framework only makes sense to use the code as much as possible without writing new classes. So best way indeed to work with it is to use the Bootstrap elements and styling them the Bootstrap way. That makes it simple and avoids conflicts... And: you are able to do nearly everything with these elements.
And if you need to extend Bootstrap i.e. with additonal classes: avoid (deep) nested classes and !important as well so you are able to overwrite settings with simple helper classes.
i had the similar problem it was my scss was successfully converted to the css but not applied, after checking for hours i found out ,i have written B capital while the class name was btn
so when everything is working then the problem is always in your code syntax!

How can one pass component property values to the css/less clientlibs for that component? AEM 6.2

I'm still learning the variable scopes and rendering order of AEM. I have this trivial problem where I would like to take an integer input from my dialog box, and set that value as the padding of a specified class.
padding/padding.html:
<div class="my-padding">Pad me up!</div>
padding/clientlibs/padding.less
.my-padding {
padding-top: ${properties.top}px;
padding-right: ${properties.right}px;
padding-bottom: ${properties.bottom}px;
padding-left: ${properties.left}px;
}
The WCMUse properties for the component are outside less' scope, but I don't know the best-practice to accomplish this would be.
I've tried directly injecting Javascript into less, but this doesn't compile correctly and just transforms the function into a string.
padding-2.less
.my-padding-2{
padding: `function(){return 10;}` px;
}
compiles to this:
client-libs.css
...
.my-padding-2{
padding: function(){return 10;} px;
}
...
As such there is no direct way of passing attributes/variables to CSS, you could use JQUERY to do this, that said I am not sure why would you want to give authors flexibility to change the design of a component. Its neither their role to do it nor how an AEM component should be implemented.
Each component adheres to a design, in case you are looking for a way to support different designs for a same component there are other ways to do it all of which will require you to have different CSS classes for each configurations. Once you have done that you can provide authors a predefined choice of design of the component to pick from. This can be done in two ways -
Like RichText components allows for style classes to be applied, you can provide same behavior to author by providing a drop down for different styles that are supported for the component.
You could use concept of choosing a design via providing options for the view (as it happens in the OOTB List component). Each option maps to a component script that have implementation for a specific design.

BEM - Where to include modifiers for specific pages?

I am trying to use BEM naming convention and having some slight difficulty in deciding where to include a modifier for a specific page.
For example, say I have an orange button:
<button class="btn btn-orange">Button A</button>
My project has 3 different pages:
- pageA.html - pageA.scss
- pageB.html - pageB.scss
- pageC.html - pageC.scss
On pageB.html the button should have a margin-top:30px. Is it correct to write the modifier this way:
.btn {
padding: 5px 20px;
background: orange;
margin: 0
&--margin-top {
margin-top: 30px;
}
}
And what is the best way to include a modifier like that only for a specific page? In this case that would be for pageB.html. Should I include that modifier inside the pageB.scss or .buttons.scss?
I think you're confusing two concepts here - BEM, which is Naming Convention with the problem of structuring your projects. Both have nothing to do with each other, and I think BEM is not opinionated in terms of structuring your SASS files.
But, there's a couple of questions you ask here:
Is it correct to write the modifier this way? - it is correct if you want to stick to BEM convention, although I would say, the name you picked .btn--margin-top might not be very fortunate in a long term - imagine, you'll want to include another btn modifier with margin-top property set to, let's say 40px. How will you name it?
What is the best way to include a modifier like that only for a specific page? - These CSS classes you are usually not making for specific page. Whole point of BEM is to enable you, to write more modular CSS, and having this in mind you should use these CSS classes, by assigning them to your Blocks/Elements/Modifiers respectively. Trick here is to determine what is a block/element/modifier in your markup. What you'll achieve by this is reusable CSS, so you can quickly apply same css, by adding BEM classes.
Think in terms of Blocks or Components, NOT pages. You want to use it only on pageB - just add btn--margin-top class to your pageB markup.
Should I include that modifier inside the pageB.scss or .buttons.scss? - it depends on how you structure your project, and I would say that usually, buttons and other UI elements, are in most cases common to whole website/webapp, so there is no need of having them "attached" to specific page (which concept I think you need to drop, if you want to take full advantage of BEM). Besides, whatever suits you will be good for you, and unless you're not working within a team of developers, just stick to your own method, so you'll know in future where to look for things.
In production sites I solve this problem by using a file for the page that is deliberately more specific.
The other answerer is correct, BEM doesn't solve this problem but the solution is available in the css architecture.
I tend to structure projects as follows:
modules
sections
pages
with each getting more specific.
A section might have some specific way of rendering a button, in which case the sass would be like this:
.section {
.button--primary {
// styles
}
}
For a page, the same, but with a page specific key:
.page {
.button--primary {
// styles
}
}
You could even do:
.page {
.section {
.button--primary {
// styles
}
}
}
The key is keeping on top of the specificity in the structure of you sass files. Your button file would not change and you could be sure of dropping it in anywhere in the HTML of your site and having it render correctly and, as a module, it should only contain styles you would want to apply site-wide. For example:
.button--call-to-action {
background-color: $brand-colours__call-to-action;
}
(the hyphens are used to denote that call-to-action is a variation of button and the underscores to denote that call-to-action is one of a set of colours that belong to brand-colours)
Your margin top would then be defined simply as margin-top: 20px; in part of your sass that limited it's effect to the desired portion of the site.
As an aside, usually find that almost everything in the specific page files can be refactored further up the chain into variations of sections and modules, meaning often that they end up empty.

Using BEM CSS with Angular Directives

I've been using BEM style CSS to style my angular directives and usually use replace: true to so that my Block level class can be on the "root" of the custom element. This makes it so that I can write all my CSS primarily with classes.
However, replace: true sometimes causes issues (having two ng-if, etc...) and is now marked as deprecated. So I'm starting to try to stay away from replace completely.
But now I'm having trouble applying BEM to these elements that have an actual custom tag the DOM -- now I have to use a tag name instead of a class name, which means I can't really use BEM anymore (since I'll have to use the tag name since I can't apply classes directly to my element in my template). Additionally, using modifiers on my custom element now seems impossible, as does using sibling CSS selectors.
Here's an example that hopefully will illustrate what I mean:
The directive:
angular.module('my.module')
.directive('customElement', function() {
return {
restrict: 'E',
scope: {
isSpecial: '='
},
template: '<div class="custom-element" ng-class="{\'custom-element--special\': isSpecial"></div>'
};
});
The CSS:
.custom-element {
background-color: white;
}
.custom-element--special {
background-color: red;
}
.custom-element--special + .custom-element--special { // this won't work without replace: true
background-color: blue;
}
If I use replace: true everything works as expected (but then it comes with its own headaches).
If I don't use replace, the classes are not applied to the root custom element so the child selector doesn't work.
I could always add classes to the element in the postLink function, but that makes the template much less clear.
Does anyone have any experience using BEM with angular and using classes instead of tag names in your custom directives? What did you do to solve this problem?
i known it's a problem having replace:false for readability purpose.
The actual problem is that we need our OOCSS but you are handling Angular Components with custom tags has CSS Objects, and is not the case.
There is no practical solution for this, i won't recommend you to start adding classes on postLink function.
However what we are use to do is treat the custom tag as is own CSS Object besides the inner object structure. Forcing us to implement an extra CSS class for the custom tag.
block-context
block-context__element
custom-element
Why doing this when block-context__element is a redundant' class?
Because the rest of your BEM structure is the one you will maintain, the custom-element block should have meaning by it self and the block-context__element element is no expected to, you should abstract the CSS Objects from the directive's implementation, if you in some point start changing your html components your classes should still apply.
I hope this answer helps you

Resources