[英] 使用 BEM 来模块化你的 CSS 代码_html/css_WEB-ITnose
How we use BEM to modularise our CSS
If you’re not familiar with BEM, it’s a naming methodology that provides a rather strict way to arrange CSS classes into independent components. It stands for Block Element Modifier and a common one looks like this:
.block {}
.block__element {}
.block--modifier {}
.block__element--modifier {}
The principles are simple — a Block represents an object (a person, a login form, a menu) , an Element is a component within the block that performs a particular function (a hand, a login button, a menu item) and a Modifier is how we represent the variations of a block or an element (a female person, a condensed login form with hidden labels, a menu modified to look differently in the context of a footer) .
There are plenty of resources online that explain the methodology in more detail ( https://css-tricks.com/bem-101/ , http://getbem.com/naming/ ). In this article we’ll be focusing on describing the challenges we had implementing it in our projects.
Before we decided to port our styles and use the Block-Element-Modifier methodology, it all started with a bit of research. Looking around, we found tens of articles and resources, mixins and documentation that seemed to answer all possible questions. It was pretty clear we found our new BFF.
But once you go deeply into building something to scale, it gets pretty confusing. And the more you try to battle it and make it work, the worse it gets — unless you don’t see it and treat it as your friend. Our story starts a couple of months ago when we met BEM. We went out, introduced ourselves, then lured it into working with us on a little corner side project. We connected well, so it was decided — we like it and we want to take this friendship to another level.
The process we followed was relatively simple and somehow natural. We’ve experimented with naming conventions and manually created stylesheet classes . After deciding on a s et of guidelines , we’ve created basic mixins to generate the class names , without having to pass the block name every time we add a new modifier or an element.
So our journey started with something like this:
Then using a set of custom mixins we’ve converted the above to:
And then slowly, when more and more edge cases started to emerge, we’ve improved the mixins without having to change any of the existing code. Pretty neat.
So if for example we want to define the list element in the context of the full-size modifier, we would do this:
How we do BEM in our backyard
We didn’t jump in and convert everything to follow this methodology. We took it gradually and started with scattered pieces until we saw a pattern.
Like any relationship, there must be understanding from both sides in order to make things work. Some of the guidelines we follow are part of the methodology and we don’t question, and some we’ve added on our own down the road.
The ground rule for us is that we never nest blocks inside blocks and elements inside elements . This is the one rule that we set to never to break.
The very deepest level of nesting for a single block is:
If there’s need for more nesting, it means there’s too much complexity and the elements should be stripped down into smaller blocks.
Another rule here is in the way we convert elements into blocks. Following rule#1, we split everything into smaller concerns.
So let’s say we have this structure for a correspondence component:
First we create the structure for the higher-level block:
Then we repeat the process for the smaller, inner structures:
If the title becomes more complex, we just extract that into yet another smaller concern:
And then add more complexity — let’s say we want the actions to be displayed on hover:
After everything is done, if we follow the code back to our stylesheet, it’s going to be laid out nicely, like this:
And there’s nothing stopping us to clean some of the semantics that are not necessary. Since our item is clearly part of a list and there is no other item in the context of the correspondence, we can rename it to correspondence-item :
This is another guideline we use — simplify the naming of BEM blocks for nested components if it doesn’t conflict with other blocks.
For example, we don’t do it for the item-title, since we could actually have a correspondence-title on the main block or a title inside the preview. It’s just too generic.
The Mixins
The mixins that we’re using above are part of Paint, our internal styles library.
They can be found here: https://github.com/alphasights/paint/blob/develop/globals/functions/_bem.scss
Paint is available as a bower/NPM package and it’s undergoing a core redesign. The BEM mixins are still usable and maintained regularly.
Why do we need mixins in the first place?
Our aim was to make the CSS class generation system extremely simple, as we knew front-end and back-end developers don’t need to spend much time building stylesheets. So we’ve automated the process as much as possible.
At the moment we’re developing a set of helper components that would do the same thing for the templates — provide a way to define blocks, elements and modifiers, then generate the markup classes automatically, as we do in CSS .
How things work
We have a function _bem-selector-to-string that turns a selector into a string for easy processing. Sass (rails) and LibSass (node) seem to handle selector strings differently. Sometimes the class name dot is added to the string, so we make sure we strip that before any further processing, as a matter of precaution.
The function that we use to check if a selector has a modifier is _bem-selector-has-modifier . It returns true if the modifier separator is found or if the selector contains a pseudo-selector (:hover, :first-child etc.).
The last function fetches the block name from a string that contains a modifier or pseudo-selector. The _bem-get-block-name would return correspondence if correspondence — full-size is passed. We need the block name when we work with elements inside modifiers, otherwise we would have a hard time generating the proper class names.
The bem-block mixin generates a basic class with the block name and the passed properties.
The bem-modifier mixin creates a .block — modifier class name.
The bem-element mixin does a bit more. It checks if the parent selector is a modifier (or contains a pseudo-selector). If it does, then it generates a nested structure containing the block — modifier with the block__element inside. Otherwise it creates a block__element directly.
For elements and modifiers we currently use an @each $element in $elements but we would optimise this in the next versions to allow sharing the same properties instead of duplicating them on each element.
What we enjoy about BEM
Modularity
It’s very hard to restrain from adding too much logic to a component. With BEM, there’s not much choice, which most of the time is a good thing.
Clarity
When looking at the DOM, you can easily spot where’s the block, what’s the element and if any modifiers are applied. Similarly, when looking at a component stylesheet, you can easily get to where you need to make a change or add more complexity.
Sample blocks structure of an interaction participants component
A block with elements and modifiers
Team Work
Working on the same stylesheet makes it quite hard to avoid conflicts. But when using BEM, everyone can work on their own set of blocks-elements, so there’s really no getting in the way of another.
Principles
When writing CSS, we have a set of principles / rules that we like to follow. BEM enforces some of those by default, which makes writing code even easier.
1. The Separation of Concerns
BEM forces us to separate styles into smaller, maintainable block components that contain elements and modifiers. If the logic gets too complicated, it should be split into smaller concerns. Rule #2.
2. The Single Responsibility Principle
Each of the blocks has a single responsibility and that responsibility is encapsulated in the content of the component.
For the initial example, the correspondence is in charge of setting the grid for the list and preview elements. We don’t share that responsibility with outer concerns or inner concerns.
Following this approach, if the grid changes, we only change it in the context of the correspondence. Every other module would still work.
3. DRY
Every time we stumble upon code duplication, we extract things into placeholders and mixins. If it’s something we DRY within the current scope (things reused in the context of a component) the pattern is to define mixins and classes prefixed with underscore.
Remember not to over engineer your code and separate coincidental occurrence of properties from actual code duplication.
4. The Open/Close Principle
This principle is quite hard to break when working with BEM. It states that everything should be open for extension and closed for modification. We avoid changing properties of a block directly, in the context of other blocks. We instead create modifiers to serve that purpose.
BEM is a powerful methodology, but I think the secret is to make it your own. If something doesn’t work out of the box, find out what does work and try to bend the rules. As long as it brings structure and improves productivity, there’s definitely value in implementing it.
We would love to hear from anyone using BEM to see what challenges you’re faced with.

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

公众号网页更新缓存,这玩意儿,说简单也简单,说复杂也够你喝一壶的。你辛辛苦苦更新了公众号文章,结果用户打开还是老版本,这滋味,谁受得了?这篇文章,咱就来扒一扒这背后的弯弯绕绕,以及如何优雅地解决这个问题。读完之后,你就能轻松应对各种缓存难题,让你的用户始终体验到最新鲜的内容。先说点基础的。网页缓存,说白了就是浏览器或者服务器为了提高访问速度,把一些静态资源(比如图片、CSS、JS)或者页面内容存储起来。下次访问时,直接从缓存里取,不用再重新下载,速度自然快。但这玩意儿,也是个双刃剑。新版本上线,

本文讨论了使用HTML5表单验证属性,例如必需的,图案,最小,最大和长度限制,以直接在浏览器中验证用户输入。

本文展示了使用CSS为网页中添加有效的PNG边框。 它认为,与JavaScript或库相比,CSS提供了出色的性能,详细介绍了如何调整边界宽度,样式和颜色以获得微妙或突出的效果

本文讨论了html< datalist>元素,通过提供自动完整建议,改善用户体验并减少错误来增强表格。Character计数:159

本文讨论了HTML< Progress>元素,其目的,样式和与< meter>元素。主要重点是使用< progress>为了完成任务和LT;仪表>对于stati

本文解释了HTML5< time>语义日期/时间表示的元素。 它强调了DateTime属性对机器可读性(ISO 8601格式)的重要性,并在人类可读文本旁边,增强Accessibilit

本文讨论了HTML< meter>元素,用于在一个范围内显示标量或分数值及其在Web开发中的常见应用。它区分了< meter>从< progress>和前
