Leveraging the CSS sibling selector within BEM - css

Say I have a block called .my-block. Depending on whether a specific element, say, .my-header appears before it, I need to style it differently. Because this is easy to do with the CSS sibling selector, I'd like to avoid adding conditionals to my HTML templates and add modifiers to my-block. I've considering two options.
Option 1)
<body class="my-block-container">
<header class="my-header my-block-container__header"></header>
<div class="my-block-container__my-block"</div>
</body>
Option 2)
<header class="my-block-sibling"></header>
<div class="my-block"</div>
I dislike option 1, because no classes will be applied directly to .my-block-container and .my-block-container__header. Moreover, I'd have to either rename the children of .my-block and apply the somewhat vague my-block-container as a block name, or introduce a new block-level name with the only purpose of selecting a sibling.
I dislike option 2, because it's not truly BEM; there's no true block-level name.
Should I accept that I've reached the limits of BEM naming, or is there a convention for this kind of situation?

Did you considered using a modifier for this case?
<body>
<header class="my-header"></header>
<div class="my-block my-block--after-a-header"</div>
</body>
This will allow us to have separated styles between header and block, and to style differently a block when it's after a header.
Next step will be to rename the modifier class to express what it does (and not when to use it), so it will allow you to reuse it in an other context in the future.
For example: .my-header--small will be more explicit than .my-block--after-a-header

I think your idea to use a sibling selector (+) is a good one in this scenario.
Here is a working example of BEM + sibling selector in practice,
Working Example:
.my-block-container {
float: left;
width: 120px;
height: 144px;
margin-right: 12px;
text-align: center;
}
.my-block-container__header {
line-height: 24px;
font-weight: bold;
}
.my-block {
width: 120px;
height: 120px;
line-height: 60px;
color: rgb(255, 255, 255);
}
.my-block-container__my-block {
margin-top: 24px;
background-color: rgb(255, 0, 0);
}
.my-block-container__header + .my-block-container__my-block {
margin-top: 0;
background-color: rgb(0, 0, 255);
}
<div class="my-block-container">
<div class="my-block my-block-container__my-block">Not preceded by <header></div>
</div>
<div class="my-block-container">
<header class="my-block-container__header">Header</header>
<div class="my-block my-block-container__my-block">Preceded by <header></div>
</div>

Related

BEM: How to (and should I) reuse class names?

Lets suppose I have the following site structure:
As you can see, the affirmation blocks serve the same purpose, so it makes sense to use the same name for them, but it creates a name conflict.
The question is the following:
Is there a cool trick that allows me to reuse class names without creating conflicts?
If there is, is it a good idea? Is it BEM-like?
Is it better just to come up with a new class name (something like affirmation-awesome?
Note:
I use affirmation__p instead of cool-block__p and awesome-block__p because that text must be styled differently.
Using BEM conventions, these two blocks do not conflict when using BEM conventions correctly. Typically when nesting you should not really venture into to many nesting layers layers but using SCSS they can be split up assuming they are blocks with separate styling conventions. Think of BEM as grouping and structuring your code in an orderly fashion, but do not go beyond 3 nesting layers as this can make your code messy & unreadable.
.cool-block{
background:#f5f5f5;
padding:1rem;
box-sizing: border-box;
&__affirmation{
background: #ffffff;
color: #333;
&__p{
font-size: 1.2rem;
}
}
}
and your html:
<div class="cool-block">
<div class="cool-block__affirmation">
<div class="cool-block__affirmation__p">
This is my cool block
</div>
</div>
</div>
Then for your other block you can separate:
.awesome-block{
background:#e7e7e7;
padding:2rem;
box-sizing: border-box;
&__affirmation{
background: #333333;
color: #ffffff;
&__p{
font-size: 1.4rem;
}
}
}
and your html for this:
<div class="awesome-block">
<div class="awesome-block__affirmation">
<div class="awesome-block__affirmation__p">
This is my awesome block
</div>
</div>
</div>

Apply CSS rules based on other rule - RTL specific style

Presentation
I'm trying to build a web site available in multiple cultures, with different reading direction.
To do so, I simply add the dir="rtl" attribute on my root HTML element.
My issue is that I have some CSS rules that are specific to one direction or the other (margins or paddings, most of the times).
Unsuccessful try with attribute selector
I though that I could simply use the attribute selector but the dir attribute is only set on the root element, so this wouldn't work :
selector {
&[dir="ltr"] {
// LTR specific
}
&[dir="rtl"] {
// RTL specific
}
}
For instance, on this demo, the title should have a margin of 5px on the right if the application is in rtl or on the left if it's in standard ltr.
Other idea
I've noticed that the direction is rightfully set at rtl, is there a way to use that rule within a CSS or Sass selector ?
Edit and precisions
It seems that I've forgotten an important point. I'm building the web site using Vue.js, the dir attribute is bind in the main component (App) and the RTL/LTR specific CSS rules can be in the same component or in other self-contained component.
Following your css code you could do this with SASS at-root directive DEMO. So this:
#app {
width: 300px;
height: 100px;
border: 1px solid red;
h1 {
#at-root {
[dir="rtl"]#{&} {color: green}
}
#at-root {
[dir="ltr"]#{&} {color: red}
}
}
}
It will compile to this css.
#app {
width: 300px;
height: 100px;
border: 1px solid red;
}
[dir="rtl"]#app h1 {
color: green;
}
[dir="ltr"]#app h1 {
color: red;
}
You could style everything LTR, and only adjust some elements styling for RTL. Might this work for you?
[dir="rtl"] {
&selector {
// RTL specific
}
&selectorN {
// RTL specific
}
}
Use below scss to get expected output
#app {
width: 300px;
height: 300px;
background: red;
&[dir="ltr"] h1{
margin-left: 10px;
}
&[dir="rtl"] h1 {
margin-right: 10px;
}
}
Probably you are going a little in the wrong direction.
Most of the time, you can achieve this automatically, no need for specific selectors.
Margin, for instance:
Just set it both for left and right margin. The browser will choose the correct one for you
#app {
width: 300px;
background: tomato;
margin: 10px;
}
h1 {
margin-left: 15px;
margin-right: 5px;
}
<div id="app" dir="ltr">
<h1>
margin left 15
</h1>
</div><div id="app" dir="rtl">
<h1>
margin right 5
</h1>
</div>

