Is a good practice to combine multiple css classes when trying to create isolated components? - css

I've been using for some time a "BEM like" syntax in my projects. Recently, I was just re-reading some CSS articles when I saw this: https://en.bem.info/methodology/css/#single-responsibility-principle
Basically, instead of putting all the styles of header__button inside that class, it also relays on styles from button class. Aren't we in this case coupling the element of header with the button class? That means that if in the future, we're gonna change the button class, we also need to remember exactly where we're using this class.
In this example maybe it makes sense because you're trying to have the same styles, but what about a layout component? For instance, let's suppose that I have a Menu class that position some children vertically, and I have a Sidebar class that's also going to apply some style to those children. And we use them like this:
menu.css
Menu {
}
Menu__item {
}
sidebar.css
Sidebar {
}
Sidebar__item {
}
index.html
<div class="Menu Sidebar">
<div class="Menu__item Sidebar__item">
</div>
<div class="Menu__item Sidebar__item">
</div>
</div>
If we don't put all the code about how to position items in the Sidebar class and in the future we change some of this code from Menu, maybe the Sidebar class is going to be broken. In the other case, if we repeat code in both classes Menu and Sidebar we're violating the SRP (single responsibility principle) discussed at the begging of the question. That's what lately, in my projects, I've been favoring code duplication, so I would write all the code needed for a Sidebar into the Sidebar class.
But, what would be the best practice here?

There's also a chapter which partially answers your question: https://en.bem.info/methodology/css/#external-geometry-and-positioning
In your example I'd day Sidebar should be responsible for Menu positioning but it shouldn't know anything about Menu__items. And Menu in its turn should not know anything about its own positioning but should position its items inside.
If you really need to change something in Menu__item positioning when it's inside Sidebar use nested selectors:
.Menu {
}
.Menu__item {
}
.Sidebar {
}
.Sidebar .Menu__item {
}

I think, you should decide, what is it: menu or sidebar, and use one of these classes. If blocks are different a bit, you should use modifiers. If it is impossible to do this with modifiers, use two different classes.
Using modifiers:
// your menu
.menu { }
.menu__item { }
// your sidebar
.menu--some-modifier { }
.menu__item--some-modifier { }
//
.sidebar__menu {
// set some styles (margins, positioning) for .menu
}
Two independent different blocks:
// your menu
.menu { }
.menu__item { }
// your sidebar
.sidebar { }
.sidebar__item { }

Related

Creating a single disabled css class for multiple classes

I have multiple css classes that make up a button using SCSS.
.ghost-button {
// CSS goes here
}
.ghost-button-label {
// CSS goes here
}
.plus-circle {
//CSS goes here
}
Using Angular I can control the disabled state using the following feature.
[class.disabled]="booleanFlag"
I wanted to have a disabled state for this button with out having multiple disabled classes like so,
.ghost-button.disabled {
// CSS goes here
}
.ghost-button-label.disabled {
// CSS goes here
}
.plus-circle.disabled {
//CSS goes here
}
This is an example of what I am trying to do. This did not work for me.
.ghost-button .ghost-button-label .plus-circle-position .disabled {
//CSS goes here
}
Here is the markup I use for the button,
<div style="padding-top: 10px" (click)="handleClickAdd($event)">
<div class="ghost-button ghost-button-label icon-custom icon-margin plus-circle plus-circle-position" [class.disabled]="blockAdditions">
<div>
<div>Add</div>
</div>
</div>
</div>
Is there a way to do this? Thanks.
This doesn't work because it means each class is a descendant of the previous:
.ghost-button .ghost-button-label .plus-circle-position .disabled {
//CSS goes here
}
If you're trying to just select that one div with all four classes, just remove the spaces:
.ghost-button.ghost-button-label.plus-circle-position.disabled {
//CSS goes here
}
If you're trying to select any elements that have the disabled class plus one of the three other classes, then you use commas to separate the different combinations:
.ghost-button.disabled,
.ghost-button-label.disabled,
.plus-circle-position.disabled {
// CSS
}
Of course you could just select .disabled if you want this CSS applied to every element with the disabled class:
.disabled {
// CSS
}
Just be sure to take into account View Encapsulation. You may need to put this CSS in the global style file styles.css if this class exists in more than one component.
Just a note, you are not setting the disabled state here, you are adding a class with the name "disabled". disabled is a boolean attribute you can set via HTML, which you can then select with the pseudo-class :disabled.
button:disabled {
color: red
}
<button>Not Disabled</button>
<button disabled>Disabled</button>
If this is what you were actually trying to do then in Angular it would be:
[disabled]="booleanFlag"
You can target a disabled element with the :disabled pseudo-class https://developer.mozilla.org/en-US/docs/Web/CSS/:disabled
So depending on the relationship between your button/label/plus-circle you should be able to target those as well based on whether the button is disabled. For example, if the button and label are siblings you could do this:
.ghost-button:disabled,
.ghost-button:disabled + .ghost-button-label,
.ghost-button:disabled + .plus-circle {
// CSS goes here
}
That would only work if the label and circle were siblings that come after the button, if they are before the button, you can't select them that way.

