How to manage specificity issues using ITCSS and having forms? - css

I have a large project, structuring its CSS architecture via ITCSS. All in all, I love it. However, I have one issue when styling forms.
I've styled different form elements in my elements layer:
in forms.scss:
input[type="text"], input[type="password"] {
// sexy element styles
}
However, if I have a component that needs different styling:
in foo_component.scss:
.c-foo__text, .c-foo__password {
// sexy component styles
}
Due to the selectivity of the input type in forms.scss, my component styles in foo_component.scss do not override the element styles in forms.scss.
The current refactor I'm thinking of is changing forms.scss to an object:
form_object.scss refactor:
.o-form__text, .o-form__password {
// sexy object styles that will be overwritten by the lower component
}
I was wondering if this is a proper convention, or is there a better solution?

The main issue is caused by the fact you're declaring a very specific styling (input[type="text"]) in forms.scss quite hight in the specificity graph.
In the ITCSS, we start with the most generic styles and we end with the most explicit ones.
Moreover, lets look at the inverted pyramid layers:
I believe in the perfect case scenario you should apply your logic in the Generic, Base and the Components layers.
So, based on all this, having only the limited info you shared - I would advice you to refactor it this way:
Form styling in the Generic layer: Move any form / input related reset styles here. Use only global resets (like normalize.css or reset.css). These are ground zero styles. You could use a specific selector like input[type="text"], but only to reset style, not to add theme or anything related.
Form styling in the Base layer: Unclassed form elements comes here. Apply generic form or input styles here, that are shared across all elements. Do not use selector like input[type="text"] to style something that you would want to change on another element. Place only common styles here.
Form styling in the Components layer: Here is where your UI styles should be placed. Consider moving the // sexy element styles you're talking about here, assigning them to a class, like .form-control let's say. Below this class, add your other more specific class / UI modifiers.
In conclusion, note, that the decision depends from your specific use-case. There is no hard convention that can solve your issues. You need to make a decision based on all the project info you have. Different approaches would make sense in different stylesheet set-ups.
Anyways, if anything else fails, you could always reach ot to the Trumps layer :-)

Related

How do I "inject" a CSS-class into a lit-element?

lit-element completely encapsulates CSS and the only way to style components is via custom CSS variables.
When using tailwindcss all styles are applied via classes, and I currently don't see a way to inject those classes from the outside world.
What I would like to achieve is to make the custom lit-component completely unaware of tailwind. It should only do the most basic styling but leave the customisation up to the user of the component.
The only solution I see right now is to provide the classes via a property and then apply them using classMap. But I don't know where users would like to apply those classes and adding them to each element is unfeasible (and unmaintainable). In addition, I have my doubts that tailwind would even work in that case due to the style-encapsulation.
It sounds like you want your users to be able add classes to specific parts within the custom element you authored?
If it works with what your component's trying to do, the best way to achieve that would be to place slots in your component and have the user provide the element to fill those slots as children to your component. That way the user directly controls what classes they want to put on it and the styling will apply as the children would be part of the light DOM.
As you've said, providing classes via property would be clunky API and styling won't apply unless you forego using shadow DOM by overriding createRenderRoot which is not recommended.
CSS custom properties are not the only way to allow users to style parts of your component as you can also add part attributes letting the user use ::part() pseudo-element to style them. If your users can write CSS instead of providing tailwind classes, that would be the way to give users some control of styling your component. See https://developer.mozilla.org/en-US/docs/Web/CSS/::part

Using existing CSS selectors to apply styles across the Shadow DOM to custom elements