Polymer element-defined styles not working

First of all, sorry for yet another post about this topic but I couldn't see anything that makes sense to me in polymer documentation and on stackoverflow.
I just want to attach style to my element.
From the documentation (https://www.polymer-project.org/0.5/articles/styling-elements.html and https://www.polymer-project.org/0.5/docs/polymer/styling.html#including-stylesheets-in-an-element)it should be straight forward.
<polymer-element name="x-foo">
<template>
<style>
x-foo div { ... }
</style>
...
But it doesn't work as expected. If we define the style for an element, inside the element, it is not applied.
Here is the code:
<polymer-element name="x-button" noscript>
<template>
<style>
/* not working */
x-button {
background-color: green;
}
/* not working */
x-button .hithere{
display: block;
min-height: 50px;
background-color: red;
margin: 20px;
}
/* not working */
x-button .hitheretoo{
display: block;
min-height: 50px;
background-color: blue;
margin: 20px;
}
</style>
<div class="hithere"></div>
<template>
<div class="hitheretoo"></div>
</template>
</template>
</polymer-element>
And a live demo:
http://codepen.io/anon/pen/yyZqMN
Thanks
ssorallen explained the css issue very well and there is more. I couldn't get :host to work on it's own and depending on the browsers you will need to shim the Shadow DOM & add polyfill-next-selector styles.
Additionally, The element never gets registered because you have not used the Polymer() function inside the custom element (unless you chose not to add it in your code example). Here is a codepen of what I found to be one possible solution.
The one thing I am still trying to figure out is the nested <template> issue. I can't pierce the shadow boundary with ::shadow or /deep/. Might be a bug. I'll take a look when I get a few minutes.
Use the :host selector when styling an element from inside itself
<style>
:host {
background-color: green;
}
.hithere {
display: block;
min-height: 50px;
background-color: red;
margin: 20px;
}
.hitheretoo {
display: block;
min-height: 50px;
background-color: blue;
margin: 20px;
}
</style>
When you're styling from inside a custom element all selectors are already scoped to the element. By selecting x-button you are selecting any x-buttons that are descendants of this element, not the element itself. That also means you don't need to prefix selectors with the tag name to scope them; the shadow DOM provides scoping.

Proper Term For This Code

i need to know what the proper term for this code is. someone sent this to me and it was what ii was looking for, but i need the proper term so i can learn it myself. what i'm looking for is the multiple colors on a webpage.
<!doctype html>
<html>
<head>
<title>I am Awesome!</title>
<style type="text/css">
body, #nav, #header, .white-box, .blue-box {
width: 100%;
margin: 0;
padding: 0;
}
body {
height: 100%;
}
h1{
margin: 0;
padding: 150px 0;
}
#nav
{
height: 60px;
color: #fff;
position: fixed;
background: darkblue;
}
#header {
background: red;
text-align: center;
}
#header, .white-box, .blue-box {
height: 400px;
}
.white-box {
background: #ccc;
}
.blue-box {
background: lightblue;
}
</style>
</head>
<body>
<div id='nav'>Navigation</div>
<div id='header'>
<h1>Some Cool Image!</h1>
</div>
<div class='white-box'>Content!</div>
<div class='blue-box'>More Content!</div>
<div class='white-box'>And Something Else!</div>
<div class='blue-box'>Redundancy!</div>
</body>
</html>
There is no proper term for having multi-colors on a web page. You have a simple css code defining various classes with various colors for different parts of your site. So be easy, Not every thing needs to have a name. If its still confusing, let me know in commnents
The proper term for this is Cascading Style Sheets, also known as CSS. CSS is used to style an HTML document and make it look fancier and do formatting changes that HTML cannot do (i.e change the color of the text or change the font size)
CSS can be edited in programs such as JSfiddle.
To insert CSS into an HTML document, the tag can be used or you can reference the CSS stylesheet using href.
CSS can be applied to 3 different things:
By element type (i.e. p{}
By ID: #main{} OR
By class: .button{}
The CSS code is put inbetween the curly braces.
For example, to change the color of element p to blue I would use
p {
color:blue;
}
It's Cascading Style Sheets, otherwise known as CSS. There are a few different ways to apply the styles:
By element type: body { ... }
By ID: #nav { ... }
By class: .white-box { ... }
You can read more about it online; one example is here: http://w3schools.com/css/css_syntax.asp

CSS: What happens when declaring 2 id selectors on the same line

while doing some research i saw the following piece of code in the CSS file:
#element1{
overflow: hidden;
width: 880px;
height: 32px;
padding: 5px 30px;
background: #c82c74;
border-bottom: 1px solid #870843;}
#element1 #element2{
float: left;
width: 400px;
padding-right: 25px;
margin: 0;
padding: 0;}
As you can see the ID of element1 has its own set of properties and values then it is used again alongside element2. In the corresponding HTML file this is how the following styles were implemented:
<div id="element1">
<div id="element2">
</div>
</div>
What does this piece of code mean and what is being achieved here?
#element1 #element2 means it is only styling the element that has an id of element2 that is inside an element that has an id of element1
If you want to style both elements with the same style then you would need to add a comma between the elements: #element1, #element2
People would use #element1 #element2 say if they wanted to override specific styles for element2 but only if it is in element1 - for example, say element2 is on all your web pages and we have the following styles:
#element2 {width:800px;}
now if you had a particular page where you only wanted it to be 400px wide you could qualify the selector to a higher level to override that element on the certain page - so say we gave the body tag an id of element1 for that specific page, adding
#element1 #element2 {width:400px;}
would mean that element2 would be 400px for that page and then 800px on all other pages
That last selection you made, #element1 #element2 will tell CSS to look for a child of #element1 that has an id of #element2 but when using IDs you mostly don't need to do that because IDs are used to uniquely define an object although you may use classes for these type of selection or scoping objects.
See some CSS Tricks for Scoping.
In your example, if you'll write #element2 instead of #element1 #element2 there will be no change, but in my example:
<div class="class_one">
<div class="class_two"></div>
</div>
<div class="class_two"></div>
CSS Example 1 - You will see 3 squares
http://jsfiddle.net/BCq9C/
.class_one {
background: red;
padding: 10px;
width: 30px;
height: 30px;
}
.class_two {
background: blue;
padding: 10px;
width: 30px;
height: 30px;
}
CSS Example 2nd - You will see only 2 squares
http://jsfiddle.net/8aDTB/
.class_one {
background: red;
padding: 10px;
width: 30px;
height: 30px;
}
.class_one .class_two {
background: blue;
padding: 10px;
width: 30px;
height: 30px;
}
These styles for #element2 will only get applied when it occurs within an #element1.
For instance if element1 was an ID used for the homepage & element2 for a search box, the searchbox on the homepage would use these styles, but searchboxes elsewhere wouldn't (e.g. on a page with <body id="contentpage">).
#element1 #element2 will style the unique element #element2 inside the unique element #element1
But since an id is unique, it is completely useless to do it that way.
Using #element2 is enough.

Resources