How to think about styling AngularJS components?

I'm working on an AngularJS project with the aim of slowly getting things in order for Angular 6, or whatever version is out when we start on the upgrade. One of the big pieces of that work is converting existing directives into components.
The thing I'm struggling the most with, is that every instance of a component introduces an extra element into the DOM that wraps my actual component HTML and breaks the hierarchy, making it very hard to write CSS that does what it needs to.
To illustrate my dilemma, imagine a simple component called alert that provides styling for various types of messages you want a user to pay attention to. It accepts two bindings, a message and a type. Depending on the type we will add some special styling, and maybe display a different icon. All of the display logic should be encapsulated within the component, so the person using it just has to make sure they are passing the data correctly and it will work.
<alert message="someCtrl.someVal" type="someCtrl.someVal"></alert>
Option A: put styling on a <div> inside the extra element
Component template
<div
class="alert"
ng-class="{'alert--success': alert.type === 'success', 'alert--error': alert.type === 'error'}">
<div class="alert__message">{{alert.message}}</div>
<a class="alert__close" ng-click="alert.close()">
</div>
Sass
.alert {
& + & {
margin-top: 1rem; // this will be ignored
}
&--success {
background-color: green; // this will work
}
&--error {
background-color: red; // this will work
}
}
This works fine as long as the component is completely ignorant of everything around it, but the second you want to put it inside a flex-parent, or use a selector like "+", it breaks.
Option B: try to style the extra element directly
Component template
<div class="alert__message">{{alert.message}}</div>
<a class="alert__close" ng-click="alert.close()">
Sass
alert {
& + & {
margin-top: 1rem; // this will work now
}
.alert--success {
background-color: green; // nowhere to put this
}
.alert--error {
background-color: red; // nowhere to put this
}
}
Now I have the opposite problem, because I have nowhere to attach my modifier classes for the success and error states.
Am I missing something here? What's the best way to handle the presence of this additional element which sits above the scope of the component itself?
I personally do option A. This allows you to easily identify and create specific styles for your components without fear that they will overwrite site-wide styles. For instance, I'll use nested styles to accomplish this:
#componentContainer {
input[type=text] {
background-color: red;
}
}
This will allow you to make generic styles for your component that won't spill out into the rest of your solution.

CSS Modules & ReactJS: Parent and child CSS classes in different components