This question likely has no single direct answer, but hopefully will lead to some best practices or common patterns to use when adapting an existing styles framework to new web component development.
For my case, I have a component <custom-avatar>, and it's all set up properly with self-contained styles and functionality, everything is just peachy.
In certain use cases, the application display needs to stack avatars, just one slightly overtop one other at a diagonal, and the pattern I'm following is using a simple component <custom-composite-avatar>. All this does is wrap the slotted content in a <div> with the correct styling class, but key aspect is retaining the composability for flexible re-use, like so:
<custom-composite-avatar>
<custom-avatar title="first"></custom-avatar>
<custom-avatar title="second"></custom-avatar>
</custom-composite-avatar>
The tricky bit lies in the styles, which are imported from a monorepo that provides the same BEM-ish CSS and component CSS modules to other flavors of the component library like React, Vue, etc. I have the avatar and composite-avatar styles imported just fine, but forcing the intended overlap display is defined with the hierarchical selector .my-composite-avatar.my-composite-avatar--medium .my-avatar {}
So with .my-composite-avatar class applied to the div wrapper within <custom-composite-avatar> and the .my-avatar class applied to the wrapper within the <custom-avatar> and it's own Shadow DOM, that parent/child CSS selector is no good.
I doubt there is a silver bullet for this, but this seems like it will be a rather common scenario as more people migrate to Web Components while using existing styling systems. What approach makes the most sense to ensure that the composite component remains composable, and adaptation of existing selectors pain-free (or at least easy to communicate to other devs)? can this be solved with ::host or ::slotted, or will these cases require significant re-work?
Thanks for reading, your ideas are appreciated!
I would advice to become good friends with CSS properties
because they trickle down into shadowDOMs following CSS selectors.
CSS Custom Properties(variables)
and getPropertyValue
and setProperty if you want to be brutal and make Custom Elements change the outside world.
example
I have an <SVG-ICON> element taking configuration from attributes OR CSS properties
with my favorite lines of code:
let val = this.getAttribute(attr)
||
getComputedStyle(this)
.getPropertyValue("--svg-icon-" + attr)
.replace(/"/g, "")
.trim();
Allows for your standard attribute configuration:
<svg-icon name="configuration" fill="grey"></svg-icon>
But more powerful (simplified example):
<style>
body {
--svg-icon-fill: "grey";
}
svg-icon[selected] {
--svg-icon-fill: "green";
}
</style>
<svg-icon name="messages" selected></svg-icon>
<svg-icon name="configuration"></svg-icon>
CSS = Custom String Scripting
It doesn't often happen, but sometimes the simplest code makes me very happy.
There is no Styling restriction!
These 2 lines allow any String you want in CSS properties:
.replace(/"/g, "")
.trim();
Example
<style>
[name*="globe"] {
--svg-icon-tile: "rect:0,0,24,24,0,fill='blue'";
--svg-icon-stroke: white;
}
</style>
<svg-icon name="feather-icons-globe"></svg-icon>
The --svg-icon-tile has nothing to do with CSS, it is read (and parsed) by the <SVG-ICON> connectedCallback() code to generate a SVG background/tile for all icons named globe.
The double-quotes aren't required, but without them your IDE will complain about invalid CSS.
Have fun coding... you will pull some hairs when you start with calc() in your CSS properties...
But you can take 'CSS' to another level.
PS.
And monitor the future of ConstructAble StyleSheets aka ConstructIble StyleSheets aka Constructed Sheets aka AdoptedStyleSheets:
https://developers.google.com/web/updates/2019/02/constructable-stylesheets
https://chromestatus.com/feature/5394843094220800
iconmeister

Using nth-child or creating new classes in CSS?

I've just started my first project which is building an admin panel. My task is to create HTML and CSS - sort of a base of design to process further to the back-end developers.
I was asked to keep CSS simple and classes as descriptive as possible ( could be long ) and to use Bootstrap.
To avoid creating unnecessary classes which could be used once or twice I decided to go with :nth-child since I thought giving new class to each column is too much. Additionally I created few base classes that might be used for adding 0px padding and margin.
Unfortunately, as I was writing more and more code I've noticed that some CSS code looks like this:
.print-history-advanced-search > [class*='col-']:nth-child(5) > .form-group > .form-horizontal > .form-group > [class*='col-']:first-child
And it is not a single line.
Additionally, I've noticed that sometimes that when I am making a new class and it has lots of parent elements, I cannot write the CSS selector by its own, but I need to state the parents of the this particular element and put the class at the end, which does not make sense.
Is there any solution I could use to avoid creating classes that are simply used in one or two divs, but also make the CSS code less chaotic and avoid very long names? Or maybe I should just give up on children and nesting and work with just classes?
Thank you for your help!
Have a nice day!
If you want to write good CSS, then I'd suggest the BEM model is a good route to go down.
The essentials are;
No element/selector heirachy
No use of elements in selectors
Class based styles only
BEM stands for Block, Element, Modifier - which is how your class names are formed. Borrowing an example from their site;
.form { }
.form--theme-xmas { }
.form--simple { }
.form__input { }
.form__submit { }
.form__submit--disabled { }
<form class="form form--theme-xmas form--simple">
<input class="form__input" type="text" />
<input
class="form__submit form__submit--disabled"
type="submit" />
</form>
You can see there's a form Block, and then a form__input and form__submit Element, and then a form__submit--disabled Modifier.
Depending on your needs I would recommend using css preprocessors like SASS,LESS.
You’ll find that as a website grows, you’ll develop a pretty long, scrolling list of various elements and CSS rules. Some of the rules might overlap or override each other eventually (in that case, usually the more specific rule will win).
You can end up with a lot more code than you expected, especially considering the different variations of a rule you need for different browsers and screen sizes.
There are many ways to refactor your CSS code to make it easier to navigate and use. Some of the easiest methods are the most effective and have the most mileage. Here are some of the quickest ones:
Keep your spacing uniform: Maintain the same spacing between rules
and within declarations throughout your file so that it’s easier to
read.
Use semantic or “familiar” class/id names: Instead of using a class
name like “bottom_menu”, try using the semantic tag “footer”. Or
when you have an image in your “contact” section, make sure you’re
using a class on your image like “contact_image”
Keep it DRY (Don’t Repeat Yourself): Ideally you want to repeat as
little of your code as possible. Do you find the declaration
“background-color: #000″ repeated throughout your CSS file? Consider
typing it once and instead, using multiple selectors on the one
declaration.
Put your tidiness to the test with these tools: Run your CSS through
CSS Lint or W3C—these will help to parse your CSS file correctly,
and highlight problem areas. Your web browser’s developer tools are
also extremely useful for pinpointing specific elements on your
website and using the area as a sandbox to experiment with different
styles and positioning.
Have a look here for more info

Confusion with BEM modifiers

I have started using BEM methodology while writing my CSS and there have been few occasions where I have struggled to find out the best way to do a particular thing.
I would like to take up a simple example of a panel here.
Lets say I am writing a panel component CSS using BEM style. So my CSS might look as follows:
.panel {}
.panel__titlebar {}
.panel__content { display: none; }
A panel can be either chromeless or with chrome. So I define another modifier class for the panel:
.panel--with-chrome {
border: 4px solid black;
border-radius: 4px;
}
Now lets say, the panel can be in a fullscreen/maximized state also in which the chrome and titlebar disappear. Instead of defining modifiers for both panel and titlebar, it would be be wise to define the modifier just on parent (say panel--fullscreen) and rest elements shall change accordingly. So now my CSS becomes:
.panel--fullscreen {
/* something has to be done here */
}
.panel--fullscreen .panel__titlebar { display: none; }
To remove the chrome in fullscreen mode, I can either:
toggle the panel--with-chrome class in JS along with the panel--fullscreen class
overwrite the chrome CSS inside the panel--fullscreen class.
First isn't good because ideally I would like to simply toggle just one class (.panel--fullscreen) in JS to toggle fullscreen mode.
And second one is bad because I'll have to overwrite previous CSS which is a bad practice.
So whats the best way to go about it? Appreciate your comments.
Thanks
The answer depends on many things.
First, how much logic and appearance have "panel--with-chrome" and "panel--fullscreen" modifiers. And also on what kind this logic is.
If "panel--with-chrome" brings a lot of CSS properties and special JS functionality, I would toggle it in JavaScript when applying "panel--fullscreen".
It also depends on a JavaScript framework you use. In "i-bem.js" which we use at Yandex it's easy to react to appending a modifier:
A square changes size modifier when after a click
Reacting on applying a modifier
But if the framework you use doesn't allow to express such a reaction handy, this answer won't work that great for you.
In the other case, when "panel--with-chrome" has not very much properties and doesn't bring any JavaScript logic to a page, I would redefine those CSS properties in "panel--fullscreen" class.
To sum up, there is no universal solution and strict rules to follow. You should decide yourself what will be useful in your case. The decision should depend on many things:
if you expect your project to be maintained in the future, which solution will be easier to support?
capabilities of the JavaScript framework you use
performance stuff
Not in this particular case, but sometimes we measure speed of rendering for variants we are choosing from.
opinion of the other guys, if you work in team
file structure of your project
We, here at Yandex, store CSS and JavaScript for a block in the same block folder. So, it is not a problem to share logic between CSS and JavaScript since they all are in one place.
But if you keep your JavaScript files separately, this can influence on how comfortable it is to support shared logic.
And so on...
I’d go with the first option; you are toggling state after all, so you need to add/remove/toggle classes accordingly. It’s better than undoing a load of stuff in CSS IMO.

How to share common CSS styles

On my page I have few blocks (div) that have the same style regarding background and border (menu panel, info panel, footer panel, ...).
Now I would like to write that style only once and not repeat it for every panel. Yet I don't see any comfortable way of doing that.
One approach I investigated was to introduce a dedicated class (for example panelClass) that would capture the common panel styles. Then in (X)HTML I would just add that class to every element that is supposed to be a panel.
But this doesn't feel right. After all I would be "revealing implementation" in the (X)HTML. I'm no longer able to transparently change things easily because that requires modification of the (X)HTML.
Not to mention that it introduces issues with order of the classes (and thus order in which CSS attributes will be overwritten if needed).
EDIT: (an extended explanation for kolin's answer)
By “revealing implementation” I meant that the (X)HTML (“the content”) is much more strongly connected to the CSS (“the presentation”) than I would like them to be. Maybe I’m pursuing an unreachable ideal (maybe even an unreal or a dummy one!) but I’m trying to keep “the content” separate from “the presentation”.
Thus having a class menu isn’t bad because it describes “contents” not “presentation”. While using instead (what I understood from the cited articles and few others on that site) classes like menu box bordered left_column is bad because it mixes presentation with contents. Once you start adding such classes you might very well add that CSS directly to style attribute. It sure would be much more work and an unmaintainable result but conceptually (when regarding contents-presentation separation) it wouldn’t make a difference.
Now I do realize that in real life for real pages (rich and nice) it is virtually impossible to keep contents entirely separate from presentation. But still you may (should?) at least try to.
Also just look at the “But” in the end of the article The single responsibility principle applied to CSS. In my opinion the island class he used is already presentational because it does not describe contents. It describes how to show it. And that is immediately obvious once you see how widely he used (or might have used) that class on elements having nothing in common as regarding contents.
END EDIT
Another approach was to use selectors grouping. So I would have something like:
#menu, #info, #footer {
background: /* ... */
border: /* ... */
}
This avoids the need to modify (X)HTML. But still causes order issues. And also makes it hard to group styles logically. Especially if they are distributed among many files.
I think that what I really would like to have is to be able to name a group of attributes and just import them somehow in selectors. Something like #include in C++ for example. Is there any way to achieve this? I doubt it but maybe...
If not then is there any other method?
Using classes to define styles is the correct way to do it.
One approach I investigated was to introduce a dedicated class (for example panelClass) that would capture the common panel styles. Then in (X)HTML I would just add that class to every element that is supposed to be a panel.
For me this is exactly the way I would do it.
But this doesn't feel right. After all I would be "revealing implementation" in the (X)HTML.
is there a security problem with revealing implementation?
A few selected posts from Harry Roberts :
http://csswizardry.com/2012/04/my-html-css-coding-style/
http://csswizardry.com/2012/04/the-single-responsibility-principle-applied-to-css/
http://csswizardry.com/2012/05/keep-your-css-selectors-short
I find his style of using CSS eye opening, and it may help you
update
Following on from your update, I agree with you that you should try and seperate structure from presentation, although there will be times where we can't quite manage it. Whether it is fully possible or not, i don't know.
I partially disagree about the island class, the padding property to me kind of hovers over the border of structural and presentational. structural because it alters the layout of whatever element it is applied to, presentational because the padding alters how it looks on the page.
in an ideal world you should never need a class attribute that encompasses menu box bordered left_column, because you would write a couple of classes that seperate out the structure and presentation.
thinking about your case I might create a panel class
.panel{
margin:10px 0;
padding: 10px;
display:block
}
and a panel-display class
.panel-display{
background-color:#1111e4
}
.panel-display > a{
color:#fff
}
in this way I could just play with the presentation without affecting the structure of the site.
(n.b. I'm not sure if this helps you in anyway!, it just seems logical to me)

Resources