I am building a UI library in Angular and often designate elements to be styled with generic classes such as .slider, or .form-control. The problem I run into is that sometimes the consumer (who uses the library) uses the same classes for its own elements and when he applies styling it inadvertently breaks the library's UI.
Angular does provide scoped classes so that if for instance I have the style:
.form-control { line-height: 2em; }
then at runtime, Angular has modified it to dynamically add a component specific attribute:
.form-control[ng_content0] { line-height: 2em; }
And because that attribute is added to the element itself dynamically, my styles don't bleed out and impact the elements of the client who consumes the library.
That's great. But how do I prevent the reverse? Basically, how do I use CSS in a way that limits the consumer from breaking things when there is a conflict of class names? Only thing I've thought about is to prefix all class names with a prefix. Some kind of janky namespacing:
.mylib_form-control { line-height: 2em; }
What's the right approach?
Basically, how do I use CSS in a way that limits the consumer from
breaking things when there is a conflict of class names?
I think it's more important to try to prevent a conflict in class names, instead of dealing with what happens if there is one. If there is a conflict, assuming the selectors have the same specificity the style defined last will win. So, depending on if the consumer adds your library before or after their own styles, that would affect what conflicting rules would apply. If you think your library is super important, you can add !important to all your library styles. Which is a bad idea. You should just try to avoid the conflict.
You could perhaps add a prefix to all your classes, say beetle-ui and I would assume the consumer doesn't have any classes that start with that.
You could do something like Semantic UI and for an HTML element to take on the style of the library, it must have the class ui in it's class list. Then all your selectors kind of look like:
.ui.input {
}
.ui.header {
}
The corresponding HTML would like something like:
<input class="ui input" />
I would do something like my first example, and use BEM and define my CSS using SASS so my syntax can be a bit cleaner and benefit from the prefixing.
.beetle-ui-form {
background-color: grey;
&__input {
outline: red;
}
}
Which would generate CSS like:
.beetle-ui-form {
background-color: grey;
}
.beetle-ui-form__input {
outline: red;
}
Related
I have two Components and two css file for each component. css file is imported in req component. The problem is each component has same classnames and if i changes css in component it's effecting the other component with same class too.. Pls help.. comment if you don't understand my question
html {
font-family: sans-serif;
}
/*
This rule is not needed ↷
p {
font-family: sans-serif;
}
*/
html {
font-family: sans-serif;
}
p {
line-height: 1.5;
}
/*
This rule is not needed ↷
p a {
line-height: 1.5;
}
*/
About the css priority level,
Basically, the css that follows has a higher priority.
!important> inline style attribute> id> class, other attributes, capital class (like :first-child)> tag element, capital element (like ::before) in order of priority.
If the priorities are the same, the css with a larger number have higher priority.
https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
If it is not inside and is imported, the priority is the same.
And because of the inheritance, cascade of css, it will affect if you define p even if it's a different file.
There are also css methodologies such as BEM, SMACSS, and OOCSS. However, this also does not solve the fundamental problem.
From CSS methodologies such as BEM and Atomic CSS through to programmatically encapsulated CSS modules, many are doing their best to sidestep or otherwise suppress these features. This gives developers more control over their CSS, but only an autocratic sort of control based on frequent intervention.
https://www.smashingmagazine.com/2016/11/css-inheritance-cascade-global-scope-new-old-worst-best-friends/
There are options such as shadow dom, but polyfill is also directly linked to performance issues.
If you're using react, I think the approach taken by the next's attitude that is looking at about css is probably the closest to the current best we can see.
I hope you have a look at the way css is divided in next.
https://nextjs.org/
Let's say I have a styled checkbox (think material design, where there is a bit going on to achieve the desired checkbox style). Which block is responsible for modifying a parent-dependent child block?
Example Component - Checkbox
So I have the following:
<div class="Checkbox">
<label class="Checkbox__label">
<input class="Checkbox__input" type="checkbox" checked=true />
<span class="Checkbox__icon glyphicon glyphicon-ok"></span>
<span class="Checkbox__text">{label}</span>
</label>
</div>
I style up each element within the block for the base checkbox. Within the context of the application, the checkbox block can live in many other blocks (with their own BEM structures).
Example of other blocks
The checkbox with have slightly difference appearance when say within the "Compact Panel":
<div class="Panel Panel--compact">
<p>Disclaimer.. [text]</p>
<Checkbox label="I Agree" />
</div>
Option One - Parent "knows" about child
So.. should the Compact Panel be "aware" of the various children blocks, and style them, so:
// Checkbox.scss
.Checkbox {
margin: 15px;
// .. other
}
// Panel.scss
.Panel {
&.Panel--compact {
margin: 0;
padding: 2px;
}
&.Panel--compact .Checkbox {
margin: 0;
padding: 1px;
}
}
Option Two - Child "knows" about parent
Or, the panel has zero awareness, and the checkbox checks for parent scope.
// Checkbox.scss
.Checkbox {
margin: 15px;
padding: 15px;
// .. other
}
.Panel.Panel--compact .Checkbox {
margin: 0;
padding: 1px;
}
// Panel.scss
.Panel {
&.Panel--compact {
margin: 0;
padding: 2px;
}
}
Option Three - ?
Maybe there are other options.
Usually with BEM if they look different, they are different.
Usually.
There are a number of different choices for handling context and state with BEM. Each has different pros and cons, so which you use will depend heavily on your use case.
The first option I'll mention is to use descendant selectors. You've already identified this choice, and are running into the usual problem of "where does the code belong?"
For the following examples, I'm going to rely on LESS syntax, this is only to make it easier for me to demonstrate relationships in the code.
Descendant Selector
If you're going to use a descendant selector, I recommend that the code be grouped with the child block.
widget.less
.widget {
&__container {
...
}
...
}
checkbox.less
.checkbox {
&__label {
...
}
...
// using inversion to override checkbox styles in a widget
// this will render to `.widget .checkbox` instead of
// `.checkbox .widget` due to the `&` placement
.widget & {
}
}
The reason I recommend associating the styles with the inner block is because the styles will affect the checkbox, and the cascade order will be important.
If the styles were associated with the parent, reordering the parent styles relative to the child styles could adversely affect how the styles render.
Consider this inclusion order:
site.less
#import 'widget';
#import 'checkbox';
If the styles were part of the widget, they could be overridden by a selector of equal specificity in checkbox.less.
Modifiers
I recommend using modifiers for state. I don't generally consider position or context to be "state", so modifiers may not be appropriate. Additionally, multiple modifiers on the same element can be difficult to reason about and therefor difficult to style.
Assuming you're not using a modifier on the checkbox block, then it may be simpler to add the modifier for the case where it's used in a panel.
.checkbox {
&__label {
...defaults...
}
...defaults...
&--alt {
&__label {
...overrides...
}
...overrides...
}
}
Of course, this requires that the markup be updated for the particular case where it's used in a panel, but then it also opens you up to using the checkbox with the same styles elsewhere.
Different Selector
I'm going to reiterate my first point: If they look different they are different.
This doesn't mean you have to start from scratch on the checkbox. BEM allows for object oriented styles. Come up with a new name, and extend* the checkbox:
checkbox.less
.checkbox {
&__label {
...
}
...
}
checkbox-2.less
#import (reference) 'checkbox';
.checkbox-2 {
.checkbox;
&__label {
...overrides...
}
...overrides...
}
* in LESS I'm using a mixin for this as it's generally better suited toward extending and overriding styles than using the :extend feature of the language. Feel free to use the :extend feature, just be aware that selector order will matter.
Refactor the Need Away
Sometimes I run into cases where I want to use a descendant selector or modifier because I need to bump a block for positioning purposes in a container.
In these cases, I often find that the container itself is what should be changed. I can usually tell that it's the container when I need to update the child to have different:
margins
padding
position
top, right, bottom, left
width
height
flex
Refactoring comes with other challenges, however I often end up using container divs to normalize the insertion region for blocks that contain other blocks; YMMV.
tl;dr: Which Should I Pick?
Can you (reasonably) update the markup?
YES: If you can easily update the markup to use different classes, I'd recommend extending your checkbox block as a new block. Naming things is hard though, so be sure to document which one is which somewhere.
NO: If you can't easily update the classes, using modifiers wouldn't be a great choice either. I'd recommend skipping that one, and falling back to the good ol' descendant selector. In BEM you really want to avoid descendant selectors, but sometimes they're the right tool for the job.
According to this documentation, the use of nested selectors should be avoided in BEM, but "is appropriate for changing elements depending on the state of a block or its assigned theme". This means that you can use a block's modifier to style its elements, but I couldn't find any mention of using a block's modifier to style its child blocks.
I think the best approach would be to add modifiers to both .Pannel and .Checkbox blocks, like: .Panel--compact and .Checkbox--context-compact. This way you won't create a dependency between them, which is a BEM principle.
If somehow you can't add a modifier to .Checkbox depending on it's context, I think the closest option would be the second one, where the child behaves differently depending on the state of its parent.
This is the "right" way:
I'm quite surprised why the accepted answer doesn't mention BEM "mixes".
In these scenarios, that is, when a block should change style when used within another block, the official BEM documentation recommends using a block AND an element class on the same DOM node.
So, in your case, this would be the markup:
<div class="Panel Panel--compact">
<p>Disclaimer.. [text]</p>
<div class="Checkbox Panel__checkbox" /> <!-- Here is the change -->
</div>
And this would be the CSS/SCSS:
// Checkbox.scss
.Checkbox {
margin: 15px;
padding: 15px;
// .. other
}
// Panel.scss
.Panel {
&__checkbox {
margin: 0;
padding: 2px;
}
}
It's really that easy and simple. The other answers are overcomplicating this unnecessarily, and I don't know why, the BEM documentation has a clear answer to this question. You can also find many articles online that explain the very same technique I just described.
I recently started a react project and I would like to share my experience on styling react components.
Cascading styles within react components are really confusing. So first thing is try to write class per element. If you want you can wrap using a main class which defines the component.
.panel {
.checkbox {
}
}
I use css-modules. This is super awesome. This tool can create unique classes so you don't need to worry about duplicating same name in other components. You can learn more from their git page and there are many articles online.
If you are using sass and need to use variables you can define a separate sass file in a different folder (let's say ../assets/variables.scss), in your component scss file you can import it and use all variables. Same goes to mixins and functions.
In your case don't worry about child and parent relationship, write single classes for all elements you need to style. Sometime you may need to target children using parent.
A good read
Is there/what is the best way to set a variable in my CSS stylesheet that is cross browser compatible?
I want to set
color: #123456;
into a variable since I am using it in numerous different spots and if I choose to change that colour I want it all the change.
CSS Variables are a thing but the only browser that has any support for it at this time is Mozilla.
Alternative options:
use Javascript and/or a server-side language to set the variables in your CSS file programatically.
use a CSS preprocessor like SASS. This allows you to create variables. You do have to re-deploy your CSS each time.
consider handling colors a different way in your markup.
Regarding the last one, instead of hardcoding a color into an elements style:
<div class="thisElement"></div>
.thisElement {
font-size: 13px
background: red;
color: #123456;
}
consider using classes for this instea:
<div class="thisElement color1"></div>
.thisElement {
font-size: 13px
background: red;
}
.color1 {
color: #123456;
}
That way you only need to declare the color once in your style sheet. This is essentially 'object oriented CSS'. The idea is that instead of applying monolithic style declarations for each DOM object, you instead declare 'snippets' of style to a bunch of separate classes, then assign those separate classes as you see fit to each DOM object.
In a sense, you've turned the class name, itself, into the variable. You declare it in your CSS once, then use it as many times as needed in your HTML.
If you want to do it in native css you can't. However, you can use technologies / preprocessors like SASS / LESS to achieve exactly what you are describing.
Cross-browser compatibility, variables and calculating.
Once you get used to the syntax (which is really easy to understand and modify) and you are ready to go, SASS creates the "plain" css files for you. Keeps your code clean, simple and easy to maintain.
Have a look at this:
http://sass-lang.com/
Also, here you can find some examples and snippets to have a first impression.
Its not well supported, but this is how it works according to
http://www.w3.org/TR/css-variables/
Custom properties define variables, referenced with the var() notation, which can be used for many purposes. For example, a page that consistently uses a small set of colors in its design can store the colors in custom properties and use them with variables:
:root {
--main-color: #06c;
--accent-color: #006;
}
/* The rest of the CSS file */
#foo h1 {
color: var(--main-color);
}
You can to use a preprocessor like SASS, which has this done much better.
I'm currently working on refactoring a large amount of CSS, and a common trend I'm seeing is that several classes have been created for a very specific item on a page. Rather than trying to describe what they do, the classes are named things like "PressReleaseText", or "SpecLabel", etc. Most of these just define one item, like a font-size or a color.
I'm wondering if it would be better to just create several utility classes, like .fontSize140 {font-size: 140%;}, .bgColorWhite{ background-color: white;}, and utilize those in place of all the duplication occurring across the current set of classes.
Are there any drawbacks to doing this? The point where it becomes blurry is if a current class has 3 attributes set, like color, background color, and font size, and I already have generic classes for all three of those, would my class definition in the html just look something like class="white bgColorBlue fontSize140". That just seems excessive.
This is absolutely a horrible practice. It's 10x worse than the current class names that you're trying to replace. Consider the following class names:
fontSize140
bgColorWhite
marginTop150
These are obviously very descriptive class names. The problem is that they describe the styles behind the class, not the content that it styles. While this can be easier to read in HTML, it will be a complete nightmare in the future when and if you decide to make even the tiniest redesign.
For example, let's say we just applied these three classes to a block of text. It has a font size of 140%, a white background, and a top margin of 150px. That's all fine--until we decide that it needs to be 90% font, a blue background, and no top margin. Now, not only do you have to change the CSS declarations, you have to either:
(1) edit every instance of the class in the HTML to be fontSize90bgColorBlueNoTopMargin or whatever; or
(2) leave the class name alone and leave an extremely confusing class name in the HTML.
Either way it will be a massive pain for you in the future, whereas the current class names (e.g., specLabel, pressReleaseText) appropriately describe the content that they style; their styles can be easily changed without affecting the content inside of them, and thereby never affecting the name of the class.
Part of the point of CSS is to separate the content from the presentation, to make it easier to alter the presentation without altering the content. If you have class="white bgColorBlue fontSize140" all over the place, you have defeated this goal; you might as well just go with style="color: white; background-color: blue; font-size: 140%". Your classes should say what you mean not what you want it to look like.
If you find yourself repeating certain settings for lots of classes, like the following
.PreReleaseText { font-size: 140% }
.SpecLabel { font-size: 140%; background-color: white }
.SomeOtherThing { font-size: 140% }
You can instead combine several of them into one single rule
.PreReleaseText, .SpecLabel, .SomeOtherThing { font-size: 140% }
.SpecLabel { background-color: white }
If you really do just have several classes that are synonyms of each other, you might want to think about why that is. Why are all of those styled the same way? Is there some class name you can come up with that encompasses all of those uses? Or is it just incidental that they happen to be styled the same way? If it's just incidental, then they should have separate rules, so you can easily update the styles of each class independently. If there is some unifying theme, then perhaps you should merge them into a single class.
Remember to consider what will happen in different media, or in a redesign. Imagine that the company is bought out, and you want to change the color scheme to match the new corporate colors, without doing a full redesign. If you have a .bgColorWhite class, but only some of the things labelled with that class should change to a new color in the redesign, you'll have to go through all of your templates and markup again to separate out the classes, but if you labelled them with more meaningful classes, you may be able to just tweak the colors in the appropriate classes.
These are some general guidelines; you should always use what works best for you. If you had a more specific example, I might be able to suggest a better way of refactoring your classes for your specific need.
There is not a right and wrong way to do this as far as I'm concerned. It depends on knowing how often you'll reuse things and what makes it easiest to understand the CSS. I've often seen those general things like .fontSize140 end up causing problems later on when you have to make changes. I prefer in most cases to group classes but keep the individual names.
So I might have
.Thing1,
.Thing2,
.Thing3 { font-size:14px; }
.Thing1 { font-weight:bold; }
.Thing2 { font-size:italic; }
Instead of having
.font14 { font-size:14px; }
And then still needing the .Thing1 and .Thing2 clases.
That was I can always change the CSS easily later without having to worry what is sharing that common .fontSize140 for example.
I would stay away from getting too general like .fontSomeSize. That said i generally try and use classes that define things as logical "types" or "objects" for example .ruled-list or .summary.
Why don't you try something like this:
Use a css preprocessor like sass.
/* define app/website colors */
$main-color: #223c61;
$secondary-color: #2954a2;
$accent-color: #4cceac;
/* some example css classes */
.text-main { color: $main-color; }
.bg-secondary { background-color: $secondary-color; }
.bg-accent { background-color: $accent-color; }
/* define app/website spacings */
$spacing-xs: 10px;
$spacing-sm: 15px;
$spacing-md: 25px;
$spacing-lg: 35px;
/* some example css classes */
.padding-up-xs { padding-top: $spacing-xs; }
.padding-down-lg { padding-bottom: $spacing-lg; }
.margin-left-md { margin-left: $spacing-md; }
The above code has generic css classes, but it is not bound to a specific value. For some very specific styling, you can always make a custom css file to account for that.
I see a lot of people using custom margins and paddings throughout their css. See the code below.
.blog-post-sidebar-right { margin-top: 14px; }
.news-post-bottom-text { margin-bottom: 23px; }
As a rule of thumb, I always use 4/5 predefined margins and paddings. And not some arbitrary number you make up on the fly.
So why not define generic css classes to use them. I took this same idea an applied it to all of my css. Now I can have the same code base in every project.
Because you now use a css preprocessor, it's easy to maintain, flexible and easy to extend.
Im not saying this is the best option, but it does the job for me.
I am a CSS newbie. I am just wondering, is that possible to include one common class into another class?
for example,
.center {align: center};
.content { include .center here};
I came across css framework - Blueprint. We need to put the position information into HTML, e.g.
<div class="span-4"><div class="span-24 last">
As such, we will place the positioning attribute inside html, instead of css. If we change the layout, we need to change html, instead of css.
That's the reason I ask this question. If I can include .span-4 into my own css, i won't have to specify it in my html tag.
Bizarrely, even though CSS talks about inheritance, classes can't "inherit" in this way. The best you can really do is this:
.center, .content { align: center; }
.content { /* ... */ }
Also I'd strongly suggest you not do "naked" class selectors like this. Use ID or tag in addition to class where possible:
div.center, div.content { align: center; }
div.content { /* ... */ }
I say this because if you do your selectors as broad as possible it ends up becoming unmanageable (in my experience) once you get large stylesheets. You end up with unintended selectors interacting with each other to the point where you create a new class (like .center2) because changing the original will affect all sorts of things you don't want.
In standard CSS, it's not possible to do this, though it would be nice.
For something like that you'd need to use SASS or similar, which "compiles" to CSS.
This is where the Cascading in Cascading Style Sheets comes in to play.
Think of your html element or widget/module (group of nested html elements) as an object. You know you're going to have objects that share the same properties so you'll want to create a reusable class they can utilize.
.baseModule {align: center;}
Say your module is a message (error, flash...). So you "extend" or "include" your .baseModule class because all messages will be center aligned (see final html example).
.message {border: 1px solid #555;}
Furthermore you want your error messages to have a red background. Additionally you can overwrite the border property from .baseModule.message here if you wanted it to be a different color or something.
.error {background-color: red;}
So now you have a few css definitions that can be reused with ease.
<!-- Regular message module -->
<p class="baseModule message">
I am a regular message.
</p>
<!-- Error message module -->
<p class="baseModule message error">
I am an error message. My background color is red.
</p>
To relate this to your question you'd basically leverage multiple class names for maximum reusability. Granted ie6 doesn't support chained selectors (class1.class2.class3), but it's still a neat trick!