BEM - Where to include modifiers for specific pages? - css

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.

Related

Switch background colors between active/inactive tabs

I'm migrating my site from Bootstrap to Tailwind 3 and, in the process, built-in solutions (Dropdown, Tabs, Accordion...) needed to be replaced with alternatives. The section I'm working on right now is a custom Comments Editor I created.
I'll leave a link to what Tailwind's Playground generated for me in a CodePen because the code is longer than the maximum number of allowed characters here. The decision to create a Pen is only because in the Playground it doesn't work as the anchors open in new windows/tabs.
Anyway, the code that really matters, what makes the tabs work, is this one:
[data-target] {
scroll-margin-top: 10rem;
}
[data-target]:last-of-type + [role="tabpanel"], :target + [role="tabpanel"]{
display: flex;
}
[role="tabpanel"], :target ~ [data-target]:last-of-type + [role="tabpanel"]{
display: none;
}
As the title says, I'm looking for a way to change the background-color of the tabs, hinting to the User which one is currently active.
To accomplish that, I would need to switch Tailwind's bg-color-0 with bg-color-100 and take border-b-color-0 out of the once active tab and give it to the new one. But I don't know if I can do that only with CSS.
Not add/remove the classes per se, only their corresponding styles
I've seen a lot of implementations of Pure CSS Tabs, and all of them used hidden <input> fields. Though this implementation doesn't use them, I've added and named them accordingly, but I could only target them with CSS if the User clicked exactly where they're positioned (top-left of the tabs) instead of any part of them.
I'm aware I'll eventually have to add JS to switch the ARIA attributes, but is the basic functionality possible to be accomplished with CSS only? If not, is there an alternative implementation with which I could?
Thank you for your time :)

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.

Ember: How to apply different stylesheets depending on the language?

I want to create an Ember application with two languages: one of them is rtl and the other is ltr.
How can I create two different stylesheets that one will loaded when I need rtl and one will loaded when I need ltr?
I'm using ember 2.8.
There are two main ways.
The first one - keep styles for different directions in different files and use only one of them. There is an obvious negative thing - you have to double your rules.
The second way - to keep it in the single way, but separate by css classes. Just add a language-related css class to the body, for example, .en or .th. Then modify your css for these classes:
div {
color: red;
}
.....
.th {
div {
color: blue;
direction: rtl;
}
}
If you select this way, I would encourage you to use a global lang attribute for the body tag instead of custom class names. It will make your css a little complex, but the semantic of your code will be perfect.

Shorthand CSS for multiple classes with the same style

Is there a shorthand way to write the following css classes that all have the same style?
.gtlab1-17, .gtlab1-19, .gtlab1-21, .gtlab2-17, .gtlab2-19, .gtlab2-21, .gtlab3-17, .gtlab3-19, .gtlab3-21 {margin-left:-3px;}
I need to avoid picking up:
.gtlab1-16, .gtlab2-16, .gtlab3-16
and
.gtlab1-15, .gtlab2-15, .gtlab3-15
which have different styles.
Thanks.
Mabye try this:
div[class^="gtlab"] {
border: 1px solid magenta;
}
div.gtlab2-16, div.gtlab1-57 {
border: 0;
}
If finds divs that have "gtlab" somewhere in its class, and then override the ones you want to exclude.
reference is here: this site i have bookmarked and i revisit that page all the time http://code.tutsplus.com/tutorials/the-30-css-selectors-you-must-memorize--net-16048
You could add the same class to all elements as suggested, but if you dont have access to the html (using CMS or what ever) You could add a class to the elements with jQuery .addClass() and having div[class^="gtlab"] as your selector.
Short answer is:
[class*=gtlab]:not([class*=-16]):not([class*=-15])
But depending on the rest of your code and expected browser support (IE8?), this may not work.
Long answer is, change your HTML if you have that option or just use the long version, it's really not going to cost you much more in terms of coding time or download time and will probably be quicker to render.
Use more classes? It seems like the gtlab2 part is describing one aspect while the number is representing another. Why not split it into two distinct classes that can be used together?

Is it error-prone to use ID-attribute selectors (not #id) on body elements to namespace CSS files?

I'm using Sass to compile my SCSS stylesheets into a single assembled.css to reduce HTTP requests. To namespace individual pages for styling, I wrap each page-specific CSS file in an ID selector for that page's <body> element - for example:
body#support {
.introduction {
#extend %dropcap;
}
}
In nanoc (using ERB), I have a helper that assigns each page's body a dash-separated unique ID based on the HTML folder structure, so the root pages will be #support or #products, while their sub-pages would have an ID like `#products-giantspacelaser'.
I want to make a set of SCSS rules that only apply to these 'products' sub-pages (not including the root-level #products page itself). Is there anything I should look out for regarding specificity if I use an attribute selector instead of an ID for this, as follows?
body[id^="products-"] {
.introduction {
#extend %dropcap;
}
}
I really don't want to use !important, but I do want to ensure that these page-specific rules take precedent over styles set in the '_base.scss' partial that precedes them in the #import order. Seeing as I have full control over the HTML structure, I could also theoretically use Erb in the Sass files to substitute in a comma-separated list of IDs like so:
body#products-giantspacelaser,
body#products-laboratorycamouflage,
body#products-resurrecteddinosaur {
.introduction {
#extend %dropcap;
}
}
- but that seems quite inelegant. Thanks in advance.
EDIT:
I've written my other styles in a really cascade-reliant way:
Normalise CSS
HTML5 Boilerplate's & my own sensible house rules
CSS Libraries (in this case Bourbon & Neat)
A "_source.scss" which in turn imports its own mixins & placeholder selectors.
A "_base.scss" which styles the default layout framework of every page.
A series of .scss files for each page's individual content styling - and, I hoped, overrides of base.scss layout decisions when necessary (if the page needs to take a serious departure from the norm).
Either way, these individual page stylesheets would need to definitely have a higher specificity than earlier defaults, as they were written for a specific purpose & page.
I'm intentionally not using any ID selectors except for this one specific purpose - namespaceing page stylesheets.
Using, say
.services .sharktraining .introduction .disarmingJoke {} --0,0,4,0
in "_base.scss" would surpass
body[id^="products-"] .disarmingJoke {} --0,0,2,1
in a further-down-the-cascade "products.scss", wouldn't it? (N.B. I know needing to use four classes is awful practice, I just don't want to worry about something slipping through the namespace).
I suppose there's another - really dirty - option: to repeat the body[id^="products-"] selector many times, to simply outnumber even the most specific class-strength rule.
It's going to have to depend on how you've written your other styles and whether or not they should take precedence (see: http://coding.smashingmagazine.com/2007/07/27/css-specificity-things-you-should-know/).
If you match the selector exactly but prefix one of them with your body selector, the prefixed one will be specific enough to take precedence no matter what (even if the order was reversed):
body[id^="products-"] .widget {
color: green;
}
.widget {
color: red;
}
The .widget will be green because the first selector is more specific than the second.
The only problem with using attribute selectors over ids is if you care about IE6. If that's a concern for you, the IE7 JS library by Dean Edwards can help you out: http://code.google.com/p/ie7-js/
If changing how the page information is attached to the body element is an option, my recommendation would be to have the parent directory be an id and the child pages be classes:
<body id="products" class="giantspacelaser" />
This way you can retain the specificity of the id:
// excludes the body#products page, which wouldn't have a class set at all
body[class]#products {
// styling here
}

Resources