So I am building a react application and have a quick question. If I have two separate components:
and
with CSS classes navigation.css and navigationLogo.css respectively. In navigation.css I have a class named .main and in navigationLogo.css I want to have a class like so:
.main .main_in_logo {
color: red;
}
But with CSS Modules I am unable to do this, any ideas on a work around?
I just feel that the explanations here are not complete enough. In css you do .parentSelector .childSelector in order to select the child. The same rule is for css modules, but in your html/jsx you should add to the parent and the child the relevant className -> styles.parentSelector , styles.childSelector.
<div className={styles.container}>text</div>
This way you can have in your css something like:
.banner .container{
background-color:reb;
}
.banner .container{
background-color:blue;
}
Sometimes you use libraries and you want to change something somewhere down the DOM inside the library and you can't change its source code. In this case you can use the :global like this:
.parentElement :global(div)
.parentElement :global(#some-lib-element-selector)
I was looking for the same problem and didn't find the solution here, maybe because the post is 3 years old. The accepted answer is, in my opinion but not mine only, not scalable.
I don't really know if this is something new, but I found out what I would do in vanilla CSS adapted to CSS modules.
Here is what I did and fully suits my needs:
/* parent.css */
.main {
...some CSS...
}
/* logo.css */
#value main from "./parent.css";
.logo {
...some CSS...
}
.main .logo {
color: red
}
Here, we are using #value, which is a CSS modules variable and allows us to bind with another file to build a selector including the final name of the parent "main".
As strange as it looks to me, it took some time to find out about this solution, I hope this will save some time and help other people!
Why you need to create .main .main_in_logo - the main idea of styles with parent elements its not to broke your css with other styles in the future. But its impossible with css modules, because your styles will be unique forever.
But even you really need it you can use global css for these 2 components - documentation about global css for react-css-modules.
The child component should not have a css rule that is dependent upon the parent css classname.
the child should just be:
.main_in_logo { color: red; }
If you need to define styles that involve both parent and child, then the easiest way is to define the styles completely in the parent:
/* navigation.css */
.main .main_in_logo {
color: red;
}
Then have the parent pass the css class to the child and tell the child to use it:
// Navigation.js
<NavigationLogo className={navigationCss.main_in_logo} />
// NavigationLogo.js
<div className={"foo " + this.props.className}>stuff</div>
You don't need to be specify which child class you are referring to when using CSS modules in ReactjS.
so doing:
.main_in_logo {
color: red;
}
will be enough in the stylesheet.
I ended up using CSS the normal way but with BEM convention.
I mean after all, what the CSS modules do is adding the [this_name].module.css to your css classes anyway. If you typed it correctly in the first place, there's no need of using this. It's just a new abstract that allow newbies so they can just do stuff without having to worry about class names clashing.
// Main.jsx
import './Main.css'
import Logo from './Logo.jsx'
const Main = () => {
return (
<div className="main">
<Logo className="main__logo" />
</div>
)
}
/* Main.css */
.main {/* do magic */}
.main__logo {/* do magic but for Logo component */}
So maybe you had Logo component like this..
// Logo.jsx
import './Logo.css'
const Logo = () => {
return (
<div className="logo">
<img className="logo__img" />
</div>
)
}
/* Logo.css */
.logo {/* do magic for logo */}
.logo__img {/* do magic for logo's image */}
This feels much more natural.

Can I adhere to OOCSS separation of container and content when object style need to depend on parent container?

My question is different than this one, but it's regarding the same principle, so this quote is relevant here too:
from https://github.com/stubbornella/oocss/wiki
Essentially, this means “rarely use location-dependent styles”. An object should look the same no matter where you put it. So instead of styling a specific h2 with .myObject h2 {...}, create and apply a class that describes the h2 in question, like h2 class="category".
But what if the design dictates that an object's style changes when it's inside certain containers? Here's a simplified example of my problem. Let's say there's an object called foo, and a container object called bar. foo and bar have their own location-independent styles:
.foo {
...
}
.bar {
...
}
But when foo is inside container bar like so, its color needs to change when the user hovers over bar:
<div class="bar">
...
<div class="foo">
...
</div>
...
</div>
It seems in this case, you can't avoid writing a location-dependent selector that looks like this:
.bar:hover .foo {
// color style
}
One solution I thought of is to introduce a class that's explicitly dependent on bar (named using BEM naming convention to be explicit about parent-child relationship), and add it to the foo object:
<div class="bar">
...
<div class="foo bar__foo">
...
</div>
...
</div>
.bar:hover .bar__foo {
// color style
}
I want to confirm, is this a good way to handle the issue? Are there other ways in OOCSS as well?
The big concern here isn't that your chaining classes together, it's that your classes are location independent. Nesting is going to happen. Approaches like OOCSS are great because they help to you know when things like nesting and class-naming is going awry.
Mark Otto released a Code Guide last week and here are some relevant points:
Keep selectors short and strive to limit the number of elements in each selector to three.
Scope classes to the closest parent only when necessary (e.g., when not using prefixed classes).
He also provides these examples:
/* Bad example */
span { ... }
.page-container #stream .stream-item .tweet .tweet-header .username { ... }
.avatar { ... }
/* Good example */
.avatar { ... }
.tweet-header .username { ... }
.tweet .avatar { ... }
In short: Aim to scope a class to it's parent. Don't go further than 3 selectors.
You're fine going with:
.bar:hover .foo { ... }
Further Reading
Stop The Cascade
Scope CSS Classes with Prefixes

How to change the order of the primeFaces picklist buttons

Is there an easy way to change the order of the sort and move buttons from the PrimeFaces picklist?
For better usability i need the buttons to be in this order:
Sort:
all up
up
down
all down
and for moving:
all to the right
right
left
all to the left
I am just the one who implements a dummy page and someone else has to implement as a PrimeFaces Component what i am designing here. So i don't want it to be a impossible task for the programmer.
There is no built-in buttonTemplate feature, you can change the order with css though.
Code:
.ui-picklist-button-add {
position:relative;
top:25px;
}
.ui-picklist-button-add-all {
position:relative;
top:-40px;
}
-> This is what 'Optimus Prime' says. His answer in the Prime Faces Forum on my question
you can try doing it with jQuery like that : JavaScript moving element in the DOM
Use firebug to find out all the classes of the buttons and its containers
for example try jQuery(".ui-picklist-target-controls .ui-picklist-button-move-top").insertAfter(".ui-picklist-target-controls .ui-picklist-button-move-top");
If want to patch the primefaces jar look at the PickListRenderer.java file look where they use the encodeButton method , and just re order the buttons...
although you will have to re patch it each time you'll want to upgrade
I am the same problem but still got pixel issues with different screens.
Using flexbox should be better than px change:
.ui-picklist-buttons-cell{
display: flex;
flex-direction: column;
}
.ui-picklist-button-add {
order:2;
}
.ui-picklist-button-add-all {
order:1;
}
.ui-picklist-button-remove {
order:3;
}
.ui-picklist-button-remove-all {
order:4;
}
Example: https://codepen.io/Frank_Worker/pen/abzYmYr

Resources